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-build/.cargo-checksum.json
vendored
Normal file
1
vendor/cxx-build/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
80
vendor/cxx-build/Cargo.toml
vendored
Normal file
80
vendor/cxx-build/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# 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-build"
|
||||
version = "1.0.85"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
exclude = ["build.rs"]
|
||||
description = "C++ code generator for integrating `cxx` crate into a Cargo build."
|
||||
homepage = "https://cxx.rs"
|
||||
keywords = [
|
||||
"ffi",
|
||||
"build-dependencies",
|
||||
]
|
||||
categories = [
|
||||
"development-tools::build-utils",
|
||||
"development-tools::ffi",
|
||||
]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/dtolnay/cxx"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[lib]
|
||||
doc-scrape-examples = false
|
||||
|
||||
[dependencies.cc]
|
||||
version = "1.0.49"
|
||||
|
||||
[dependencies.codespan-reporting]
|
||||
version = "0.11.1"
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1.9"
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0.39"
|
||||
features = ["span-locations"]
|
||||
default-features = false
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.scratch]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0.95"
|
||||
features = [
|
||||
"parsing",
|
||||
"printing",
|
||||
"clone-impls",
|
||||
"full",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies.cxx]
|
||||
version = "1.0"
|
||||
|
||||
[dev-dependencies.cxx-gen]
|
||||
version = "0.7"
|
||||
|
||||
[dev-dependencies.pkg-config]
|
||||
version = "0.3"
|
||||
|
||||
[features]
|
||||
experimental-async-fn = []
|
||||
parallel = ["cc/parallel"]
|
||||
201
vendor/cxx-build/LICENSE-APACHE
vendored
Normal file
201
vendor/cxx-build/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-build/LICENSE-MIT
vendored
Normal file
23
vendor/cxx-build/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.
|
||||
157
vendor/cxx-build/src/cargo.rs
vendored
Normal file
157
vendor/cxx-build/src/cargo.rs
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use crate::gen::{CfgEvaluator, CfgResult};
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::borrow::Borrow;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{BTreeMap as Map, BTreeSet as Set};
|
||||
use std::env;
|
||||
|
||||
static ENV: OnceCell<CargoEnv> = OnceCell::new();
|
||||
|
||||
struct CargoEnv {
|
||||
features: Set<Name>,
|
||||
cfgs: Map<Name, String>,
|
||||
}
|
||||
|
||||
pub(super) struct CargoEnvCfgEvaluator;
|
||||
|
||||
impl CfgEvaluator for CargoEnvCfgEvaluator {
|
||||
fn eval(&self, name: &str, query_value: Option<&str>) -> CfgResult {
|
||||
let env = ENV.get_or_init(CargoEnv::load);
|
||||
if name == "feature" {
|
||||
return if let Some(query_value) = query_value {
|
||||
CfgResult::from(env.features.contains(Lookup::new(query_value)))
|
||||
} else {
|
||||
let msg = "expected `feature = \"...\"`".to_owned();
|
||||
CfgResult::Undetermined { msg }
|
||||
};
|
||||
}
|
||||
if name == "test" && query_value.is_none() {
|
||||
let msg = "cfg(test) is not supported because Cargo runs your build script only once across the lib and test build of the same crate".to_owned();
|
||||
return CfgResult::Undetermined { msg };
|
||||
}
|
||||
if let Some(cargo_value) = env.cfgs.get(Lookup::new(name)) {
|
||||
return if let Some(query_value) = query_value {
|
||||
CfgResult::from(cargo_value.split(',').any(|value| value == query_value))
|
||||
} else {
|
||||
CfgResult::True
|
||||
};
|
||||
}
|
||||
if name == "debug_assertions" && query_value.is_none() {
|
||||
return CfgResult::from(cfg!(debug_assertions));
|
||||
}
|
||||
CfgResult::False
|
||||
}
|
||||
}
|
||||
|
||||
impl CargoEnv {
|
||||
fn load() -> Self {
|
||||
const CARGO_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
|
||||
const CARGO_CFG_PREFIX: &str = "CARGO_CFG_";
|
||||
|
||||
let mut features = Set::new();
|
||||
let mut cfgs = Map::new();
|
||||
for (k, v) in env::vars_os() {
|
||||
let k = match k.to_str() {
|
||||
Some(k) => k,
|
||||
None => continue,
|
||||
};
|
||||
let v = match v.into_string() {
|
||||
Ok(v) => v,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if let Some(feature_name) = k.strip_prefix(CARGO_FEATURE_PREFIX) {
|
||||
let feature_name = Name(feature_name.to_owned());
|
||||
features.insert(feature_name);
|
||||
} else if let Some(cfg_name) = k.strip_prefix(CARGO_CFG_PREFIX) {
|
||||
let cfg_name = Name(cfg_name.to_owned());
|
||||
cfgs.insert(cfg_name, v);
|
||||
}
|
||||
}
|
||||
CargoEnv { features, cfgs }
|
||||
}
|
||||
}
|
||||
|
||||
struct Name(String);
|
||||
|
||||
impl Ord for Name {
|
||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
||||
Lookup::new(&self.0).cmp(Lookup::new(&rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Name {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Name {}
|
||||
|
||||
impl PartialEq for Name {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
Lookup::new(&self.0).eq(Lookup::new(&rhs.0))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Lookup(str);
|
||||
|
||||
impl Lookup {
|
||||
fn new(name: &str) -> &Self {
|
||||
unsafe { &*(name as *const str as *const Self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<Lookup> for Name {
|
||||
fn borrow(&self) -> &Lookup {
|
||||
Lookup::new(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Lookup {
|
||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
||||
self.0
|
||||
.bytes()
|
||||
.map(CaseAgnosticByte)
|
||||
.cmp(rhs.0.bytes().map(CaseAgnosticByte))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Lookup {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Lookup {}
|
||||
|
||||
impl PartialEq for Lookup {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.0
|
||||
.bytes()
|
||||
.map(CaseAgnosticByte)
|
||||
.eq(rhs.0.bytes().map(CaseAgnosticByte))
|
||||
}
|
||||
}
|
||||
|
||||
struct CaseAgnosticByte(u8);
|
||||
|
||||
impl Ord for CaseAgnosticByte {
|
||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
||||
self.0.to_ascii_lowercase().cmp(&rhs.0.to_ascii_lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for CaseAgnosticByte {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for CaseAgnosticByte {}
|
||||
|
||||
impl PartialEq for CaseAgnosticByte {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.cmp(rhs) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
495
vendor/cxx-build/src/cfg.rs
vendored
Normal file
495
vendor/cxx-build/src/cfg.rs
vendored
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
use std::fmt::{self, Debug};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
|
||||
/// Build configuration. See [CFG].
|
||||
pub struct Cfg<'a> {
|
||||
/// See [`CFG.include_prefix`][CFG#cfginclude_prefix].
|
||||
pub include_prefix: &'a str,
|
||||
/// See [`CFG.exported_header_dirs`][CFG#cfgexported_header_dirs].
|
||||
pub exported_header_dirs: Vec<&'a Path>,
|
||||
/// See [`CFG.exported_header_prefixes`][CFG#cfgexported_header_prefixes].
|
||||
pub exported_header_prefixes: Vec<&'a str>,
|
||||
/// See [`CFG.exported_header_links`][CFG#cfgexported_header_links].
|
||||
pub exported_header_links: Vec<&'a str>,
|
||||
/// See [`CFG.doxygen`][CFG#cfgdoxygen].
|
||||
pub doxygen: bool,
|
||||
marker: PhantomData<*const ()>, // !Send + !Sync
|
||||
}
|
||||
|
||||
/// Global configuration of the current build.
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// <div style="float:right;margin:22px 50px 0;font-size:1.15em;opacity:.73"><strong>&str</strong></div>
|
||||
///
|
||||
/// ## **`CFG.include_prefix`**
|
||||
///
|
||||
/// The prefix at which C++ code from your crate as well as directly dependent
|
||||
/// crates can access the code generated during this build.
|
||||
///
|
||||
/// By default, the `include_prefix` is equal to the name of the current crate.
|
||||
/// That means if your crate is called `demo` and has Rust source files in a
|
||||
/// *src/* directory and maybe some handwritten C++ header files in an
|
||||
/// *include/* directory, then the current crate as well as downstream crates
|
||||
/// might include them as follows:
|
||||
///
|
||||
/// ```
|
||||
/// # const _: &str = stringify! {
|
||||
/// // include one of the handwritten headers:
|
||||
/// #include "demo/include/wow.h"
|
||||
///
|
||||
/// // include a header generated from Rust cxx::bridge:
|
||||
/// #include "demo/src/lib.rs.h"
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// By modifying `CFG.include_prefix` we can substitute a prefix that is
|
||||
/// different from the crate name if desired. Here we'll change it to
|
||||
/// `"path/to"` which will make import paths take the form
|
||||
/// `"path/to/include/wow.h"` and `"path/to/src/lib.rs.h"`.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // build.rs
|
||||
///
|
||||
/// use cxx_build::CFG;
|
||||
///
|
||||
/// fn main() {
|
||||
/// CFG.include_prefix = "path/to";
|
||||
///
|
||||
/// cxx_build::bridge("src/lib.rs")
|
||||
/// .file("src/demo.cc") // probably contains `#include "path/to/src/lib.rs.h"`
|
||||
/// /* ... */
|
||||
/// .compile("demo");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Note that cross-crate imports are only made available between **direct
|
||||
/// dependencies**. Another crate must directly depend on your 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.
|
||||
///
|
||||
/// <br>
|
||||
///
|
||||
/// <div style="float:right;margin:22px 50px 0;font-size:1.15em;opacity:.73"><strong>Vec<&Path></strong></div>
|
||||
///
|
||||
/// ## **`CFG.exported_header_dirs`**
|
||||
///
|
||||
/// A vector of absolute paths. The current crate, directly dependent crates,
|
||||
/// and further crates to which this crate's headers are exported (see below)
|
||||
/// will be able to `#include` headers from these directories.
|
||||
///
|
||||
/// Adding a directory to `exported_header_dirs` is similar to adding it to the
|
||||
/// current build via the `cc` crate's [`Build::include`][cc::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.
|
||||
///
|
||||
/// 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
|
||||
/// execute before yours decides what to put into `exported_header_dirs`.
|
||||
///
|
||||
/// [links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// One of your crate's headers wants to include a system library, such as
|
||||
/// `#include "Python.h"`.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // 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"`.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // 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");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// <p style="margin:0"><br><br></p>
|
||||
///
|
||||
/// <div style="float:right;margin:22px 50px 0;font-size:1.15em;opacity:.73"><strong>Vec<&str></strong></div>
|
||||
///
|
||||
/// ## **`CFG.exported_header_prefixes`**
|
||||
///
|
||||
/// Vector of strings. These 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:
|
||||
///
|
||||
/// ```no_run
|
||||
/// // 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");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// <p style="margin:0"><br><br></p>
|
||||
///
|
||||
/// <div style="float:right;margin:22px 50px 0;font-size:1.15em;opacity:.73"><strong>Vec<&str></strong></div>
|
||||
///
|
||||
/// ## **`CFG.exported_header_links`**
|
||||
///
|
||||
/// Vector of strings. These 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 dependency as part of your crate's public API, except with
|
||||
/// finer grained 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
|
||||
///
|
||||
/// ```no_run
|
||||
/// // build.rs
|
||||
///
|
||||
/// use cxx_build::CFG;
|
||||
///
|
||||
/// fn main() {
|
||||
/// CFG.exported_header_links.push("git2");
|
||||
///
|
||||
/// cxx_build::bridge("src/bridge.rs").compile("demo");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// <p style="margin:0"><br><br></p>
|
||||
///
|
||||
/// <div style="float:right;margin:22px 50px 0;font-size:1.15em;opacity:.73"><strong>bool</strong></div>
|
||||
///
|
||||
/// ## **`CFG.doxygen`**
|
||||
///
|
||||
/// Boolean. Whether to propagate Rust documentation from inside the cxx::bridge
|
||||
/// module as Doxygen-style comments in the generated C++ header.
|
||||
///
|
||||
/// Documentation on the following are supported:
|
||||
///
|
||||
/// - shared structs, and fields of shared structs
|
||||
/// - shared enums, and their variants
|
||||
/// - extern "Rust" opaque types
|
||||
/// - extern "Rust" functions, including methods/member functions
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// // build.rs
|
||||
///
|
||||
/// use cxx_build::CFG;
|
||||
///
|
||||
/// fn main() {
|
||||
/// CFG.doxygen = true;
|
||||
///
|
||||
/// cxx_build::bridge("src/bridge.rs").compile("demo");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// // src/bridge.rs
|
||||
///
|
||||
/// #[cxx::bridge]
|
||||
/// mod ffi {
|
||||
/// /// documentation of MyStruct
|
||||
/// pub struct MyStruct {
|
||||
/// /// documentation of the struct field
|
||||
/// lol: String,
|
||||
/// }
|
||||
///
|
||||
/// extern "Rust" {
|
||||
/// /// documentation of MyType
|
||||
/// type MyType;
|
||||
///
|
||||
/// /// function documentation
|
||||
/// fn asdf() -> bool;
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # pub struct MyType;
|
||||
/// # fn asdf() -> bool { true }
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// With `CFG.doxygen` enabled, the generated C++ header through which
|
||||
/// downstream C++ code will be able to access these shared structs and extern
|
||||
/// "Rust" signatures will have the Rust documentation comments propagated as
|
||||
/// Doxygen-style comments:
|
||||
///
|
||||
/// ```cpp
|
||||
/// /// documentation of MyStruct
|
||||
/// struct MyStruct final {
|
||||
/// /// documentation of the struct field
|
||||
/// ::rust::String lol;
|
||||
/// …
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Otherwise by default (without `CFG.doxygen`) they'll just be `//` comments.
|
||||
#[cfg(doc)]
|
||||
pub static mut CFG: Cfg = Cfg {
|
||||
include_prefix: "",
|
||||
exported_header_dirs: Vec::new(),
|
||||
exported_header_prefixes: Vec::new(),
|
||||
exported_header_links: Vec::new(),
|
||||
doxygen: false,
|
||||
marker: PhantomData,
|
||||
};
|
||||
|
||||
impl<'a> Debug for Cfg<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Self {
|
||||
include_prefix,
|
||||
exported_header_dirs,
|
||||
exported_header_prefixes,
|
||||
exported_header_links,
|
||||
doxygen,
|
||||
marker: _,
|
||||
} = self;
|
||||
formatter
|
||||
.debug_struct("Cfg")
|
||||
.field("include_prefix", include_prefix)
|
||||
.field("exported_header_dirs", exported_header_dirs)
|
||||
.field("exported_header_prefixes", exported_header_prefixes)
|
||||
.field("exported_header_links", exported_header_links)
|
||||
.field("doxygen", doxygen)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(doc))]
|
||||
pub use self::r#impl::Cfg::CFG;
|
||||
|
||||
#[cfg(not(doc))]
|
||||
mod r#impl {
|
||||
use crate::intern::{intern, InternedString};
|
||||
use crate::syntax::map::UnorderedMap as Map;
|
||||
use crate::vec::{self, InternedVec as _};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{PoisonError, RwLock};
|
||||
|
||||
struct CurrentCfg {
|
||||
include_prefix: InternedString,
|
||||
exported_header_dirs: Vec<InternedString>,
|
||||
exported_header_prefixes: Vec<InternedString>,
|
||||
exported_header_links: Vec<InternedString>,
|
||||
doxygen: bool,
|
||||
}
|
||||
|
||||
impl CurrentCfg {
|
||||
fn default() -> Self {
|
||||
let include_prefix = crate::env_os("CARGO_PKG_NAME")
|
||||
.map(|pkg| intern(&pkg.to_string_lossy()))
|
||||
.unwrap_or_default();
|
||||
let exported_header_dirs = Vec::new();
|
||||
let exported_header_prefixes = Vec::new();
|
||||
let exported_header_links = Vec::new();
|
||||
let doxygen = false;
|
||||
CurrentCfg {
|
||||
include_prefix,
|
||||
exported_header_dirs,
|
||||
exported_header_prefixes,
|
||||
exported_header_links,
|
||||
doxygen,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static CURRENT: Lazy<RwLock<CurrentCfg>> = Lazy::new(|| RwLock::new(CurrentCfg::default()));
|
||||
|
||||
thread_local! {
|
||||
// FIXME: If https://github.com/rust-lang/rust/issues/77425 is resolved,
|
||||
// we can delete this thread local side table and instead make each CFG
|
||||
// instance directly own the associated super::Cfg.
|
||||
//
|
||||
// #[allow(const_item_mutation)]
|
||||
// pub const CFG: Cfg = Cfg {
|
||||
// cfg: AtomicPtr::new(ptr::null_mut()),
|
||||
// };
|
||||
// pub struct Cfg {
|
||||
// cfg: AtomicPtr<super::Cfg>,
|
||||
// }
|
||||
//
|
||||
static CONST_DEREFS: RefCell<Map<Handle, Box<super::Cfg<'static>>>> = RefCell::default();
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash)]
|
||||
struct Handle(*const Cfg<'static>);
|
||||
|
||||
impl<'a> Cfg<'a> {
|
||||
fn current() -> super::Cfg<'a> {
|
||||
let current = CURRENT.read().unwrap_or_else(PoisonError::into_inner);
|
||||
let include_prefix = current.include_prefix.str();
|
||||
let exported_header_dirs = current.exported_header_dirs.vec();
|
||||
let exported_header_prefixes = current.exported_header_prefixes.vec();
|
||||
let exported_header_links = current.exported_header_links.vec();
|
||||
let doxygen = current.doxygen;
|
||||
super::Cfg {
|
||||
include_prefix,
|
||||
exported_header_dirs,
|
||||
exported_header_prefixes,
|
||||
exported_header_links,
|
||||
doxygen,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
const fn handle(self: &Cfg<'a>) -> Handle {
|
||||
Handle(<*const Cfg>::cast(self))
|
||||
}
|
||||
}
|
||||
|
||||
// Since super::Cfg is !Send and !Sync, all Cfg are thread local and will
|
||||
// drop on the same thread where they were created.
|
||||
pub enum Cfg<'a> {
|
||||
Mut(super::Cfg<'a>),
|
||||
CFG,
|
||||
}
|
||||
|
||||
impl<'a> Debug for Cfg<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Cfg::Mut(cfg) = self {
|
||||
Debug::fmt(cfg, formatter)
|
||||
} else {
|
||||
Debug::fmt(&Cfg::current(), formatter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for Cfg<'a> {
|
||||
type Target = super::Cfg<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
if let Cfg::Mut(cfg) = self {
|
||||
cfg
|
||||
} else {
|
||||
let cfg = CONST_DEREFS.with(|derefs| -> *mut super::Cfg {
|
||||
&mut **derefs
|
||||
.borrow_mut()
|
||||
.entry(self.handle())
|
||||
.or_insert_with(|| Box::new(Cfg::current()))
|
||||
});
|
||||
unsafe { &mut *cfg }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for Cfg<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
if let Cfg::CFG = self {
|
||||
CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
|
||||
*self = Cfg::Mut(Cfg::current());
|
||||
}
|
||||
match self {
|
||||
Cfg::Mut(cfg) => cfg,
|
||||
Cfg::CFG => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for Cfg<'a> {
|
||||
fn drop(&mut self) {
|
||||
if let Cfg::Mut(cfg) = self {
|
||||
let super::Cfg {
|
||||
include_prefix,
|
||||
exported_header_dirs,
|
||||
exported_header_prefixes,
|
||||
exported_header_links,
|
||||
doxygen,
|
||||
marker: _,
|
||||
} = cfg;
|
||||
let mut current = CURRENT.write().unwrap_or_else(PoisonError::into_inner);
|
||||
current.include_prefix = intern(include_prefix);
|
||||
current.exported_header_dirs = vec::intern(exported_header_dirs);
|
||||
current.exported_header_prefixes = vec::intern(exported_header_prefixes);
|
||||
current.exported_header_links = vec::intern(exported_header_links);
|
||||
current.doxygen = *doxygen;
|
||||
} else {
|
||||
CONST_DEREFS.with(|derefs| derefs.borrow_mut().remove(&self.handle()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
107
vendor/cxx-build/src/deps.rs
vendored
Normal file
107
vendor/cxx-build/src/deps.rs
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Crate {
|
||||
pub include_prefix: Option<PathBuf>,
|
||||
pub links: Option<OsString>,
|
||||
pub header_dirs: Vec<HeaderDir>,
|
||||
}
|
||||
|
||||
pub struct HeaderDir {
|
||||
pub exported: bool,
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
pub fn print_to_cargo(&self) {
|
||||
if let Some(include_prefix) = &self.include_prefix {
|
||||
println!(
|
||||
"cargo:CXXBRIDGE_PREFIX={}",
|
||||
include_prefix.to_string_lossy(),
|
||||
);
|
||||
}
|
||||
if let Some(links) = &self.links {
|
||||
println!("cargo:CXXBRIDGE_LINKS={}", links.to_string_lossy());
|
||||
}
|
||||
for (i, header_dir) in self.header_dirs.iter().enumerate() {
|
||||
if header_dir.exported {
|
||||
println!(
|
||||
"cargo:CXXBRIDGE_DIR{}={}",
|
||||
i,
|
||||
header_dir.path.to_string_lossy(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn direct_dependencies() -> Vec<Crate> {
|
||||
let mut crates: BTreeMap<String, Crate> = BTreeMap::new();
|
||||
let mut exported_header_dirs: BTreeMap<String, Vec<(usize, PathBuf)>> = BTreeMap::new();
|
||||
|
||||
// Only variables set from a build script of direct dependencies are
|
||||
// observable. That's exactly what we want! Your crate needs to declare a
|
||||
// direct dependency on the other crate in order to be able to #include its
|
||||
// headers.
|
||||
//
|
||||
// Also, they're only observable if the dependency's manifest contains a
|
||||
// `links` key. This is important because Cargo imposes no ordering on the
|
||||
// execution of build scripts without a `links` key. When exposing a
|
||||
// generated header for the current crate to #include, we need to be sure
|
||||
// the dependency's build script has already executed and emitted that
|
||||
// generated header.
|
||||
//
|
||||
// References:
|
||||
// - https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key
|
||||
// - https://doc.rust-lang.org/cargo/reference/build-script-examples.html#using-another-sys-crate
|
||||
for (k, v) in env::vars_os() {
|
||||
let mut k = k.to_string_lossy().into_owned();
|
||||
if !k.starts_with("DEP_") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if k.ends_with("_CXXBRIDGE_PREFIX") {
|
||||
k.truncate(k.len() - "_CXXBRIDGE_PREFIX".len());
|
||||
crates.entry(k).or_default().include_prefix = Some(PathBuf::from(v));
|
||||
continue;
|
||||
}
|
||||
|
||||
if k.ends_with("_CXXBRIDGE_LINKS") {
|
||||
k.truncate(k.len() - "_CXXBRIDGE_LINKS".len());
|
||||
crates.entry(k).or_default().links = Some(v);
|
||||
continue;
|
||||
}
|
||||
|
||||
let without_counter = k.trim_end_matches(|ch: char| ch.is_ascii_digit());
|
||||
let counter_len = k.len() - without_counter.len();
|
||||
if counter_len == 0 || !without_counter.ends_with("_CXXBRIDGE_DIR") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let sort_key = k[k.len() - counter_len..]
|
||||
.parse::<usize>()
|
||||
.unwrap_or(usize::MAX);
|
||||
k.truncate(k.len() - counter_len - "_CXXBRIDGE_DIR".len());
|
||||
exported_header_dirs
|
||||
.entry(k)
|
||||
.or_default()
|
||||
.push((sort_key, PathBuf::from(v)));
|
||||
}
|
||||
|
||||
for (k, mut dirs) in exported_header_dirs {
|
||||
dirs.sort_by_key(|(sort_key, _dir)| *sort_key);
|
||||
crates
|
||||
.entry(k)
|
||||
.or_default()
|
||||
.header_dirs
|
||||
.extend(dirs.into_iter().map(|(_sort_key, dir)| HeaderDir {
|
||||
exported: true,
|
||||
path: dir,
|
||||
}));
|
||||
}
|
||||
|
||||
crates.into_iter().map(|entry| entry.1).collect()
|
||||
}
|
||||
98
vendor/cxx-build/src/error.rs
vendored
Normal file
98
vendor/cxx-build/src/error.rs
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use crate::cfg::CFG;
|
||||
use crate::gen::fs;
|
||||
use std::error::Error as StdError;
|
||||
use std::ffi::OsString;
|
||||
use std::fmt::{self, Display};
|
||||
use std::path::Path;
|
||||
|
||||
pub(super) type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) enum Error {
|
||||
NoEnv(OsString),
|
||||
Fs(fs::Error),
|
||||
ExportedDirNotAbsolute(&'static Path),
|
||||
ExportedEmptyPrefix,
|
||||
ExportedDirsWithoutLinks,
|
||||
ExportedPrefixesWithoutLinks,
|
||||
ExportedLinksWithoutLinks,
|
||||
UnusedExportedPrefix(&'static str),
|
||||
UnusedExportedLinks(&'static str),
|
||||
}
|
||||
|
||||
macro_rules! expr {
|
||||
($expr:expr) => {{
|
||||
let _ = $expr; // ensure it doesn't fall out of sync with CFG definition
|
||||
stringify!($expr)
|
||||
}};
|
||||
}
|
||||
|
||||
const LINKS_DOCUMENTATION: &str =
|
||||
"https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key";
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::NoEnv(var) => {
|
||||
write!(f, "missing {} environment variable", var.to_string_lossy())
|
||||
}
|
||||
Error::Fs(err) => err.fmt(f),
|
||||
Error::ExportedDirNotAbsolute(path) => write!(
|
||||
f,
|
||||
"element of {} must be absolute path, but was: {:?}",
|
||||
expr!(CFG.exported_header_dirs),
|
||||
path,
|
||||
),
|
||||
Error::ExportedEmptyPrefix => write!(
|
||||
f,
|
||||
"element of {} must not be empty string",
|
||||
expr!(CFG.exported_header_prefixes),
|
||||
),
|
||||
Error::ExportedDirsWithoutLinks => write!(
|
||||
f,
|
||||
"if {} is nonempty then `links` needs to be set in Cargo.toml; see {}",
|
||||
expr!(CFG.exported_header_dirs),
|
||||
LINKS_DOCUMENTATION,
|
||||
),
|
||||
Error::ExportedPrefixesWithoutLinks => write!(
|
||||
f,
|
||||
"if {} is nonempty then `links` needs to be set in Cargo.toml; see {}",
|
||||
expr!(CFG.exported_header_prefixes),
|
||||
LINKS_DOCUMENTATION,
|
||||
),
|
||||
Error::ExportedLinksWithoutLinks => write!(
|
||||
f,
|
||||
"if {} is nonempty then `links` needs to be set in Cargo.toml; see {}",
|
||||
expr!(CFG.exported_header_links),
|
||||
LINKS_DOCUMENTATION,
|
||||
),
|
||||
Error::UnusedExportedPrefix(unused) => write!(
|
||||
f,
|
||||
"unused element in {}: {:?} does not match the include prefix of any direct dependency",
|
||||
expr!(CFG.exported_header_prefixes),
|
||||
unused,
|
||||
),
|
||||
Error::UnusedExportedLinks(unused) => write!(
|
||||
f,
|
||||
"unused element in {}: {:?} does not match the `links` attribute any direct dependency",
|
||||
expr!(CFG.exported_header_links),
|
||||
unused,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||
match self {
|
||||
Error::Fs(err) => err.source(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fs::Error> for Error {
|
||||
fn from(err: fs::Error) -> Self {
|
||||
Error::Fs(err)
|
||||
}
|
||||
}
|
||||
45
vendor/cxx-build/src/gen/block.rs
vendored
Normal file
45
vendor/cxx-build/src/gen/block.rs
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use proc_macro2::Ident;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum Block<'a> {
|
||||
AnonymousNamespace,
|
||||
Namespace(&'static str),
|
||||
UserDefinedNamespace(&'a Ident),
|
||||
InlineNamespace(&'static str),
|
||||
ExternC,
|
||||
}
|
||||
|
||||
impl<'a> Block<'a> {
|
||||
pub fn write_begin(self, out: &mut String) {
|
||||
if let Block::InlineNamespace(_) = self {
|
||||
out.push_str("inline ");
|
||||
}
|
||||
self.write_common(out);
|
||||
out.push_str(" {\n");
|
||||
}
|
||||
|
||||
pub fn write_end(self, out: &mut String) {
|
||||
out.push_str("} // ");
|
||||
self.write_common(out);
|
||||
out.push('\n');
|
||||
}
|
||||
|
||||
fn write_common(self, out: &mut String) {
|
||||
match self {
|
||||
Block::AnonymousNamespace => out.push_str("namespace"),
|
||||
Block::Namespace(name) => {
|
||||
out.push_str("namespace ");
|
||||
out.push_str(name);
|
||||
}
|
||||
Block::UserDefinedNamespace(name) => {
|
||||
out.push_str("namespace ");
|
||||
out.push_str(&name.to_string());
|
||||
}
|
||||
Block::InlineNamespace(name) => {
|
||||
out.push_str("namespace ");
|
||||
out.push_str(name);
|
||||
}
|
||||
Block::ExternC => out.push_str("extern \"C\""),
|
||||
}
|
||||
}
|
||||
}
|
||||
422
vendor/cxx-build/src/gen/builtin.rs
vendored
Normal file
422
vendor/cxx-build/src/gen/builtin.rs
vendored
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
use crate::gen::block::Block;
|
||||
use crate::gen::ifndef;
|
||||
use crate::gen::out::{Content, OutFile};
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
pub struct Builtins<'a> {
|
||||
pub panic: bool,
|
||||
pub rust_string: bool,
|
||||
pub rust_str: bool,
|
||||
pub rust_slice: bool,
|
||||
pub rust_box: bool,
|
||||
pub rust_vec: bool,
|
||||
pub rust_fn: bool,
|
||||
pub rust_isize: bool,
|
||||
pub opaque: bool,
|
||||
pub layout: bool,
|
||||
pub unsafe_bitcopy: bool,
|
||||
pub unsafe_bitcopy_t: bool,
|
||||
pub rust_error: bool,
|
||||
pub manually_drop: bool,
|
||||
pub maybe_uninit: bool,
|
||||
pub trycatch: bool,
|
||||
pub ptr_len: bool,
|
||||
pub repr_fat: bool,
|
||||
pub rust_str_new_unchecked: bool,
|
||||
pub rust_str_repr: bool,
|
||||
pub rust_slice_new: bool,
|
||||
pub rust_slice_repr: bool,
|
||||
pub relocatable: bool,
|
||||
pub relocatable_or_array: bool,
|
||||
pub friend_impl: bool,
|
||||
pub is_complete: bool,
|
||||
pub destroy: bool,
|
||||
pub deleter_if: bool,
|
||||
pub content: Content<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Builtins<'a> {
|
||||
pub fn new() -> Self {
|
||||
Builtins::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write(out: &mut OutFile) {
|
||||
if out.builtin == Default::default() {
|
||||
return;
|
||||
}
|
||||
|
||||
let include = &mut out.include;
|
||||
let builtin = &mut out.builtin;
|
||||
let out = &mut builtin.content;
|
||||
|
||||
if builtin.rust_string {
|
||||
include.array = true;
|
||||
include.cstdint = true;
|
||||
include.string = true;
|
||||
}
|
||||
|
||||
if builtin.rust_str {
|
||||
include.array = true;
|
||||
include.cstdint = true;
|
||||
include.string = true;
|
||||
builtin.friend_impl = true;
|
||||
}
|
||||
|
||||
if builtin.rust_vec {
|
||||
include.algorithm = true;
|
||||
include.array = true;
|
||||
include.cassert = true;
|
||||
include.cstddef = true;
|
||||
include.cstdint = true;
|
||||
include.initializer_list = true;
|
||||
include.iterator = true;
|
||||
include.new = true;
|
||||
include.stdexcept = true;
|
||||
include.type_traits = true;
|
||||
include.utility = true;
|
||||
builtin.panic = true;
|
||||
builtin.rust_slice = true;
|
||||
builtin.unsafe_bitcopy_t = true;
|
||||
}
|
||||
|
||||
if builtin.rust_slice {
|
||||
include.array = true;
|
||||
include.cassert = true;
|
||||
include.cstddef = true;
|
||||
include.cstdint = true;
|
||||
include.iterator = true;
|
||||
include.stdexcept = true;
|
||||
include.type_traits = true;
|
||||
builtin.friend_impl = true;
|
||||
builtin.layout = true;
|
||||
builtin.panic = true;
|
||||
}
|
||||
|
||||
if builtin.rust_box {
|
||||
include.new = true;
|
||||
include.type_traits = true;
|
||||
include.utility = true;
|
||||
}
|
||||
|
||||
if builtin.rust_fn {
|
||||
include.utility = true;
|
||||
}
|
||||
|
||||
if builtin.rust_error {
|
||||
include.exception = true;
|
||||
builtin.friend_impl = true;
|
||||
}
|
||||
|
||||
if builtin.rust_isize {
|
||||
include.basetsd = true;
|
||||
include.sys_types = true;
|
||||
}
|
||||
|
||||
if builtin.relocatable_or_array {
|
||||
include.cstddef = true;
|
||||
builtin.relocatable = true;
|
||||
}
|
||||
|
||||
if builtin.relocatable {
|
||||
include.type_traits = true;
|
||||
}
|
||||
|
||||
if builtin.layout {
|
||||
include.type_traits = true;
|
||||
include.cstddef = true;
|
||||
builtin.is_complete = true;
|
||||
}
|
||||
|
||||
if builtin.is_complete {
|
||||
include.cstddef = true;
|
||||
include.type_traits = true;
|
||||
}
|
||||
|
||||
if builtin.unsafe_bitcopy {
|
||||
builtin.unsafe_bitcopy_t = true;
|
||||
}
|
||||
|
||||
if builtin.trycatch {
|
||||
builtin.ptr_len = true;
|
||||
}
|
||||
|
||||
out.begin_block(Block::Namespace("rust"));
|
||||
out.begin_block(Block::InlineNamespace("cxxbridge1"));
|
||||
|
||||
let cxx_header = include.has_cxx_header();
|
||||
if !cxx_header {
|
||||
writeln!(out, "// #include \"rust/cxx.h\"");
|
||||
|
||||
ifndef::write(out, builtin.panic, "CXXBRIDGE1_PANIC");
|
||||
|
||||
if builtin.rust_string {
|
||||
out.next_section();
|
||||
writeln!(out, "struct unsafe_bitcopy_t;");
|
||||
}
|
||||
|
||||
if builtin.friend_impl {
|
||||
out.begin_block(Block::AnonymousNamespace);
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "class impl;");
|
||||
out.end_block(Block::AnonymousNamespace);
|
||||
}
|
||||
|
||||
out.next_section();
|
||||
if builtin.rust_str && !builtin.rust_string {
|
||||
writeln!(out, "class String;");
|
||||
}
|
||||
if builtin.layout && !builtin.opaque {
|
||||
writeln!(out, "class Opaque;");
|
||||
}
|
||||
|
||||
if builtin.rust_slice {
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "::std::size_t size_of();");
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "::std::size_t align_of();");
|
||||
}
|
||||
|
||||
ifndef::write(out, builtin.rust_string, "CXXBRIDGE1_RUST_STRING");
|
||||
ifndef::write(out, builtin.rust_str, "CXXBRIDGE1_RUST_STR");
|
||||
ifndef::write(out, builtin.rust_slice, "CXXBRIDGE1_RUST_SLICE");
|
||||
ifndef::write(out, builtin.rust_box, "CXXBRIDGE1_RUST_BOX");
|
||||
ifndef::write(out, builtin.unsafe_bitcopy_t, "CXXBRIDGE1_RUST_BITCOPY_T");
|
||||
ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE1_RUST_BITCOPY");
|
||||
ifndef::write(out, builtin.rust_vec, "CXXBRIDGE1_RUST_VEC");
|
||||
ifndef::write(out, builtin.rust_fn, "CXXBRIDGE1_RUST_FN");
|
||||
ifndef::write(out, builtin.rust_error, "CXXBRIDGE1_RUST_ERROR");
|
||||
ifndef::write(out, builtin.rust_isize, "CXXBRIDGE1_RUST_ISIZE");
|
||||
ifndef::write(out, builtin.opaque, "CXXBRIDGE1_RUST_OPAQUE");
|
||||
ifndef::write(out, builtin.is_complete, "CXXBRIDGE1_IS_COMPLETE");
|
||||
ifndef::write(out, builtin.layout, "CXXBRIDGE1_LAYOUT");
|
||||
ifndef::write(out, builtin.relocatable, "CXXBRIDGE1_RELOCATABLE");
|
||||
}
|
||||
|
||||
if builtin.rust_str_new_unchecked {
|
||||
out.next_section();
|
||||
writeln!(out, "class Str::uninit {{}};");
|
||||
writeln!(out, "inline Str::Str(uninit) noexcept {{}}");
|
||||
}
|
||||
|
||||
if builtin.rust_slice_new {
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "class Slice<T>::uninit {{}};");
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "inline Slice<T>::Slice(uninit) noexcept {{}}");
|
||||
}
|
||||
|
||||
out.begin_block(Block::Namespace("repr"));
|
||||
|
||||
if builtin.repr_fat {
|
||||
include.array = true;
|
||||
include.cstdint = true;
|
||||
out.next_section();
|
||||
writeln!(out, "using Fat = ::std::array<::std::uintptr_t, 2>;");
|
||||
}
|
||||
|
||||
if builtin.ptr_len {
|
||||
include.cstddef = true;
|
||||
out.next_section();
|
||||
writeln!(out, "struct PtrLen final {{");
|
||||
writeln!(out, " void *ptr;");
|
||||
writeln!(out, " ::std::size_t len;");
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
out.end_block(Block::Namespace("repr"));
|
||||
|
||||
out.begin_block(Block::Namespace("detail"));
|
||||
|
||||
if builtin.maybe_uninit {
|
||||
include.cstddef = true;
|
||||
include.new = true;
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T, typename = void *>");
|
||||
writeln!(out, "struct operator_new {{");
|
||||
writeln!(
|
||||
out,
|
||||
" void *operator()(::std::size_t sz) {{ return ::operator new(sz); }}",
|
||||
);
|
||||
writeln!(out, "}};");
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(
|
||||
out,
|
||||
"struct operator_new<T, decltype(T::operator new(sizeof(T)))> {{",
|
||||
);
|
||||
writeln!(
|
||||
out,
|
||||
" void *operator()(::std::size_t sz) {{ return T::operator new(sz); }}",
|
||||
);
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if builtin.trycatch {
|
||||
include.string = true;
|
||||
out.next_section();
|
||||
writeln!(out, "class Fail final {{");
|
||||
writeln!(out, " ::rust::repr::PtrLen &throw$;");
|
||||
writeln!(out, "public:");
|
||||
writeln!(
|
||||
out,
|
||||
" Fail(::rust::repr::PtrLen &throw$) noexcept : throw$(throw$) {{}}",
|
||||
);
|
||||
writeln!(out, " void operator()(char const *) noexcept;");
|
||||
writeln!(out, " void operator()(std::string const &) noexcept;");
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
out.end_block(Block::Namespace("detail"));
|
||||
|
||||
if builtin.manually_drop {
|
||||
out.next_section();
|
||||
include.utility = true;
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "union ManuallyDrop {{");
|
||||
writeln!(out, " T value;");
|
||||
writeln!(
|
||||
out,
|
||||
" ManuallyDrop(T &&value) : value(::std::move(value)) {{}}",
|
||||
);
|
||||
writeln!(out, " ~ManuallyDrop() {{}}");
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if builtin.maybe_uninit {
|
||||
include.cstddef = true;
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "union MaybeUninit {{");
|
||||
writeln!(out, " T value;");
|
||||
writeln!(
|
||||
out,
|
||||
" void *operator new(::std::size_t sz) {{ return detail::operator_new<T>{{}}(sz); }}",
|
||||
);
|
||||
writeln!(out, " MaybeUninit() {{}}");
|
||||
writeln!(out, " ~MaybeUninit() {{}}");
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
out.begin_block(Block::AnonymousNamespace);
|
||||
|
||||
if builtin.rust_str_new_unchecked || builtin.rust_str_repr {
|
||||
out.next_section();
|
||||
writeln!(out, "template <>");
|
||||
writeln!(out, "class impl<Str> final {{");
|
||||
writeln!(out, "public:");
|
||||
if builtin.rust_str_new_unchecked {
|
||||
writeln!(
|
||||
out,
|
||||
" static Str new_unchecked(repr::Fat repr) noexcept {{",
|
||||
);
|
||||
writeln!(out, " Str str = Str::uninit{{}};");
|
||||
writeln!(out, " str.repr = repr;");
|
||||
writeln!(out, " return str;");
|
||||
writeln!(out, " }}");
|
||||
}
|
||||
if builtin.rust_str_repr {
|
||||
writeln!(out, " static repr::Fat repr(Str str) noexcept {{");
|
||||
writeln!(out, " return str.repr;");
|
||||
writeln!(out, " }}");
|
||||
}
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if builtin.rust_slice_new || builtin.rust_slice_repr {
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "class impl<Slice<T>> final {{");
|
||||
writeln!(out, "public:");
|
||||
if builtin.rust_slice_new {
|
||||
writeln!(out, " static Slice<T> slice(repr::Fat repr) noexcept {{");
|
||||
writeln!(out, " Slice<T> slice = typename Slice<T>::uninit{{}};");
|
||||
writeln!(out, " slice.repr = repr;");
|
||||
writeln!(out, " return slice;");
|
||||
writeln!(out, " }}");
|
||||
}
|
||||
if builtin.rust_slice_repr {
|
||||
writeln!(out, " static repr::Fat repr(Slice<T> slice) noexcept {{");
|
||||
writeln!(out, " return slice.repr;");
|
||||
writeln!(out, " }}");
|
||||
}
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if builtin.rust_error {
|
||||
out.next_section();
|
||||
writeln!(out, "template <>");
|
||||
writeln!(out, "class impl<Error> final {{");
|
||||
writeln!(out, "public:");
|
||||
writeln!(out, " static Error error(repr::PtrLen repr) noexcept {{");
|
||||
writeln!(out, " Error error;");
|
||||
writeln!(out, " error.msg = static_cast<char const *>(repr.ptr);");
|
||||
writeln!(out, " error.len = repr.len;");
|
||||
writeln!(out, " return error;");
|
||||
writeln!(out, " }}");
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if builtin.destroy {
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "void destroy(T *ptr) {{");
|
||||
writeln!(out, " ptr->~T();");
|
||||
writeln!(out, "}}");
|
||||
}
|
||||
|
||||
if builtin.deleter_if {
|
||||
out.next_section();
|
||||
writeln!(out, "template <bool> struct deleter_if {{");
|
||||
writeln!(out, " template <typename T> void operator()(T *) {{}}");
|
||||
writeln!(out, "}};");
|
||||
out.next_section();
|
||||
writeln!(out, "template <> struct deleter_if<true> {{");
|
||||
writeln!(
|
||||
out,
|
||||
" template <typename T> void operator()(T *ptr) {{ ptr->~T(); }}",
|
||||
);
|
||||
writeln!(out, "}};");
|
||||
}
|
||||
|
||||
if builtin.relocatable_or_array {
|
||||
out.next_section();
|
||||
writeln!(out, "template <typename T>");
|
||||
writeln!(out, "struct IsRelocatableOrArray : IsRelocatable<T> {{}};");
|
||||
writeln!(out, "template <typename T, ::std::size_t N>");
|
||||
writeln!(
|
||||
out,
|
||||
"struct IsRelocatableOrArray<T[N]> : IsRelocatableOrArray<T> {{}};",
|
||||
);
|
||||
}
|
||||
|
||||
out.end_block(Block::AnonymousNamespace);
|
||||
out.end_block(Block::InlineNamespace("cxxbridge1"));
|
||||
|
||||
if builtin.trycatch {
|
||||
out.begin_block(Block::Namespace("behavior"));
|
||||
include.exception = true;
|
||||
include.type_traits = true;
|
||||
include.utility = true;
|
||||
writeln!(out, "class missing {{}};");
|
||||
writeln!(out, "missing trycatch(...);");
|
||||
writeln!(out);
|
||||
writeln!(out, "template <typename Try, typename Fail>");
|
||||
writeln!(out, "static typename ::std::enable_if<");
|
||||
writeln!(
|
||||
out,
|
||||
" ::std::is_same<decltype(trycatch(::std::declval<Try>(), ::std::declval<Fail>())),",
|
||||
);
|
||||
writeln!(out, " missing>::value>::type");
|
||||
writeln!(out, "trycatch(Try &&func, Fail &&fail) noexcept try {{");
|
||||
writeln!(out, " func();");
|
||||
writeln!(out, "}} catch (::std::exception const &e) {{");
|
||||
writeln!(out, " fail(e.what());");
|
||||
writeln!(out, "}}");
|
||||
out.end_block(Block::Namespace("behavior"));
|
||||
}
|
||||
|
||||
out.end_block(Block::Namespace("rust"));
|
||||
}
|
||||
133
vendor/cxx-build/src/gen/cfg.rs
vendored
Normal file
133
vendor/cxx-build/src/gen/cfg.rs
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
use crate::gen::{CfgEvaluator, CfgResult};
|
||||
use crate::syntax::cfg::CfgExpr;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::Api;
|
||||
use quote::quote;
|
||||
use std::collections::BTreeSet as Set;
|
||||
use syn::Error;
|
||||
|
||||
pub(super) struct UnsupportedCfgEvaluator;
|
||||
|
||||
impl CfgEvaluator for UnsupportedCfgEvaluator {
|
||||
fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
|
||||
let _ = name;
|
||||
let _ = value;
|
||||
let msg = "cfg attribute is not supported".to_owned();
|
||||
CfgResult::Undetermined { msg }
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn strip(
|
||||
cx: &mut Errors,
|
||||
cfg_errors: &mut Set<String>,
|
||||
cfg_evaluator: &dyn CfgEvaluator,
|
||||
apis: &mut Vec<Api>,
|
||||
) {
|
||||
apis.retain(|api| eval(cx, cfg_errors, cfg_evaluator, api.cfg()));
|
||||
for api in apis {
|
||||
match api {
|
||||
Api::Struct(strct) => strct
|
||||
.fields
|
||||
.retain(|field| eval(cx, cfg_errors, cfg_evaluator, &field.cfg)),
|
||||
Api::Enum(enm) => enm
|
||||
.variants
|
||||
.retain(|variant| eval(cx, cfg_errors, cfg_evaluator, &variant.cfg)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn eval(
|
||||
cx: &mut Errors,
|
||||
cfg_errors: &mut Set<String>,
|
||||
cfg_evaluator: &dyn CfgEvaluator,
|
||||
expr: &CfgExpr,
|
||||
) -> bool {
|
||||
match try_eval(cfg_evaluator, expr) {
|
||||
Ok(value) => value,
|
||||
Err(errors) => {
|
||||
for error in errors {
|
||||
if cfg_errors.insert(error.to_string()) {
|
||||
cx.push(error);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_eval(cfg_evaluator: &dyn CfgEvaluator, expr: &CfgExpr) -> Result<bool, Vec<Error>> {
|
||||
match expr {
|
||||
CfgExpr::Unconditional => Ok(true),
|
||||
CfgExpr::Eq(ident, string) => {
|
||||
let key = ident.to_string();
|
||||
let value = string.as_ref().map(|string| string.value());
|
||||
match cfg_evaluator.eval(&key, value.as_deref()) {
|
||||
CfgResult::True => Ok(true),
|
||||
CfgResult::False => Ok(false),
|
||||
CfgResult::Undetermined { msg } => {
|
||||
let span = quote!(#ident #string);
|
||||
Err(vec![Error::new_spanned(span, msg)])
|
||||
}
|
||||
}
|
||||
}
|
||||
CfgExpr::All(list) => {
|
||||
let mut all_errors = Vec::new();
|
||||
for subexpr in list {
|
||||
match try_eval(cfg_evaluator, subexpr) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => return Ok(false),
|
||||
Err(errors) => all_errors.extend(errors),
|
||||
}
|
||||
}
|
||||
if all_errors.is_empty() {
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(all_errors)
|
||||
}
|
||||
}
|
||||
CfgExpr::Any(list) => {
|
||||
let mut all_errors = Vec::new();
|
||||
for subexpr in list {
|
||||
match try_eval(cfg_evaluator, subexpr) {
|
||||
Ok(true) => return Ok(true),
|
||||
Ok(false) => {}
|
||||
Err(errors) => all_errors.extend(errors),
|
||||
}
|
||||
}
|
||||
if all_errors.is_empty() {
|
||||
Ok(false)
|
||||
} else {
|
||||
Err(all_errors)
|
||||
}
|
||||
}
|
||||
CfgExpr::Not(subexpr) => match try_eval(cfg_evaluator, subexpr) {
|
||||
Ok(value) => Ok(!value),
|
||||
Err(errors) => Err(errors),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl Api {
|
||||
fn cfg(&self) -> &CfgExpr {
|
||||
match self {
|
||||
Api::Include(include) => &include.cfg,
|
||||
Api::Struct(strct) => &strct.cfg,
|
||||
Api::Enum(enm) => &enm.cfg,
|
||||
Api::CxxType(ety) | Api::RustType(ety) => &ety.cfg,
|
||||
Api::CxxFunction(efn) | Api::RustFunction(efn) => &efn.cfg,
|
||||
Api::TypeAlias(alias) => &alias.cfg,
|
||||
Api::Impl(imp) => &imp.cfg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CfgResult {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
CfgResult::True
|
||||
} else {
|
||||
CfgResult::False
|
||||
}
|
||||
}
|
||||
}
|
||||
27
vendor/cxx-build/src/gen/check.rs
vendored
Normal file
27
vendor/cxx-build/src/gen/check.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use crate::gen::Opt;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::{error, Api};
|
||||
use quote::{quote, quote_spanned};
|
||||
use std::path::{Component, Path};
|
||||
|
||||
pub(super) use crate::syntax::check::{typecheck, Generator};
|
||||
|
||||
pub(super) fn precheck(cx: &mut Errors, apis: &[Api], opt: &Opt) {
|
||||
if !opt.allow_dot_includes {
|
||||
check_dot_includes(cx, apis);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_dot_includes(cx: &mut Errors, apis: &[Api]) {
|
||||
for api in apis {
|
||||
if let Api::Include(include) = api {
|
||||
let first_component = Path::new(&include.path).components().next();
|
||||
if let Some(Component::CurDir) | Some(Component::ParentDir) = first_component {
|
||||
let begin = quote_spanned!(include.begin_span=> .);
|
||||
let end = quote_spanned!(include.end_span=> .);
|
||||
let span = quote!(#begin #end);
|
||||
cx.error(span, error::DOT_INCLUDE.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
175
vendor/cxx-build/src/gen/error.rs
vendored
Normal file
175
vendor/cxx-build/src/gen/error.rs
vendored
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
use crate::gen::fs;
|
||||
use crate::syntax;
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use codespan_reporting::files::SimpleFiles;
|
||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream, WriteColor};
|
||||
use codespan_reporting::term::{self, Config};
|
||||
use std::borrow::Cow;
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{self, Display};
|
||||
use std::io::{self, Write};
|
||||
use std::ops::Range;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Error {
|
||||
NoBridgeMod,
|
||||
Fs(fs::Error),
|
||||
Utf8(PathBuf, Utf8Error),
|
||||
Syn(syn::Error),
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::NoBridgeMod => write!(f, "no #[cxx::bridge] module found"),
|
||||
Error::Fs(err) => err.fmt(f),
|
||||
Error::Utf8(path, _) => write!(f, "Failed to read file `{}`", path.display()),
|
||||
Error::Syn(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||
match self {
|
||||
Error::Fs(err) => err.source(),
|
||||
Error::Utf8(_, err) => Some(err),
|
||||
Error::Syn(err) => err.source(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fs::Error> for Error {
|
||||
fn from(err: fs::Error) -> Self {
|
||||
Error::Fs(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<syn::Error> for Error {
|
||||
fn from(err: syn::Error) -> Self {
|
||||
Error::Syn(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn format_err(path: &Path, source: &str, error: Error) -> ! {
|
||||
match error {
|
||||
Error::Syn(syn_error) => {
|
||||
let syn_error = sort_syn_errors(syn_error);
|
||||
let writer = StandardStream::stderr(ColorChoice::Auto);
|
||||
let ref mut stderr = writer.lock();
|
||||
for error in syn_error {
|
||||
let _ = writeln!(stderr);
|
||||
display_syn_error(stderr, path, source, error);
|
||||
}
|
||||
}
|
||||
Error::NoBridgeMod => {
|
||||
let _ = writeln!(
|
||||
io::stderr(),
|
||||
"cxxbridge: no #[cxx::bridge] module found in {}",
|
||||
path.display(),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let _ = writeln!(io::stderr(), "cxxbridge: {}", report(error));
|
||||
}
|
||||
}
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
pub(crate) fn report(error: impl StdError) -> impl Display {
|
||||
struct Report<E>(E);
|
||||
|
||||
impl<E: StdError> Display for Report<E> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "{}", self.0)?;
|
||||
let mut error: &dyn StdError = &self.0;
|
||||
|
||||
while let Some(cause) = error.source() {
|
||||
write!(formatter, "\n\nCaused by:\n {}", cause)?;
|
||||
error = cause;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Report(error)
|
||||
}
|
||||
|
||||
fn sort_syn_errors(error: syn::Error) -> Vec<syn::Error> {
|
||||
let mut errors: Vec<_> = error.into_iter().collect();
|
||||
errors.sort_by_key(|e| {
|
||||
let start = e.span().start();
|
||||
(start.line, start.column)
|
||||
});
|
||||
errors
|
||||
}
|
||||
|
||||
fn display_syn_error(stderr: &mut dyn WriteColor, path: &Path, source: &str, error: syn::Error) {
|
||||
let span = error.span();
|
||||
let start = span.start();
|
||||
let end = span.end();
|
||||
|
||||
let mut start_offset = 0;
|
||||
for _ in 1..start.line {
|
||||
start_offset += source[start_offset..].find('\n').unwrap() + 1;
|
||||
}
|
||||
let start_column = source[start_offset..]
|
||||
.chars()
|
||||
.take(start.column)
|
||||
.map(char::len_utf8)
|
||||
.sum::<usize>();
|
||||
start_offset += start_column;
|
||||
|
||||
let mut end_offset = start_offset;
|
||||
if start.line == end.line {
|
||||
end_offset -= start_column;
|
||||
} else {
|
||||
for _ in 0..end.line - start.line {
|
||||
end_offset += source[end_offset..].find('\n').unwrap() + 1;
|
||||
}
|
||||
}
|
||||
end_offset += source[end_offset..]
|
||||
.chars()
|
||||
.take(end.column)
|
||||
.map(char::len_utf8)
|
||||
.sum::<usize>();
|
||||
|
||||
let mut path = path.to_string_lossy();
|
||||
if path == "-" {
|
||||
path = Cow::Borrowed(if cfg!(unix) { "/dev/stdin" } else { "stdin" });
|
||||
}
|
||||
|
||||
let mut files = SimpleFiles::new();
|
||||
let file = files.add(path, source);
|
||||
|
||||
let diagnostic = diagnose(file, start_offset..end_offset, error);
|
||||
|
||||
let config = Config::default();
|
||||
let _ = term::emit(stderr, &config, &files, &diagnostic);
|
||||
}
|
||||
|
||||
fn diagnose(file: usize, range: Range<usize>, error: syn::Error) -> Diagnostic<usize> {
|
||||
let message = error.to_string();
|
||||
let info = syntax::error::ERRORS
|
||||
.iter()
|
||||
.find(|e| message.contains(e.msg));
|
||||
let mut diagnostic = Diagnostic::error().with_message(&message);
|
||||
let mut label = Label::primary(file, range);
|
||||
if let Some(info) = info {
|
||||
label.message = info.label.map_or(message, str::to_owned);
|
||||
diagnostic.labels.push(label);
|
||||
diagnostic.notes.extend(info.note.map(str::to_owned));
|
||||
} else {
|
||||
label.message = message;
|
||||
diagnostic.labels.push(label);
|
||||
}
|
||||
diagnostic.code = Some("cxxbridge".to_owned());
|
||||
diagnostic
|
||||
}
|
||||
72
vendor/cxx-build/src/gen/file.rs
vendored
Normal file
72
vendor/cxx-build/src/gen/file.rs
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use crate::syntax::file::Module;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use syn::parse::discouraged::Speculative;
|
||||
use syn::parse::{Error, Parse, ParseStream, Result};
|
||||
use syn::{braced, Attribute, Ident, Item, Token, Visibility};
|
||||
|
||||
pub struct File {
|
||||
pub modules: Vec<Module>,
|
||||
}
|
||||
|
||||
impl Parse for File {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let mut modules = Vec::new();
|
||||
input.call(Attribute::parse_inner)?;
|
||||
parse(input, &mut modules)?;
|
||||
Ok(File { modules })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(input: ParseStream, modules: &mut Vec<Module>) -> Result<()> {
|
||||
while !input.is_empty() {
|
||||
let mut cxx_bridge = false;
|
||||
let mut namespace = Namespace::ROOT;
|
||||
let mut attrs = input.call(Attribute::parse_outer)?;
|
||||
for attr in &attrs {
|
||||
let path = &attr.path.segments;
|
||||
if path.len() == 2 && path[0].ident == "cxx" && path[1].ident == "bridge" {
|
||||
cxx_bridge = true;
|
||||
namespace = parse_args(attr)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let ahead = input.fork();
|
||||
ahead.parse::<Visibility>()?;
|
||||
ahead.parse::<Option<Token![unsafe]>>()?;
|
||||
if !ahead.peek(Token![mod]) {
|
||||
let item: Item = input.parse()?;
|
||||
if cxx_bridge {
|
||||
return Err(Error::new_spanned(item, "expected a module"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if cxx_bridge {
|
||||
let mut module: Module = input.parse()?;
|
||||
module.namespace = namespace;
|
||||
attrs.extend(module.attrs);
|
||||
module.attrs = attrs;
|
||||
modules.push(module);
|
||||
} else {
|
||||
input.advance_to(&ahead);
|
||||
input.parse::<Token![mod]>()?;
|
||||
input.parse::<Ident>()?;
|
||||
let semi: Option<Token![;]> = input.parse()?;
|
||||
if semi.is_none() {
|
||||
let content;
|
||||
braced!(content in input);
|
||||
parse(&content, modules)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_args(attr: &Attribute) -> Result<Namespace> {
|
||||
if attr.tokens.is_empty() {
|
||||
Ok(Namespace::ROOT)
|
||||
} else {
|
||||
attr.parse_args_with(Namespace::parse_bridge_attr_namespace)
|
||||
}
|
||||
}
|
||||
172
vendor/cxx-build/src/gen/fs.rs
vendored
Normal file
172
vendor/cxx-build/src/gen/fs.rs
vendored
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::error::Error as StdError;
|
||||
use std::fmt::{self, Display};
|
||||
use std::io::{self, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Error {
|
||||
source: Option<io::Error>,
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn kind(&self) -> io::ErrorKind {
|
||||
match &self.source {
|
||||
Some(io_error) => io_error.kind(),
|
||||
None => io::ErrorKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(&self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl StdError for Error {
|
||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||
let source = self.source.as_ref()?;
|
||||
Some(source)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! err {
|
||||
($io_error:expr, $fmt:expr $(, $path:expr)* $(,)?) => {
|
||||
Err(Error {
|
||||
source: Option::from($io_error),
|
||||
message: format!($fmt $(, $path.display())*),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn copy(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<u64> {
|
||||
let from = from.as_ref();
|
||||
let to = to.as_ref();
|
||||
match std::fs::copy(from, to) {
|
||||
Ok(n) => Ok(n),
|
||||
Err(e) => err!(e, "Failed to copy `{}` -> `{}`", from, to),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create_dir_all(path: impl AsRef<Path>) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
match std::fs::create_dir_all(path) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => err!(e, "Failed to create directory `{}`", path),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_dir() -> Result<PathBuf> {
|
||||
match std::env::current_dir() {
|
||||
Ok(dir) => Ok(dir),
|
||||
Err(e) => err!(e, "Failed to determine current directory"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn exists(path: impl AsRef<Path>) -> bool {
|
||||
let path = path.as_ref();
|
||||
// If path is a symlink, this returns true, regardless of whether the
|
||||
// symlink points to a path that exists.
|
||||
std::fs::symlink_metadata(path).is_ok()
|
||||
}
|
||||
|
||||
pub(crate) fn read(path: impl AsRef<Path>) -> Result<Vec<u8>> {
|
||||
let path = path.as_ref();
|
||||
match std::fs::read(path) {
|
||||
Ok(string) => Ok(string),
|
||||
Err(e) => err!(e, "Failed to read file `{}`", path),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_stdin() -> Result<Vec<u8>> {
|
||||
let mut bytes = Vec::new();
|
||||
match io::stdin().read_to_end(&mut bytes) {
|
||||
Ok(_len) => Ok(bytes),
|
||||
Err(e) => err!(e, "Failed to read input from stdin"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn remove_file(path: impl AsRef<Path>) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
match std::fs::remove_file(path) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => err!(e, "Failed to remove file `{}`", path),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn remove_dir(path: impl AsRef<Path>) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
match std::fs::remove_dir(path) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => err!(e, "Failed to remove directory `{}`", path),
|
||||
}
|
||||
}
|
||||
|
||||
fn symlink<'a>(
|
||||
original: &'a Path,
|
||||
link: &'a Path,
|
||||
fun: fn(&'a Path, &'a Path) -> io::Result<()>,
|
||||
) -> Result<()> {
|
||||
match fun(original, link) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => err!(
|
||||
e,
|
||||
"Failed to create symlink `{}` pointing to `{}`",
|
||||
link,
|
||||
original,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn symlink_fail(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
|
||||
err!(
|
||||
None,
|
||||
"Failed to create symlink `{}` pointing to `{}`",
|
||||
link.as_ref(),
|
||||
original.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use self::symlink_file as symlink_dir;
|
||||
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use self::symlink_fail as symlink_dir;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
|
||||
symlink(original.as_ref(), link.as_ref(), std::os::unix::fs::symlink)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
|
||||
symlink(
|
||||
original.as_ref(),
|
||||
link.as_ref(),
|
||||
std::os::windows::fs::symlink_file,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
|
||||
symlink(
|
||||
original.as_ref(),
|
||||
link.as_ref(),
|
||||
std::os::windows::fs::symlink_dir,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
match std::fs::write(path, contents) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => err!(e, "Failed to write file `{}`", path),
|
||||
}
|
||||
}
|
||||
46
vendor/cxx-build/src/gen/ifndef.rs
vendored
Normal file
46
vendor/cxx-build/src/gen/ifndef.rs
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use crate::gen::include::HEADER;
|
||||
use crate::gen::out::Content;
|
||||
|
||||
pub(super) fn write(out: &mut Content, needed: bool, guard: &str) {
|
||||
let ifndef = format!("#ifndef {}", guard);
|
||||
let define = format!("#define {}", guard);
|
||||
let endif = format!("#endif // {}", guard);
|
||||
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let begin = find_line(offset, &ifndef);
|
||||
let end = find_line(offset, &endif);
|
||||
if let (Some(begin), Some(end)) = (begin, end) {
|
||||
if !needed {
|
||||
return;
|
||||
}
|
||||
out.next_section();
|
||||
if offset == 0 {
|
||||
writeln!(out, "{}", ifndef);
|
||||
writeln!(out, "{}", define);
|
||||
}
|
||||
for line in HEADER[begin + ifndef.len()..end].trim().lines() {
|
||||
if line != define && !line.trim_start().starts_with("//") {
|
||||
writeln!(out, "{}", line);
|
||||
}
|
||||
}
|
||||
offset = end + endif.len();
|
||||
} else if offset == 0 {
|
||||
panic!("not found in cxx.h header: {}", guard)
|
||||
} else {
|
||||
writeln!(out, "{}", endif);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_line(mut offset: usize, line: &str) -> Option<usize> {
|
||||
loop {
|
||||
offset += HEADER[offset..].find(line)?;
|
||||
let rest = &HEADER[offset + line.len()..];
|
||||
if rest.starts_with('\n') || rest.starts_with('\r') {
|
||||
return Some(offset);
|
||||
}
|
||||
offset += line.len();
|
||||
}
|
||||
}
|
||||
204
vendor/cxx-build/src/gen/include.rs
vendored
Normal file
204
vendor/cxx-build/src/gen/include.rs
vendored
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
use crate::gen::out::{Content, OutFile};
|
||||
use crate::syntax::{self, IncludeKind};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// The complete contents of the "rust/cxx.h" header.
|
||||
pub static HEADER: &str = include_str!("include/cxx.h");
|
||||
|
||||
/// A header to #include.
|
||||
///
|
||||
/// The cxxbridge tool does not parse or even require the given paths to exist;
|
||||
/// they simply go into the generated C++ code as #include lines.
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Include {
|
||||
/// The header's path, not including the enclosing quotation marks or angle
|
||||
/// brackets.
|
||||
pub path: String,
|
||||
/// Whether to emit `#include "path"` or `#include <path>`.
|
||||
pub kind: IncludeKind,
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
pub struct Includes<'a> {
|
||||
pub custom: Vec<Include>,
|
||||
pub algorithm: bool,
|
||||
pub array: bool,
|
||||
pub cassert: bool,
|
||||
pub cstddef: bool,
|
||||
pub cstdint: bool,
|
||||
pub cstring: bool,
|
||||
pub exception: bool,
|
||||
pub functional: bool,
|
||||
pub initializer_list: bool,
|
||||
pub iterator: bool,
|
||||
pub memory: bool,
|
||||
pub new: bool,
|
||||
pub stdexcept: bool,
|
||||
pub string: bool,
|
||||
pub type_traits: bool,
|
||||
pub utility: bool,
|
||||
pub vector: bool,
|
||||
pub basetsd: bool,
|
||||
pub sys_types: bool,
|
||||
pub content: Content<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Includes<'a> {
|
||||
pub fn new() -> Self {
|
||||
Includes::default()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, include: impl Into<Include>) {
|
||||
self.custom.push(include.into());
|
||||
}
|
||||
|
||||
pub fn has_cxx_header(&self) -> bool {
|
||||
self.custom
|
||||
.iter()
|
||||
.any(|header| header.path == "rust/cxx.h" || header.path == "rust\\cxx.h")
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write(out: &mut OutFile) {
|
||||
let header = out.header;
|
||||
let include = &mut out.include;
|
||||
let cxx_header = include.has_cxx_header();
|
||||
let out = &mut include.content;
|
||||
|
||||
if header {
|
||||
writeln!(out, "#pragma once");
|
||||
}
|
||||
|
||||
for include in &include.custom {
|
||||
match include.kind {
|
||||
IncludeKind::Quoted => {
|
||||
writeln!(out, "#include \"{}\"", include.path.escape_default());
|
||||
}
|
||||
IncludeKind::Bracketed => {
|
||||
writeln!(out, "#include <{}>", include.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Includes {
|
||||
custom: _,
|
||||
algorithm,
|
||||
array,
|
||||
cassert,
|
||||
cstddef,
|
||||
cstdint,
|
||||
cstring,
|
||||
exception,
|
||||
functional,
|
||||
initializer_list,
|
||||
iterator,
|
||||
memory,
|
||||
new,
|
||||
stdexcept,
|
||||
string,
|
||||
type_traits,
|
||||
utility,
|
||||
vector,
|
||||
basetsd,
|
||||
sys_types,
|
||||
content: _,
|
||||
} = *include;
|
||||
|
||||
if algorithm && !cxx_header {
|
||||
writeln!(out, "#include <algorithm>");
|
||||
}
|
||||
if array && !cxx_header {
|
||||
writeln!(out, "#include <array>");
|
||||
}
|
||||
if cassert && !cxx_header {
|
||||
writeln!(out, "#include <cassert>");
|
||||
}
|
||||
if cstddef && !cxx_header {
|
||||
writeln!(out, "#include <cstddef>");
|
||||
}
|
||||
if cstdint && !cxx_header {
|
||||
writeln!(out, "#include <cstdint>");
|
||||
}
|
||||
if cstring {
|
||||
writeln!(out, "#include <cstring>");
|
||||
}
|
||||
if exception && !cxx_header {
|
||||
writeln!(out, "#include <exception>");
|
||||
}
|
||||
if functional {
|
||||
writeln!(out, "#include <functional>");
|
||||
}
|
||||
if initializer_list && !cxx_header {
|
||||
writeln!(out, "#include <initializer_list>");
|
||||
}
|
||||
if iterator && !cxx_header {
|
||||
writeln!(out, "#include <iterator>");
|
||||
}
|
||||
if memory {
|
||||
writeln!(out, "#include <memory>");
|
||||
}
|
||||
if new && !cxx_header {
|
||||
writeln!(out, "#include <new>");
|
||||
}
|
||||
if stdexcept && !cxx_header {
|
||||
writeln!(out, "#include <stdexcept>");
|
||||
}
|
||||
if string && !cxx_header {
|
||||
writeln!(out, "#include <string>");
|
||||
}
|
||||
if type_traits && !cxx_header {
|
||||
writeln!(out, "#include <type_traits>");
|
||||
}
|
||||
if utility && !cxx_header {
|
||||
writeln!(out, "#include <utility>");
|
||||
}
|
||||
if vector && !cxx_header {
|
||||
writeln!(out, "#include <vector>");
|
||||
}
|
||||
if basetsd && !cxx_header {
|
||||
writeln!(out, "#if defined(_WIN32)");
|
||||
writeln!(out, "#include <basetsd.h>");
|
||||
}
|
||||
if sys_types && !cxx_header {
|
||||
if basetsd {
|
||||
writeln!(out, "#else");
|
||||
} else {
|
||||
writeln!(out, "#if not defined(_WIN32)");
|
||||
}
|
||||
}
|
||||
if sys_types && !cxx_header {
|
||||
writeln!(out, "#include <sys/types.h>");
|
||||
}
|
||||
if (basetsd || sys_types) && !cxx_header {
|
||||
writeln!(out, "#endif");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i, 'a> Extend<&'i Include> for Includes<'a> {
|
||||
fn extend<I: IntoIterator<Item = &'i Include>>(&mut self, iter: I) {
|
||||
self.custom.extend(iter.into_iter().cloned());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'i> From<&'i syntax::Include> for Include {
|
||||
fn from(include: &syntax::Include) -> Self {
|
||||
Include {
|
||||
path: include.path.clone(),
|
||||
kind: include.kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for Includes<'a> {
|
||||
type Target = Content<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.content
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for Includes<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.content
|
||||
}
|
||||
}
|
||||
1111
vendor/cxx-build/src/gen/include/cxx.h
vendored
Normal file
1111
vendor/cxx-build/src/gen/include/cxx.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
188
vendor/cxx-build/src/gen/mod.rs
vendored
Normal file
188
vendor/cxx-build/src/gen/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
// Functionality that is shared between the cxx_build::bridge entry point and
|
||||
// the cxxbridge CLI command.
|
||||
|
||||
mod block;
|
||||
mod builtin;
|
||||
mod cfg;
|
||||
mod check;
|
||||
pub(super) mod error;
|
||||
mod file;
|
||||
pub(super) mod fs;
|
||||
mod ifndef;
|
||||
pub(super) mod include;
|
||||
mod names;
|
||||
mod namespace;
|
||||
mod nested;
|
||||
pub(super) mod out;
|
||||
mod write;
|
||||
|
||||
use self::cfg::UnsupportedCfgEvaluator;
|
||||
use self::error::{format_err, Result};
|
||||
use self::file::File;
|
||||
use self::include::Include;
|
||||
use crate::syntax::cfg::CfgExpr;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::{self, attrs, Types};
|
||||
use std::collections::BTreeSet as Set;
|
||||
use std::path::Path;
|
||||
|
||||
pub(super) use self::error::Error;
|
||||
|
||||
/// Options for C++ code generation.
|
||||
///
|
||||
/// We expect options to be added over time, so this is a non-exhaustive struct.
|
||||
/// To instantiate one you need to crate a default value and mutate those fields
|
||||
/// that you want to modify.
|
||||
///
|
||||
/// ```
|
||||
/// # use cxx_gen::Opt;
|
||||
/// #
|
||||
/// let impl_annotations = r#"__attribute__((visibility("default")))"#.to_owned();
|
||||
///
|
||||
/// let mut opt = Opt::default();
|
||||
/// opt.cxx_impl_annotations = Some(impl_annotations);
|
||||
/// ```
|
||||
#[non_exhaustive]
|
||||
pub struct Opt {
|
||||
/// Any additional headers to #include. The cxxbridge tool does not parse or
|
||||
/// even require the given paths to exist; they simply go into the generated
|
||||
/// C++ code as #include lines.
|
||||
pub include: Vec<Include>,
|
||||
/// Optional annotation for implementations of C++ function wrappers that
|
||||
/// may be exposed to Rust. You may for example need to provide
|
||||
/// `__declspec(dllexport)` or `__attribute__((visibility("default")))` if
|
||||
/// Rust code from one shared object or executable depends on these C++
|
||||
/// functions in another.
|
||||
pub cxx_impl_annotations: Option<String>,
|
||||
|
||||
pub(super) gen_header: bool,
|
||||
pub(super) gen_implementation: bool,
|
||||
pub(super) allow_dot_includes: bool,
|
||||
pub(super) cfg_evaluator: Box<dyn CfgEvaluator>,
|
||||
pub(super) doxygen: bool,
|
||||
}
|
||||
|
||||
pub(super) trait CfgEvaluator {
|
||||
fn eval(&self, name: &str, value: Option<&str>) -> CfgResult;
|
||||
}
|
||||
|
||||
pub(super) enum CfgResult {
|
||||
True,
|
||||
False,
|
||||
Undetermined { msg: String },
|
||||
}
|
||||
|
||||
/// Results of code generation.
|
||||
#[derive(Default)]
|
||||
pub struct GeneratedCode {
|
||||
/// The bytes of a C++ header file.
|
||||
pub header: Vec<u8>,
|
||||
/// The bytes of a C++ implementation file (e.g. .cc, cpp etc.)
|
||||
pub implementation: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Default for Opt {
|
||||
fn default() -> Self {
|
||||
Opt {
|
||||
include: Vec::new(),
|
||||
cxx_impl_annotations: None,
|
||||
gen_header: true,
|
||||
gen_implementation: true,
|
||||
allow_dot_includes: true,
|
||||
cfg_evaluator: Box::new(UnsupportedCfgEvaluator),
|
||||
doxygen: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn generate_from_path(path: &Path, opt: &Opt) -> GeneratedCode {
|
||||
let source = match read_to_string(path) {
|
||||
Ok(source) => source,
|
||||
Err(err) => format_err(path, "", err),
|
||||
};
|
||||
match generate_from_string(&source, opt) {
|
||||
Ok(out) => out,
|
||||
Err(err) => format_err(path, &source, err),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_to_string(path: &Path) -> Result<String> {
|
||||
let bytes = if path == Path::new("-") {
|
||||
fs::read_stdin()
|
||||
} else {
|
||||
fs::read(path)
|
||||
}?;
|
||||
match String::from_utf8(bytes) {
|
||||
Ok(string) => Ok(string),
|
||||
Err(err) => Err(Error::Utf8(path.to_owned(), err.utf8_error())),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_from_string(source: &str, opt: &Opt) -> Result<GeneratedCode> {
|
||||
let mut source = source;
|
||||
if source.starts_with("#!") && !source.starts_with("#![") {
|
||||
let shebang_end = source.find('\n').unwrap_or(source.len());
|
||||
source = &source[shebang_end..];
|
||||
}
|
||||
proc_macro2::fallback::force();
|
||||
let syntax: File = syn::parse_str(source)?;
|
||||
generate(syntax, opt)
|
||||
}
|
||||
|
||||
pub(super) fn generate(syntax: File, opt: &Opt) -> Result<GeneratedCode> {
|
||||
if syntax.modules.is_empty() {
|
||||
return Err(Error::NoBridgeMod);
|
||||
}
|
||||
|
||||
let ref mut apis = Vec::new();
|
||||
let ref mut errors = Errors::new();
|
||||
let ref mut cfg_errors = Set::new();
|
||||
for bridge in syntax.modules {
|
||||
let mut cfg = CfgExpr::Unconditional;
|
||||
attrs::parse(
|
||||
errors,
|
||||
bridge.attrs,
|
||||
attrs::Parser {
|
||||
cfg: Some(&mut cfg),
|
||||
ignore_unrecognized: true,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
if cfg::eval(errors, cfg_errors, opt.cfg_evaluator.as_ref(), &cfg) {
|
||||
let ref namespace = bridge.namespace;
|
||||
let trusted = bridge.unsafety.is_some();
|
||||
apis.extend(syntax::parse_items(
|
||||
errors,
|
||||
bridge.content,
|
||||
trusted,
|
||||
namespace,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
cfg::strip(errors, cfg_errors, opt.cfg_evaluator.as_ref(), apis);
|
||||
errors.propagate()?;
|
||||
|
||||
let ref types = Types::collect(errors, apis);
|
||||
check::precheck(errors, apis, opt);
|
||||
errors.propagate()?;
|
||||
|
||||
let generator = check::Generator::Build;
|
||||
check::typecheck(errors, apis, types, generator);
|
||||
errors.propagate()?;
|
||||
|
||||
// Some callers may wish to generate both header and implementation from the
|
||||
// same token stream to avoid parsing twice. Others only need to generate
|
||||
// one or the other.
|
||||
let (mut header, mut implementation) = Default::default();
|
||||
if opt.gen_header {
|
||||
header = write::gen(apis, types, opt, true);
|
||||
}
|
||||
if opt.gen_implementation {
|
||||
implementation = write::gen(apis, types, opt, false);
|
||||
}
|
||||
Ok(GeneratedCode {
|
||||
header,
|
||||
implementation,
|
||||
})
|
||||
}
|
||||
14
vendor/cxx-build/src/gen/names.rs
vendored
Normal file
14
vendor/cxx-build/src/gen/names.rs
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use crate::syntax::Pair;
|
||||
|
||||
impl Pair {
|
||||
pub fn to_fully_qualified(&self) -> String {
|
||||
let mut fully_qualified = String::new();
|
||||
for segment in &self.namespace {
|
||||
fully_qualified += "::";
|
||||
fully_qualified += &segment.to_string();
|
||||
}
|
||||
fully_qualified += "::";
|
||||
fully_qualified += &self.cxx.to_string();
|
||||
fully_qualified
|
||||
}
|
||||
}
|
||||
14
vendor/cxx-build/src/gen/namespace.rs
vendored
Normal file
14
vendor/cxx-build/src/gen/namespace.rs
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::Api;
|
||||
|
||||
impl Api {
|
||||
pub fn namespace(&self) -> &Namespace {
|
||||
match self {
|
||||
Api::CxxFunction(efn) | Api::RustFunction(efn) => &efn.name.namespace,
|
||||
Api::CxxType(ety) | Api::RustType(ety) => &ety.name.namespace,
|
||||
Api::Enum(enm) => &enm.name.namespace,
|
||||
Api::Struct(strct) => &strct.name.namespace,
|
||||
Api::Impl(_) | Api::Include(_) | Api::TypeAlias(_) => Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
155
vendor/cxx-build/src/gen/nested.rs
vendored
Normal file
155
vendor/cxx-build/src/gen/nested.rs
vendored
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
use crate::syntax::map::UnorderedMap as Map;
|
||||
use crate::syntax::Api;
|
||||
use proc_macro2::Ident;
|
||||
|
||||
pub struct NamespaceEntries<'a> {
|
||||
direct: Vec<&'a Api>,
|
||||
nested: Vec<(&'a Ident, NamespaceEntries<'a>)>,
|
||||
}
|
||||
|
||||
impl<'a> NamespaceEntries<'a> {
|
||||
pub fn new(apis: Vec<&'a Api>) -> Self {
|
||||
sort_by_inner_namespace(apis, 0)
|
||||
}
|
||||
|
||||
pub fn direct_content(&self) -> &[&'a Api] {
|
||||
&self.direct
|
||||
}
|
||||
|
||||
pub fn nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)> {
|
||||
self.nested.iter().map(|(k, entries)| (*k, entries))
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
|
||||
let mut direct = Vec::new();
|
||||
let mut nested_namespaces = Vec::new();
|
||||
let mut index_of_namespace = Map::new();
|
||||
|
||||
for api in &apis {
|
||||
if let Some(first_ns_elem) = api.namespace().iter().nth(depth) {
|
||||
match index_of_namespace.get(first_ns_elem) {
|
||||
None => {
|
||||
index_of_namespace.insert(first_ns_elem, nested_namespaces.len());
|
||||
nested_namespaces.push((first_ns_elem, vec![*api]));
|
||||
}
|
||||
Some(&index) => nested_namespaces[index].1.push(*api),
|
||||
}
|
||||
continue;
|
||||
}
|
||||
direct.push(*api);
|
||||
}
|
||||
|
||||
let nested = nested_namespaces
|
||||
.into_iter()
|
||||
.map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
|
||||
.collect();
|
||||
|
||||
NamespaceEntries { direct, nested }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NamespaceEntries;
|
||||
use crate::syntax::attrs::OtherAttrs;
|
||||
use crate::syntax::cfg::CfgExpr;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::{Api, Doc, ExternType, ForeignName, Lang, Lifetimes, Pair};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use std::iter::FromIterator;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::Token;
|
||||
|
||||
#[test]
|
||||
fn test_ns_entries_sort() {
|
||||
let apis = &[
|
||||
make_api(None, "C"),
|
||||
make_api(None, "A"),
|
||||
make_api(Some("G"), "E"),
|
||||
make_api(Some("D"), "F"),
|
||||
make_api(Some("G"), "H"),
|
||||
make_api(Some("D::K"), "L"),
|
||||
make_api(Some("D::K"), "M"),
|
||||
make_api(None, "B"),
|
||||
make_api(Some("D"), "I"),
|
||||
make_api(Some("D"), "J"),
|
||||
];
|
||||
|
||||
let root = NamespaceEntries::new(Vec::from_iter(apis));
|
||||
|
||||
// ::
|
||||
let root_direct = root.direct_content();
|
||||
assert_eq!(root_direct.len(), 3);
|
||||
assert_ident(root_direct[0], "C");
|
||||
assert_ident(root_direct[1], "A");
|
||||
assert_ident(root_direct[2], "B");
|
||||
|
||||
let mut root_nested = root.nested_content();
|
||||
let (id, g) = root_nested.next().unwrap();
|
||||
assert_eq!(id, "G");
|
||||
let (id, d) = root_nested.next().unwrap();
|
||||
assert_eq!(id, "D");
|
||||
assert!(root_nested.next().is_none());
|
||||
|
||||
// ::G
|
||||
let g_direct = g.direct_content();
|
||||
assert_eq!(g_direct.len(), 2);
|
||||
assert_ident(g_direct[0], "E");
|
||||
assert_ident(g_direct[1], "H");
|
||||
|
||||
let mut g_nested = g.nested_content();
|
||||
assert!(g_nested.next().is_none());
|
||||
|
||||
// ::D
|
||||
let d_direct = d.direct_content();
|
||||
assert_eq!(d_direct.len(), 3);
|
||||
assert_ident(d_direct[0], "F");
|
||||
assert_ident(d_direct[1], "I");
|
||||
assert_ident(d_direct[2], "J");
|
||||
|
||||
let mut d_nested = d.nested_content();
|
||||
let (id, k) = d_nested.next().unwrap();
|
||||
assert_eq!(id, "K");
|
||||
|
||||
// ::D::K
|
||||
let k_direct = k.direct_content();
|
||||
assert_eq!(k_direct.len(), 2);
|
||||
assert_ident(k_direct[0], "L");
|
||||
assert_ident(k_direct[1], "M");
|
||||
}
|
||||
|
||||
fn assert_ident(api: &Api, expected: &str) {
|
||||
if let Api::CxxType(cxx_type) = api {
|
||||
assert_eq!(cxx_type.name.cxx.to_string(), expected);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn make_api(ns: Option<&str>, ident: &str) -> Api {
|
||||
let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap());
|
||||
Api::CxxType(ExternType {
|
||||
cfg: CfgExpr::Unconditional,
|
||||
lang: Lang::Rust,
|
||||
doc: Doc::new(),
|
||||
derives: Vec::new(),
|
||||
attrs: OtherAttrs::none(),
|
||||
visibility: Token),
|
||||
type_token: Token),
|
||||
name: Pair {
|
||||
namespace: ns,
|
||||
cxx: ForeignName::parse(ident, Span::call_site()).unwrap(),
|
||||
rust: Ident::new(ident, Span::call_site()),
|
||||
},
|
||||
generics: Lifetimes {
|
||||
lt_token: None,
|
||||
lifetimes: Punctuated::new(),
|
||||
gt_token: None,
|
||||
},
|
||||
colon_token: None,
|
||||
bounds: Vec::new(),
|
||||
semi_token: Token),
|
||||
trusted: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
210
vendor/cxx-build/src/gen/out.rs
vendored
Normal file
210
vendor/cxx-build/src/gen/out.rs
vendored
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
use crate::gen::block::Block;
|
||||
use crate::gen::builtin::Builtins;
|
||||
use crate::gen::include::Includes;
|
||||
use crate::gen::Opt;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::Types;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{self, Arguments, Write};
|
||||
|
||||
pub(crate) struct OutFile<'a> {
|
||||
pub header: bool,
|
||||
pub opt: &'a Opt,
|
||||
pub types: &'a Types<'a>,
|
||||
pub include: Includes<'a>,
|
||||
pub builtin: Builtins<'a>,
|
||||
content: RefCell<Content<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Content<'a> {
|
||||
bytes: String,
|
||||
namespace: &'a Namespace,
|
||||
blocks: Vec<BlockBoundary<'a>>,
|
||||
section_pending: bool,
|
||||
blocks_pending: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
enum BlockBoundary<'a> {
|
||||
Begin(Block<'a>),
|
||||
End(Block<'a>),
|
||||
}
|
||||
|
||||
impl<'a> OutFile<'a> {
|
||||
pub fn new(header: bool, opt: &'a Opt, types: &'a Types) -> Self {
|
||||
OutFile {
|
||||
header,
|
||||
opt,
|
||||
types,
|
||||
include: Includes::new(),
|
||||
builtin: Builtins::new(),
|
||||
content: RefCell::new(Content::new()),
|
||||
}
|
||||
}
|
||||
|
||||
// Write a blank line if the preceding section had any contents.
|
||||
pub fn next_section(&mut self) {
|
||||
self.content.get_mut().next_section();
|
||||
}
|
||||
|
||||
pub fn begin_block(&mut self, block: Block<'a>) {
|
||||
self.content.get_mut().begin_block(block);
|
||||
}
|
||||
|
||||
pub fn end_block(&mut self, block: Block<'a>) {
|
||||
self.content.get_mut().end_block(block);
|
||||
}
|
||||
|
||||
pub fn set_namespace(&mut self, namespace: &'a Namespace) {
|
||||
self.content.get_mut().set_namespace(namespace);
|
||||
}
|
||||
|
||||
pub fn write_fmt(&self, args: Arguments) {
|
||||
let content = &mut *self.content.borrow_mut();
|
||||
Write::write_fmt(content, args).unwrap();
|
||||
}
|
||||
|
||||
pub fn content(&mut self) -> Vec<u8> {
|
||||
self.flush();
|
||||
let include = &self.include.content.bytes;
|
||||
let builtin = &self.builtin.content.bytes;
|
||||
let content = &self.content.get_mut().bytes;
|
||||
let len = include.len() + builtin.len() + content.len() + 2;
|
||||
let mut out = String::with_capacity(len);
|
||||
out.push_str(include);
|
||||
if !out.is_empty() && !builtin.is_empty() {
|
||||
out.push('\n');
|
||||
}
|
||||
out.push_str(builtin);
|
||||
if !out.is_empty() && !content.is_empty() {
|
||||
out.push('\n');
|
||||
}
|
||||
out.push_str(content);
|
||||
if out.is_empty() {
|
||||
out.push_str("// empty\n");
|
||||
}
|
||||
out.into_bytes()
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
self.include.content.flush();
|
||||
self.builtin.content.flush();
|
||||
self.content.get_mut().flush();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Write for Content<'a> {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.write(s);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for Content<'a> {
|
||||
fn eq(&self, _other: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Content<'a> {
|
||||
fn new() -> Self {
|
||||
Content::default()
|
||||
}
|
||||
|
||||
pub fn next_section(&mut self) {
|
||||
self.section_pending = true;
|
||||
}
|
||||
|
||||
pub fn begin_block(&mut self, block: Block<'a>) {
|
||||
self.push_block_boundary(BlockBoundary::Begin(block));
|
||||
}
|
||||
|
||||
pub fn end_block(&mut self, block: Block<'a>) {
|
||||
self.push_block_boundary(BlockBoundary::End(block));
|
||||
}
|
||||
|
||||
pub fn set_namespace(&mut self, namespace: &'a Namespace) {
|
||||
for name in self.namespace.iter().rev() {
|
||||
self.end_block(Block::UserDefinedNamespace(name));
|
||||
}
|
||||
for name in namespace {
|
||||
self.begin_block(Block::UserDefinedNamespace(name));
|
||||
}
|
||||
self.namespace = namespace;
|
||||
}
|
||||
|
||||
pub fn write_fmt(&mut self, args: Arguments) {
|
||||
Write::write_fmt(self, args).unwrap();
|
||||
}
|
||||
|
||||
fn write(&mut self, b: &str) {
|
||||
if !b.is_empty() {
|
||||
if self.blocks_pending > 0 {
|
||||
self.flush_blocks();
|
||||
}
|
||||
if self.section_pending && !self.bytes.is_empty() {
|
||||
self.bytes.push('\n');
|
||||
}
|
||||
self.bytes.push_str(b);
|
||||
self.section_pending = false;
|
||||
self.blocks_pending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn push_block_boundary(&mut self, boundary: BlockBoundary<'a>) {
|
||||
if self.blocks_pending > 0 && boundary == self.blocks.last().unwrap().rev() {
|
||||
self.blocks.pop();
|
||||
self.blocks_pending -= 1;
|
||||
} else {
|
||||
self.blocks.push(boundary);
|
||||
self.blocks_pending += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
self.set_namespace(Default::default());
|
||||
if self.blocks_pending > 0 {
|
||||
self.flush_blocks();
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_blocks(&mut self) {
|
||||
self.section_pending = !self.bytes.is_empty();
|
||||
let mut read = self.blocks.len() - self.blocks_pending;
|
||||
let mut write = read;
|
||||
|
||||
while read < self.blocks.len() {
|
||||
match self.blocks[read] {
|
||||
BlockBoundary::Begin(begin_block) => {
|
||||
if self.section_pending {
|
||||
self.bytes.push('\n');
|
||||
self.section_pending = false;
|
||||
}
|
||||
Block::write_begin(begin_block, &mut self.bytes);
|
||||
self.blocks[write] = BlockBoundary::Begin(begin_block);
|
||||
write += 1;
|
||||
}
|
||||
BlockBoundary::End(end_block) => {
|
||||
write = write.checked_sub(1).unwrap();
|
||||
let begin_block = self.blocks[write];
|
||||
assert_eq!(begin_block, BlockBoundary::Begin(end_block));
|
||||
Block::write_end(end_block, &mut self.bytes);
|
||||
self.section_pending = true;
|
||||
}
|
||||
}
|
||||
read += 1;
|
||||
}
|
||||
|
||||
self.blocks.truncate(write);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BlockBoundary<'a> {
|
||||
fn rev(self) -> BlockBoundary<'a> {
|
||||
match self {
|
||||
BlockBoundary::Begin(block) => BlockBoundary::End(block),
|
||||
BlockBoundary::End(block) => BlockBoundary::Begin(block),
|
||||
}
|
||||
}
|
||||
}
|
||||
1932
vendor/cxx-build/src/gen/write.rs
vendored
Normal file
1932
vendor/cxx-build/src/gen/write.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
30
vendor/cxx-build/src/intern.rs
vendored
Normal file
30
vendor/cxx-build/src/intern.rs
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use crate::syntax::set::UnorderedSet as Set;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::sync::{Mutex, PoisonError};
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct InternedString(&'static str);
|
||||
|
||||
impl InternedString {
|
||||
pub fn str(self) -> &'static str {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intern(s: &str) -> InternedString {
|
||||
static INTERN: OnceCell<Mutex<Set<&'static str>>> = OnceCell::new();
|
||||
|
||||
let mut set = INTERN
|
||||
.get_or_init(|| Mutex::new(Set::new()))
|
||||
.lock()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
|
||||
InternedString(match set.get(s) {
|
||||
Some(interned) => *interned,
|
||||
None => {
|
||||
let interned = Box::leak(Box::from(s));
|
||||
set.insert(interned);
|
||||
interned
|
||||
}
|
||||
})
|
||||
}
|
||||
477
vendor/cxx-build/src/lib.rs
vendored
Normal file
477
vendor/cxx-build/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
//! The CXX code generator for constructing and compiling C++ code.
|
||||
//!
|
||||
//! This is intended to be used from Cargo build scripts to execute CXX's
|
||||
//! C++ code generator, set up any additional compiler flags depending on
|
||||
//! the use case, and make the C++ compiler invocation.
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! Example of a canonical Cargo build script that builds a CXX bridge:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! // build.rs
|
||||
//!
|
||||
//! fn main() {
|
||||
//! cxx_build::bridge("src/main.rs")
|
||||
//! .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");
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! A runnable working setup with this build script is shown in the *demo*
|
||||
//! directory of [https://github.com/dtolnay/cxx].
|
||||
//!
|
||||
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
|
||||
//!
|
||||
//! <br>
|
||||
//!
|
||||
//! # Alternatives
|
||||
//!
|
||||
//! 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.
|
||||
//!
|
||||
//! ```bash
|
||||
//! $ cargo install cxxbridge-cmd # or build it from the repo
|
||||
//!
|
||||
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
|
||||
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
|
||||
//! ```
|
||||
|
||||
#![allow(
|
||||
clippy::cast_sign_loss,
|
||||
clippy::default_trait_access,
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::doc_markdown,
|
||||
clippy::drop_copy,
|
||||
clippy::enum_glob_use,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::if_same_then_else,
|
||||
clippy::inherent_to_string,
|
||||
clippy::items_after_statements,
|
||||
clippy::let_underscore_drop,
|
||||
clippy::match_bool,
|
||||
clippy::match_on_vec_items,
|
||||
clippy::match_same_arms,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::needless_doctest_main,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::new_without_default,
|
||||
clippy::nonminimal_bool,
|
||||
clippy::option_if_let_else,
|
||||
clippy::or_fun_call,
|
||||
clippy::redundant_else,
|
||||
clippy::shadow_unrelated,
|
||||
clippy::significant_drop_in_scrutinee,
|
||||
clippy::similar_names,
|
||||
clippy::single_match_else,
|
||||
clippy::struct_excessive_bools,
|
||||
clippy::too_many_arguments,
|
||||
clippy::too_many_lines,
|
||||
clippy::toplevel_ref_arg,
|
||||
clippy::upper_case_acronyms,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6983
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
|
||||
mod cargo;
|
||||
mod cfg;
|
||||
mod deps;
|
||||
mod error;
|
||||
mod gen;
|
||||
mod intern;
|
||||
mod out;
|
||||
mod paths;
|
||||
mod syntax;
|
||||
mod target;
|
||||
mod vec;
|
||||
|
||||
use crate::cargo::CargoEnvCfgEvaluator;
|
||||
use crate::deps::{Crate, HeaderDir};
|
||||
use crate::error::{Error, Result};
|
||||
use crate::gen::error::report;
|
||||
use crate::gen::Opt;
|
||||
use crate::paths::PathExt;
|
||||
use crate::syntax::map::{Entry, UnorderedMap};
|
||||
use crate::target::TargetDir;
|
||||
use cc::Build;
|
||||
use std::collections::BTreeSet;
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::io::{self, Write};
|
||||
use std::iter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process;
|
||||
|
||||
pub use crate::cfg::{Cfg, CFG};
|
||||
|
||||
/// This returns a [`cc::Build`] on which you should continue to set up any
|
||||
/// additional source files or compiler flags, and lastly call its [`compile`]
|
||||
/// method to execute the C++ build.
|
||||
///
|
||||
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
|
||||
#[must_use]
|
||||
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
|
||||
bridges(iter::once(rust_source_file))
|
||||
}
|
||||
|
||||
/// `cxx_build::bridge` but for when more than one file contains a
|
||||
/// #\[cxx::bridge\] module.
|
||||
///
|
||||
/// ```no_run
|
||||
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
|
||||
/// cxx_build::bridges(source_files)
|
||||
/// .file("src/demo.cc")
|
||||
/// .flag_if_supported("-std=c++11")
|
||||
/// .compile("cxxbridge-demo");
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
|
||||
let ref mut rust_source_files = rust_source_files.into_iter();
|
||||
build(rust_source_files).unwrap_or_else(|err| {
|
||||
let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
|
||||
process::exit(1);
|
||||
})
|
||||
}
|
||||
|
||||
struct Project {
|
||||
include_prefix: PathBuf,
|
||||
manifest_dir: PathBuf,
|
||||
// The `links = "..."` value from Cargo.toml.
|
||||
links_attribute: Option<OsString>,
|
||||
// Output directory as received from Cargo.
|
||||
out_dir: PathBuf,
|
||||
// Directory into which to symlink all generated code.
|
||||
//
|
||||
// This is *not* used for an #include path, only as a debugging convenience.
|
||||
// Normally available at target/cxxbridge/ if we are able to know where the
|
||||
// target dir is, otherwise under a common scratch dir.
|
||||
//
|
||||
// The reason this isn't the #include dir is that we do not want builds to
|
||||
// have access to headers from arbitrary other parts of the dependency
|
||||
// graph. Using a global directory for all builds would be both a race
|
||||
// condition depending on what order Cargo randomly executes the build
|
||||
// scripts, as well as semantically undesirable for builds not to have to
|
||||
// declare their real dependencies.
|
||||
shared_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
fn init() -> Result<Self> {
|
||||
let include_prefix = Path::new(CFG.include_prefix);
|
||||
assert!(include_prefix.is_relative());
|
||||
let include_prefix = include_prefix.components().collect();
|
||||
|
||||
let links_attribute = env::var_os("CARGO_MANIFEST_LINKS");
|
||||
|
||||
let manifest_dir = paths::manifest_dir()?;
|
||||
let out_dir = paths::out_dir()?;
|
||||
|
||||
let shared_dir = match target::find_target_dir(&out_dir) {
|
||||
TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
|
||||
TargetDir::Unknown => scratch::path("cxxbridge"),
|
||||
};
|
||||
|
||||
Ok(Project {
|
||||
include_prefix,
|
||||
manifest_dir,
|
||||
links_attribute,
|
||||
out_dir,
|
||||
shared_dir,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
|
||||
// subdirectory to avoid stomping on other things that the caller's build script
|
||||
// might be doing inside OUT_DIR.
|
||||
//
|
||||
// $OUT_DIR/
|
||||
// cxxbridge/
|
||||
// crate/
|
||||
// $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
|
||||
// include/
|
||||
// rust/
|
||||
// cxx.h
|
||||
// $CARGO_PKG_NAME/
|
||||
// .../
|
||||
// lib.rs.h
|
||||
// sources/
|
||||
// $CARGO_PKG_NAME/
|
||||
// .../
|
||||
// lib.rs.cc
|
||||
//
|
||||
// The crate/ and include/ directories are placed on the #include path for the
|
||||
// current build as well as for downstream builds that have a direct dependency
|
||||
// on the current crate.
|
||||
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
|
||||
let ref prj = Project::init()?;
|
||||
validate_cfg(prj)?;
|
||||
let this_crate = make_this_crate(prj)?;
|
||||
|
||||
let mut build = Build::new();
|
||||
build.cpp(true);
|
||||
build.cpp_link_stdlib(None); // linked via link-cplusplus crate
|
||||
|
||||
for path in rust_source_files {
|
||||
generate_bridge(prj, &mut build, path.as_ref())?;
|
||||
}
|
||||
|
||||
this_crate.print_to_cargo();
|
||||
eprintln!("\nCXX include path:");
|
||||
for header_dir in this_crate.header_dirs {
|
||||
build.include(&header_dir.path);
|
||||
if header_dir.exported {
|
||||
eprintln!(" {}", header_dir.path.display());
|
||||
} else {
|
||||
eprintln!(" {} (private)", header_dir.path.display());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(build)
|
||||
}
|
||||
|
||||
fn validate_cfg(prj: &Project) -> Result<()> {
|
||||
for exported_dir in &CFG.exported_header_dirs {
|
||||
if !exported_dir.is_absolute() {
|
||||
return Err(Error::ExportedDirNotAbsolute(exported_dir));
|
||||
}
|
||||
}
|
||||
|
||||
for prefix in &CFG.exported_header_prefixes {
|
||||
if prefix.is_empty() {
|
||||
return Err(Error::ExportedEmptyPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
if prj.links_attribute.is_none() {
|
||||
if !CFG.exported_header_dirs.is_empty() {
|
||||
return Err(Error::ExportedDirsWithoutLinks);
|
||||
}
|
||||
if !CFG.exported_header_prefixes.is_empty() {
|
||||
return Err(Error::ExportedPrefixesWithoutLinks);
|
||||
}
|
||||
if !CFG.exported_header_links.is_empty() {
|
||||
return Err(Error::ExportedLinksWithoutLinks);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_this_crate(prj: &Project) -> Result<Crate> {
|
||||
let crate_dir = make_crate_dir(prj);
|
||||
let include_dir = make_include_dir(prj)?;
|
||||
|
||||
let mut this_crate = Crate {
|
||||
include_prefix: Some(prj.include_prefix.clone()),
|
||||
links: prj.links_attribute.clone(),
|
||||
header_dirs: Vec::new(),
|
||||
};
|
||||
|
||||
// The generated code directory (include_dir) is placed in front of
|
||||
// crate_dir on the include line so that `#include "path/to/file.rs"` from
|
||||
// C++ "magically" works and refers to the API generated from that Rust
|
||||
// source file.
|
||||
this_crate.header_dirs.push(HeaderDir {
|
||||
exported: true,
|
||||
path: include_dir,
|
||||
});
|
||||
|
||||
this_crate.header_dirs.push(HeaderDir {
|
||||
exported: true,
|
||||
path: crate_dir,
|
||||
});
|
||||
|
||||
for exported_dir in &CFG.exported_header_dirs {
|
||||
this_crate.header_dirs.push(HeaderDir {
|
||||
exported: true,
|
||||
path: PathBuf::from(exported_dir),
|
||||
});
|
||||
}
|
||||
|
||||
let mut header_dirs_index = UnorderedMap::new();
|
||||
let mut used_header_links = BTreeSet::new();
|
||||
let mut used_header_prefixes = BTreeSet::new();
|
||||
for krate in deps::direct_dependencies() {
|
||||
let mut is_link_exported = || match &krate.links {
|
||||
None => false,
|
||||
Some(links_attribute) => CFG.exported_header_links.iter().any(|&exported| {
|
||||
let matches = links_attribute == exported;
|
||||
if matches {
|
||||
used_header_links.insert(exported);
|
||||
}
|
||||
matches
|
||||
}),
|
||||
};
|
||||
|
||||
let mut is_prefix_exported = || match &krate.include_prefix {
|
||||
None => false,
|
||||
Some(include_prefix) => CFG.exported_header_prefixes.iter().any(|&exported| {
|
||||
let matches = include_prefix.starts_with(exported);
|
||||
if matches {
|
||||
used_header_prefixes.insert(exported);
|
||||
}
|
||||
matches
|
||||
}),
|
||||
};
|
||||
|
||||
let exported = is_link_exported() || is_prefix_exported();
|
||||
|
||||
for dir in krate.header_dirs {
|
||||
// Deduplicate dirs reachable via multiple transitive dependencies.
|
||||
match header_dirs_index.entry(dir.path.clone()) {
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(this_crate.header_dirs.len());
|
||||
this_crate.header_dirs.push(HeaderDir {
|
||||
exported,
|
||||
path: dir.path,
|
||||
});
|
||||
}
|
||||
Entry::Occupied(entry) => {
|
||||
let index = *entry.get();
|
||||
this_crate.header_dirs[index].exported |= exported;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(unused) = CFG
|
||||
.exported_header_links
|
||||
.iter()
|
||||
.find(|&exported| !used_header_links.contains(exported))
|
||||
{
|
||||
return Err(Error::UnusedExportedLinks(unused));
|
||||
}
|
||||
|
||||
if let Some(unused) = CFG
|
||||
.exported_header_prefixes
|
||||
.iter()
|
||||
.find(|&exported| !used_header_prefixes.contains(exported))
|
||||
{
|
||||
return Err(Error::UnusedExportedPrefix(unused));
|
||||
}
|
||||
|
||||
Ok(this_crate)
|
||||
}
|
||||
|
||||
fn make_crate_dir(prj: &Project) -> PathBuf {
|
||||
if prj.include_prefix.as_os_str().is_empty() {
|
||||
return prj.manifest_dir.clone();
|
||||
}
|
||||
let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
|
||||
let ref link = crate_dir.join(&prj.include_prefix);
|
||||
let ref manifest_dir = prj.manifest_dir;
|
||||
if out::symlink_dir(manifest_dir, link).is_err() && cfg!(not(unix)) {
|
||||
let cachedir_tag = "\
|
||||
Signature: 8a477f597d28d172789f06886806bc55\n\
|
||||
# This file is a cache directory tag created by cxx.\n\
|
||||
# For information about cache directory tags see https://bford.info/cachedir/\n";
|
||||
let _ = out::write(crate_dir.join("CACHEDIR.TAG"), cachedir_tag.as_bytes());
|
||||
let max_depth = 6;
|
||||
best_effort_copy_headers(manifest_dir, link, max_depth);
|
||||
}
|
||||
crate_dir
|
||||
}
|
||||
|
||||
fn make_include_dir(prj: &Project) -> Result<PathBuf> {
|
||||
let include_dir = prj.out_dir.join("cxxbridge").join("include");
|
||||
let cxx_h = include_dir.join("rust").join("cxx.h");
|
||||
let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
|
||||
if let Some(ref original) = env::var_os("DEP_CXXBRIDGE1_HEADER") {
|
||||
out::symlink_file(original, cxx_h)?;
|
||||
out::symlink_file(original, shared_cxx_h)?;
|
||||
} else {
|
||||
out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
|
||||
out::symlink_file(shared_cxx_h, cxx_h)?;
|
||||
}
|
||||
Ok(include_dir)
|
||||
}
|
||||
|
||||
fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
|
||||
let opt = Opt {
|
||||
allow_dot_includes: false,
|
||||
cfg_evaluator: Box::new(CargoEnvCfgEvaluator),
|
||||
doxygen: CFG.doxygen,
|
||||
..Opt::default()
|
||||
};
|
||||
let generated = gen::generate_from_path(rust_source_file, &opt);
|
||||
let ref rel_path = paths::local_relative_path(rust_source_file);
|
||||
|
||||
let cxxbridge = prj.out_dir.join("cxxbridge");
|
||||
let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
|
||||
let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);
|
||||
|
||||
let ref rel_path_h = rel_path.with_appended_extension(".h");
|
||||
let ref header_path = include_dir.join(rel_path_h);
|
||||
out::write(header_path, &generated.header)?;
|
||||
|
||||
let ref link_path = include_dir.join(rel_path);
|
||||
let _ = out::symlink_file(header_path, link_path);
|
||||
|
||||
let ref rel_path_cc = rel_path.with_appended_extension(".cc");
|
||||
let ref implementation_path = sources_dir.join(rel_path_cc);
|
||||
out::write(implementation_path, &generated.implementation)?;
|
||||
build.file(implementation_path);
|
||||
|
||||
let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
|
||||
let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
|
||||
let _ = out::symlink_file(header_path, shared_h);
|
||||
let _ = out::symlink_file(implementation_path, shared_cc);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn best_effort_copy_headers(src: &Path, dst: &Path, max_depth: usize) {
|
||||
// Not using crate::gen::fs because we aren't reporting the errors.
|
||||
use std::fs;
|
||||
|
||||
let mut dst_created = false;
|
||||
let mut entries = match fs::read_dir(src) {
|
||||
Ok(entries) => entries,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
while let Some(Ok(entry)) = entries.next() {
|
||||
let file_name = entry.file_name();
|
||||
if file_name.to_string_lossy().starts_with('.') {
|
||||
continue;
|
||||
}
|
||||
match entry.file_type() {
|
||||
Ok(file_type) if file_type.is_dir() && max_depth > 0 => {
|
||||
let src = entry.path();
|
||||
if src.join("Cargo.toml").exists() || src.join("CACHEDIR.TAG").exists() {
|
||||
continue;
|
||||
}
|
||||
let dst = dst.join(file_name);
|
||||
best_effort_copy_headers(&src, &dst, max_depth - 1);
|
||||
}
|
||||
Ok(file_type) if file_type.is_file() => {
|
||||
let src = entry.path();
|
||||
match src.extension().and_then(OsStr::to_str) {
|
||||
Some("h") | Some("hh") | Some("hpp") => {}
|
||||
_ => continue,
|
||||
}
|
||||
if !dst_created && fs::create_dir_all(dst).is_err() {
|
||||
return;
|
||||
}
|
||||
dst_created = true;
|
||||
let dst = dst.join(file_name);
|
||||
let _ = fs::remove_file(&dst);
|
||||
let _ = fs::copy(src, dst);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
|
||||
let key = key.as_ref();
|
||||
env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
|
||||
}
|
||||
119
vendor/cxx-build/src/out.rs
vendored
Normal file
119
vendor/cxx-build/src/out.rs
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
use crate::error::{Error, Result};
|
||||
use crate::gen::fs;
|
||||
use crate::paths;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) fn write(path: impl AsRef<Path>, content: &[u8]) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
|
||||
let mut create_dir_error = None;
|
||||
if fs::exists(path) {
|
||||
if let Ok(existing) = fs::read(path) {
|
||||
if existing == content {
|
||||
// Avoid bumping modified time with unchanged contents.
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
best_effort_remove(path);
|
||||
} else {
|
||||
let parent = path.parent().unwrap();
|
||||
create_dir_error = fs::create_dir_all(parent).err();
|
||||
}
|
||||
|
||||
match fs::write(path, content) {
|
||||
// As long as write succeeded, ignore any create_dir_all error.
|
||||
Ok(()) => Ok(()),
|
||||
// If create_dir_all and write both failed, prefer the first error.
|
||||
Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn symlink_file(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
|
||||
let original = original.as_ref();
|
||||
let link = link.as_ref();
|
||||
|
||||
let mut create_dir_error = None;
|
||||
if fs::exists(link) {
|
||||
best_effort_remove(link);
|
||||
} else {
|
||||
let parent = link.parent().unwrap();
|
||||
create_dir_error = fs::create_dir_all(parent).err();
|
||||
}
|
||||
|
||||
match paths::symlink_or_copy(original, link) {
|
||||
// As long as symlink_or_copy succeeded, ignore any create_dir_all error.
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) => {
|
||||
if err.kind() == io::ErrorKind::AlreadyExists {
|
||||
// This is fine, a different simultaneous build script already
|
||||
// created the same link or copy. The cxx_build target directory
|
||||
// is laid out such that the same path never refers to two
|
||||
// different targets during the same multi-crate build, so if
|
||||
// some other build script already created the same path then we
|
||||
// know it refers to the identical target that the current build
|
||||
// script was trying to create.
|
||||
Ok(())
|
||||
} else {
|
||||
// If create_dir_all and symlink_or_copy both failed, prefer the
|
||||
// first error.
|
||||
Err(Error::Fs(create_dir_error.unwrap_or(err)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn symlink_dir(original: impl AsRef<Path>, link: impl AsRef<Path>) -> Result<()> {
|
||||
let original = original.as_ref();
|
||||
let link = link.as_ref();
|
||||
|
||||
let mut create_dir_error = None;
|
||||
if fs::exists(link) {
|
||||
best_effort_remove(link);
|
||||
} else {
|
||||
let parent = link.parent().unwrap();
|
||||
create_dir_error = fs::create_dir_all(parent).err();
|
||||
}
|
||||
|
||||
match fs::symlink_dir(original, link) {
|
||||
// As long as symlink_dir succeeded, ignore any create_dir_all error.
|
||||
Ok(()) => Ok(()),
|
||||
// If create_dir_all and symlink_dir both failed, prefer the first error.
|
||||
Err(err) => Err(Error::Fs(create_dir_error.unwrap_or(err))),
|
||||
}
|
||||
}
|
||||
|
||||
fn best_effort_remove(path: &Path) {
|
||||
use std::fs;
|
||||
|
||||
if cfg!(windows) {
|
||||
// On Windows, the correct choice of remove_file vs remove_dir needs to
|
||||
// be used according to what the symlink *points to*. Trying to use
|
||||
// remove_file to remove a symlink which points to a directory fails
|
||||
// with "Access is denied".
|
||||
if let Ok(metadata) = fs::metadata(path) {
|
||||
if metadata.is_dir() {
|
||||
let _ = fs::remove_dir_all(path);
|
||||
} else {
|
||||
let _ = fs::remove_file(path);
|
||||
}
|
||||
} else if fs::symlink_metadata(path).is_ok() {
|
||||
// The symlink might exist but be dangling, in which case there is
|
||||
// no standard way to determine what "kind" of symlink it is. Try
|
||||
// deleting both ways.
|
||||
if fs::remove_dir_all(path).is_err() {
|
||||
let _ = fs::remove_file(path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// On non-Windows, we check metadata not following symlinks. All
|
||||
// symlinks are removed using remove_file.
|
||||
if let Ok(metadata) = fs::symlink_metadata(path) {
|
||||
if metadata.is_dir() {
|
||||
let _ = fs::remove_dir_all(path);
|
||||
} else {
|
||||
let _ = fs::remove_file(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
67
vendor/cxx-build/src/paths.rs
vendored
Normal file
67
vendor/cxx-build/src/paths.rs
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use crate::error::Result;
|
||||
use crate::gen::fs;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
pub(crate) fn manifest_dir() -> Result<PathBuf> {
|
||||
crate::env_os("CARGO_MANIFEST_DIR").map(PathBuf::from)
|
||||
}
|
||||
|
||||
pub(crate) fn out_dir() -> Result<PathBuf> {
|
||||
crate::env_os("OUT_DIR").map(PathBuf::from)
|
||||
}
|
||||
|
||||
// Given a path provided by the user, determines where generated files related
|
||||
// to that path should go in our out dir. In particular we don't want to
|
||||
// accidentally write generated code upward of our out dir, even if the user
|
||||
// passed a path containing lots of `..` or an absolute path.
|
||||
pub(crate) fn local_relative_path(path: &Path) -> PathBuf {
|
||||
let mut rel_path = PathBuf::new();
|
||||
for component in path.components() {
|
||||
match component {
|
||||
Component::Prefix(_) | Component::RootDir | Component::CurDir => {}
|
||||
Component::ParentDir => drop(rel_path.pop()), // noop if empty
|
||||
Component::Normal(name) => rel_path.push(name),
|
||||
}
|
||||
}
|
||||
rel_path
|
||||
}
|
||||
|
||||
pub(crate) trait PathExt {
|
||||
fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf;
|
||||
}
|
||||
|
||||
impl PathExt for Path {
|
||||
fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf {
|
||||
let mut file_name = self.file_name().unwrap().to_owned();
|
||||
file_name.push(suffix);
|
||||
self.with_file_name(file_name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(crate) use self::fs::symlink_file as symlink_or_copy;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn symlink_or_copy(
|
||||
original: impl AsRef<Path>,
|
||||
link: impl AsRef<Path>,
|
||||
) -> fs::Result<()> {
|
||||
// Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
|
||||
// require Developer Mode. If it fails, fall back to copying the file.
|
||||
let original = original.as_ref();
|
||||
let link = link.as_ref();
|
||||
if fs::symlink_file(original, link).is_err() {
|
||||
fs::copy(original, link)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
pub(crate) fn symlink_or_copy(
|
||||
original: impl AsRef<Path>,
|
||||
copy: impl AsRef<Path>,
|
||||
) -> fs::Result<()> {
|
||||
fs::copy(original, copy)?;
|
||||
Ok(())
|
||||
}
|
||||
103
vendor/cxx-build/src/syntax/atom.rs
vendored
Normal file
103
vendor/cxx-build/src/syntax/atom.rs
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
use crate::syntax::Type;
|
||||
use proc_macro2::Ident;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Atom {
|
||||
Bool,
|
||||
Char, // C char, not Rust char
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
Usize,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
Isize,
|
||||
F32,
|
||||
F64,
|
||||
CxxString,
|
||||
RustString,
|
||||
}
|
||||
|
||||
impl Atom {
|
||||
pub fn from(ident: &Ident) -> Option<Self> {
|
||||
Self::from_str(ident.to_string().as_str())
|
||||
}
|
||||
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
use self::Atom::*;
|
||||
match s {
|
||||
"bool" => Some(Bool),
|
||||
"c_char" => Some(Char),
|
||||
"u8" => Some(U8),
|
||||
"u16" => Some(U16),
|
||||
"u32" => Some(U32),
|
||||
"u64" => Some(U64),
|
||||
"usize" => Some(Usize),
|
||||
"i8" => Some(I8),
|
||||
"i16" => Some(I16),
|
||||
"i32" => Some(I32),
|
||||
"i64" => Some(I64),
|
||||
"isize" => Some(Isize),
|
||||
"f32" => Some(F32),
|
||||
"f64" => Some(F64),
|
||||
"CxxString" => Some(CxxString),
|
||||
"String" => Some(RustString),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Atom {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(self.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Atom {
|
||||
fn as_ref(&self) -> &str {
|
||||
use self::Atom::*;
|
||||
match self {
|
||||
Bool => "bool",
|
||||
Char => "c_char",
|
||||
U8 => "u8",
|
||||
U16 => "u16",
|
||||
U32 => "u32",
|
||||
U64 => "u64",
|
||||
Usize => "usize",
|
||||
I8 => "i8",
|
||||
I16 => "i16",
|
||||
I32 => "i32",
|
||||
I64 => "i64",
|
||||
Isize => "isize",
|
||||
F32 => "f32",
|
||||
F64 => "f64",
|
||||
CxxString => "CxxString",
|
||||
RustString => "String",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Atom> for Type {
|
||||
fn eq(&self, atom: &Atom) -> bool {
|
||||
match self {
|
||||
Type::Ident(ident) => ident.rust == atom,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Atom> for &Ident {
|
||||
fn eq(&self, atom: &Atom) -> bool {
|
||||
*self == atom
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Atom> for &Type {
|
||||
fn eq(&self, atom: &Atom) -> bool {
|
||||
*self == atom
|
||||
}
|
||||
}
|
||||
302
vendor/cxx-build/src/syntax/attrs.rs
vendored
Normal file
302
vendor/cxx-build/src/syntax/attrs.rs
vendored
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
use crate::syntax::cfg::CfgExpr;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::Atom::{self, *};
|
||||
use crate::syntax::{cfg, Derive, Doc, ForeignName};
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use syn::parse::{Nothing, Parse, ParseStream, Parser as _};
|
||||
use syn::{parenthesized, token, Attribute, Error, LitStr, Path, Result, Token};
|
||||
|
||||
// Intended usage:
|
||||
//
|
||||
// let mut doc = Doc::new();
|
||||
// let mut cxx_name = None;
|
||||
// let mut rust_name = None;
|
||||
// /* ... */
|
||||
// let attrs = attrs::parse(
|
||||
// cx,
|
||||
// item.attrs,
|
||||
// attrs::Parser {
|
||||
// doc: Some(&mut doc),
|
||||
// cxx_name: Some(&mut cxx_name),
|
||||
// rust_name: Some(&mut rust_name),
|
||||
// /* ... */
|
||||
// ..Default::default()
|
||||
// },
|
||||
// );
|
||||
//
|
||||
#[derive(Default)]
|
||||
pub struct Parser<'a> {
|
||||
pub cfg: Option<&'a mut CfgExpr>,
|
||||
pub doc: Option<&'a mut Doc>,
|
||||
pub derives: Option<&'a mut Vec<Derive>>,
|
||||
pub repr: Option<&'a mut Option<Atom>>,
|
||||
pub namespace: Option<&'a mut Namespace>,
|
||||
pub cxx_name: Option<&'a mut Option<ForeignName>>,
|
||||
pub rust_name: Option<&'a mut Option<Ident>>,
|
||||
pub variants_from_header: Option<&'a mut Option<Attribute>>,
|
||||
pub ignore_unrecognized: bool,
|
||||
|
||||
// Suppress clippy needless_update lint ("struct update has no effect, all
|
||||
// the fields in the struct have already been specified") when preemptively
|
||||
// writing `..Default::default()`.
|
||||
pub(crate) _more: (),
|
||||
}
|
||||
|
||||
pub fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> OtherAttrs {
|
||||
let mut passthrough_attrs = Vec::new();
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident("doc") {
|
||||
match parse_doc_attribute.parse2(attr.tokens.clone()) {
|
||||
Ok(attr) => {
|
||||
if let Some(doc) = &mut parser.doc {
|
||||
match attr {
|
||||
DocAttribute::Doc(lit) => doc.push(lit),
|
||||
DocAttribute::Hidden => doc.hidden = true,
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("derive") {
|
||||
match attr.parse_args_with(|attr: ParseStream| parse_derive_attribute(cx, attr)) {
|
||||
Ok(attr) => {
|
||||
if let Some(derives) = &mut parser.derives {
|
||||
derives.extend(attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("repr") {
|
||||
match attr.parse_args_with(parse_repr_attribute) {
|
||||
Ok(attr) => {
|
||||
if let Some(repr) = &mut parser.repr {
|
||||
**repr = Some(attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("namespace") {
|
||||
match parse_namespace_attribute.parse2(attr.tokens.clone()) {
|
||||
Ok(attr) => {
|
||||
if let Some(namespace) = &mut parser.namespace {
|
||||
**namespace = attr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("cxx_name") {
|
||||
match parse_cxx_name_attribute.parse2(attr.tokens.clone()) {
|
||||
Ok(attr) => {
|
||||
if let Some(cxx_name) = &mut parser.cxx_name {
|
||||
**cxx_name = Some(attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("rust_name") {
|
||||
match parse_rust_name_attribute.parse2(attr.tokens.clone()) {
|
||||
Ok(attr) => {
|
||||
if let Some(rust_name) = &mut parser.rust_name {
|
||||
**rust_name = Some(attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("cfg") {
|
||||
match cfg::parse_attribute.parse2(attr.tokens.clone()) {
|
||||
Ok(cfg_expr) => {
|
||||
if let Some(cfg) = &mut parser.cfg {
|
||||
cfg.merge(cfg_expr);
|
||||
passthrough_attrs.push(attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
cx.push(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if attr.path.is_ident("variants_from_header")
|
||||
&& cfg!(feature = "experimental-enum-variants-from-header")
|
||||
{
|
||||
if let Err(err) = Nothing::parse.parse2(attr.tokens.clone()) {
|
||||
cx.push(err);
|
||||
}
|
||||
if let Some(variants_from_header) = &mut parser.variants_from_header {
|
||||
**variants_from_header = Some(attr);
|
||||
continue;
|
||||
}
|
||||
} else if attr.path.is_ident("allow")
|
||||
|| attr.path.is_ident("warn")
|
||||
|| attr.path.is_ident("deny")
|
||||
|| attr.path.is_ident("forbid")
|
||||
|| attr.path.is_ident("deprecated")
|
||||
|| attr.path.is_ident("must_use")
|
||||
{
|
||||
// https://doc.rust-lang.org/reference/attributes/diagnostics.html
|
||||
passthrough_attrs.push(attr);
|
||||
continue;
|
||||
} else if attr.path.is_ident("serde") {
|
||||
passthrough_attrs.push(attr);
|
||||
continue;
|
||||
} else if attr.path.segments.len() > 1 {
|
||||
let tool = &attr.path.segments.first().unwrap().ident;
|
||||
if tool == "rustfmt" {
|
||||
// Skip, rustfmt only needs to find it in the pre-expansion source file.
|
||||
continue;
|
||||
} else if tool == "clippy" {
|
||||
passthrough_attrs.push(attr);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if !parser.ignore_unrecognized {
|
||||
cx.error(attr, "unsupported attribute");
|
||||
break;
|
||||
}
|
||||
}
|
||||
OtherAttrs(passthrough_attrs)
|
||||
}
|
||||
|
||||
enum DocAttribute {
|
||||
Doc(LitStr),
|
||||
Hidden,
|
||||
}
|
||||
|
||||
mod kw {
|
||||
syn::custom_keyword!(hidden);
|
||||
}
|
||||
|
||||
fn parse_doc_attribute(input: ParseStream) -> Result<DocAttribute> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(Token![=]) {
|
||||
input.parse::<Token![=]>()?;
|
||||
let lit: LitStr = input.parse()?;
|
||||
Ok(DocAttribute::Doc(lit))
|
||||
} else if lookahead.peek(token::Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
content.parse::<kw::hidden>()?;
|
||||
Ok(DocAttribute::Hidden)
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Derive>> {
|
||||
let paths = input.parse_terminated::<Path, Token![,]>(Path::parse_mod_style)?;
|
||||
|
||||
let mut derives = Vec::new();
|
||||
for path in paths {
|
||||
if let Some(ident) = path.get_ident() {
|
||||
if let Some(derive) = Derive::from(ident) {
|
||||
derives.push(derive);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
cx.error(path, "unsupported derive");
|
||||
}
|
||||
Ok(derives)
|
||||
}
|
||||
|
||||
fn parse_repr_attribute(input: ParseStream) -> Result<Atom> {
|
||||
let begin = input.cursor();
|
||||
let ident: Ident = input.parse()?;
|
||||
if let Some(atom) = Atom::from(&ident) {
|
||||
match atom {
|
||||
U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize if input.is_empty() => {
|
||||
return Ok(atom);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Err(Error::new_spanned(
|
||||
begin.token_stream(),
|
||||
"unrecognized repr",
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_namespace_attribute(input: ParseStream) -> Result<Namespace> {
|
||||
input.parse::<Token![=]>()?;
|
||||
let namespace = input.parse::<Namespace>()?;
|
||||
Ok(namespace)
|
||||
}
|
||||
|
||||
fn parse_cxx_name_attribute(input: ParseStream) -> Result<ForeignName> {
|
||||
input.parse::<Token![=]>()?;
|
||||
if input.peek(LitStr) {
|
||||
let lit: LitStr = input.parse()?;
|
||||
ForeignName::parse(&lit.value(), lit.span())
|
||||
} else {
|
||||
let ident: Ident = input.parse()?;
|
||||
ForeignName::parse(&ident.to_string(), ident.span())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_rust_name_attribute(input: ParseStream) -> Result<Ident> {
|
||||
input.parse::<Token![=]>()?;
|
||||
if input.peek(LitStr) {
|
||||
let lit: LitStr = input.parse()?;
|
||||
lit.parse()
|
||||
} else {
|
||||
input.parse()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OtherAttrs(Vec<Attribute>);
|
||||
|
||||
impl OtherAttrs {
|
||||
pub fn none() -> Self {
|
||||
OtherAttrs(Vec::new())
|
||||
}
|
||||
|
||||
pub fn extend(&mut self, other: Self) {
|
||||
self.0.extend(other.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for OtherAttrs {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
for attr in &self.0 {
|
||||
let Attribute {
|
||||
pound_token,
|
||||
style,
|
||||
bracket_token,
|
||||
path,
|
||||
tokens: attr_tokens,
|
||||
} = attr;
|
||||
pound_token.to_tokens(tokens);
|
||||
let _ = style; // ignore; render outer and inner attrs both as outer
|
||||
bracket_token.surround(tokens, |tokens| {
|
||||
path.to_tokens(tokens);
|
||||
attr_tokens.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
77
vendor/cxx-build/src/syntax/cfg.rs
vendored
Normal file
77
vendor/cxx-build/src/syntax/cfg.rs
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
use proc_macro2::Ident;
|
||||
use std::mem;
|
||||
use syn::parse::{Error, ParseStream, Result};
|
||||
use syn::{parenthesized, token, LitStr, Token};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CfgExpr {
|
||||
Unconditional,
|
||||
Eq(Ident, Option<LitStr>),
|
||||
All(Vec<CfgExpr>),
|
||||
Any(Vec<CfgExpr>),
|
||||
Not(Box<CfgExpr>),
|
||||
}
|
||||
|
||||
impl CfgExpr {
|
||||
pub fn merge(&mut self, expr: CfgExpr) {
|
||||
if let CfgExpr::Unconditional = self {
|
||||
*self = expr;
|
||||
} else if let CfgExpr::All(list) = self {
|
||||
list.push(expr);
|
||||
} else {
|
||||
let prev = mem::replace(self, CfgExpr::Unconditional);
|
||||
*self = CfgExpr::All(vec![prev, expr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_attribute(input: ParseStream) -> Result<CfgExpr> {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
let cfg_expr = content.call(parse_single)?;
|
||||
content.parse::<Option<Token![,]>>()?;
|
||||
Ok(cfg_expr)
|
||||
}
|
||||
|
||||
fn parse_single(input: ParseStream) -> Result<CfgExpr> {
|
||||
let ident: Ident = input.parse()?;
|
||||
let lookahead = input.lookahead1();
|
||||
if input.peek(token::Paren) {
|
||||
let content;
|
||||
parenthesized!(content in input);
|
||||
if ident == "all" {
|
||||
let list = content.call(parse_multiple)?;
|
||||
Ok(CfgExpr::All(list))
|
||||
} else if ident == "any" {
|
||||
let list = content.call(parse_multiple)?;
|
||||
Ok(CfgExpr::Any(list))
|
||||
} else if ident == "not" {
|
||||
let expr = content.call(parse_single)?;
|
||||
content.parse::<Option<Token![,]>>()?;
|
||||
Ok(CfgExpr::Not(Box::new(expr)))
|
||||
} else {
|
||||
Err(Error::new(ident.span(), "unrecognized cfg expression"))
|
||||
}
|
||||
} else if lookahead.peek(Token![=]) {
|
||||
input.parse::<Token![=]>()?;
|
||||
let string: LitStr = input.parse()?;
|
||||
Ok(CfgExpr::Eq(ident, Some(string)))
|
||||
} else if lookahead.peek(Token![,]) || input.is_empty() {
|
||||
Ok(CfgExpr::Eq(ident, None))
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_multiple(input: ParseStream) -> Result<Vec<CfgExpr>> {
|
||||
let mut vec = Vec::new();
|
||||
while !input.is_empty() {
|
||||
let expr = input.call(parse_single)?;
|
||||
vec.push(expr);
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
input.parse::<Token![,]>()?;
|
||||
}
|
||||
Ok(vec)
|
||||
}
|
||||
733
vendor/cxx-build/src/syntax/check.rs
vendored
Normal file
733
vendor/cxx-build/src/syntax/check.rs
vendored
Normal file
|
|
@ -0,0 +1,733 @@
|
|||
use crate::syntax::atom::Atom::{self, *};
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::visit::{self, Visit};
|
||||
use crate::syntax::{
|
||||
error, ident, trivial, Api, Array, Enum, ExternFn, ExternType, Impl, Lang, Lifetimes,
|
||||
NamedType, Ptr, Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, Types,
|
||||
};
|
||||
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::fmt::Display;
|
||||
use syn::{GenericParam, Generics, Lifetime};
|
||||
|
||||
pub(crate) struct Check<'a> {
|
||||
apis: &'a [Api],
|
||||
types: &'a Types<'a>,
|
||||
errors: &'a mut Errors,
|
||||
generator: Generator,
|
||||
}
|
||||
|
||||
pub(crate) enum Generator {
|
||||
// cxx-build crate, cxxbridge cli, cxx-gen.
|
||||
#[allow(dead_code)]
|
||||
Build,
|
||||
// cxxbridge-macro. This is relevant in that the macro output is going to
|
||||
// get fed straight to rustc, so for errors that rustc already contains
|
||||
// logic to catch (probably with a better diagnostic than what the proc
|
||||
// macro API is able to produce), we avoid duplicating them in our own
|
||||
// diagnostics.
|
||||
#[allow(dead_code)]
|
||||
Macro,
|
||||
}
|
||||
|
||||
pub(crate) fn typecheck(cx: &mut Errors, apis: &[Api], types: &Types, generator: Generator) {
|
||||
do_typecheck(&mut Check {
|
||||
apis,
|
||||
types,
|
||||
errors: cx,
|
||||
generator,
|
||||
});
|
||||
}
|
||||
|
||||
fn do_typecheck(cx: &mut Check) {
|
||||
ident::check_all(cx, cx.apis);
|
||||
|
||||
for ty in cx.types {
|
||||
match ty {
|
||||
Type::Ident(ident) => check_type_ident(cx, ident),
|
||||
Type::RustBox(ptr) => check_type_box(cx, ptr),
|
||||
Type::RustVec(ty) => check_type_rust_vec(cx, ty),
|
||||
Type::UniquePtr(ptr) => check_type_unique_ptr(cx, ptr),
|
||||
Type::SharedPtr(ptr) => check_type_shared_ptr(cx, ptr),
|
||||
Type::WeakPtr(ptr) => check_type_weak_ptr(cx, ptr),
|
||||
Type::CxxVector(ptr) => check_type_cxx_vector(cx, ptr),
|
||||
Type::Ref(ty) => check_type_ref(cx, ty),
|
||||
Type::Ptr(ty) => check_type_ptr(cx, ty),
|
||||
Type::Array(array) => check_type_array(cx, array),
|
||||
Type::Fn(ty) => check_type_fn(cx, ty),
|
||||
Type::SliceRef(ty) => check_type_slice_ref(cx, ty),
|
||||
Type::Str(_) | Type::Void(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
for api in cx.apis {
|
||||
match api {
|
||||
Api::Include(_) => {}
|
||||
Api::Struct(strct) => check_api_struct(cx, strct),
|
||||
Api::Enum(enm) => check_api_enum(cx, enm),
|
||||
Api::CxxType(ety) | Api::RustType(ety) => check_api_type(cx, ety),
|
||||
Api::CxxFunction(efn) | Api::RustFunction(efn) => check_api_fn(cx, efn),
|
||||
Api::TypeAlias(alias) => check_api_type_alias(cx, alias),
|
||||
Api::Impl(imp) => check_api_impl(cx, imp),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Check<'_> {
|
||||
pub(crate) fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
|
||||
self.errors.error(sp, msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_type_ident(cx: &mut Check, name: &NamedType) {
|
||||
let ident = &name.rust;
|
||||
if Atom::from(ident).is_none()
|
||||
&& !cx.types.structs.contains_key(ident)
|
||||
&& !cx.types.enums.contains_key(ident)
|
||||
&& !cx.types.cxx.contains(ident)
|
||||
&& !cx.types.rust.contains(ident)
|
||||
{
|
||||
let msg = format!("unsupported type: {}", ident);
|
||||
cx.error(ident, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_type_box(cx: &mut Check, ptr: &Ty1) {
|
||||
if let Type::Ident(ident) = &ptr.inner {
|
||||
if cx.types.cxx.contains(&ident.rust)
|
||||
&& !cx.types.aliases.contains_key(&ident.rust)
|
||||
&& !cx.types.structs.contains_key(&ident.rust)
|
||||
&& !cx.types.enums.contains_key(&ident.rust)
|
||||
{
|
||||
cx.error(ptr, error::BOX_CXX_TYPE.msg);
|
||||
}
|
||||
|
||||
if Atom::from(&ident.rust).is_none() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cx.error(ptr, "unsupported target type of Box");
|
||||
}
|
||||
|
||||
fn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
|
||||
match &ty.inner {
|
||||
Type::Ident(ident) => {
|
||||
if cx.types.cxx.contains(&ident.rust)
|
||||
&& !cx.types.aliases.contains_key(&ident.rust)
|
||||
&& !cx.types.structs.contains_key(&ident.rust)
|
||||
&& !cx.types.enums.contains_key(&ident.rust)
|
||||
{
|
||||
cx.error(ty, "Rust Vec containing C++ type is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
match Atom::from(&ident.rust) {
|
||||
None | Some(Bool) | Some(Char) | Some(U8) | Some(U16) | Some(U32) | Some(U64)
|
||||
| Some(Usize) | Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize)
|
||||
| Some(F32) | Some(F64) | Some(RustString) => return,
|
||||
Some(CxxString) => {}
|
||||
}
|
||||
}
|
||||
Type::Str(_) => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
cx.error(ty, "unsupported element type of Vec");
|
||||
}
|
||||
|
||||
fn check_type_unique_ptr(cx: &mut Check, ptr: &Ty1) {
|
||||
if let Type::Ident(ident) = &ptr.inner {
|
||||
if cx.types.rust.contains(&ident.rust) {
|
||||
cx.error(ptr, "unique_ptr of a Rust type is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
match Atom::from(&ident.rust) {
|
||||
None | Some(CxxString) => return,
|
||||
_ => {}
|
||||
}
|
||||
} else if let Type::CxxVector(_) = &ptr.inner {
|
||||
return;
|
||||
}
|
||||
|
||||
cx.error(ptr, "unsupported unique_ptr target type");
|
||||
}
|
||||
|
||||
fn check_type_shared_ptr(cx: &mut Check, ptr: &Ty1) {
|
||||
if let Type::Ident(ident) = &ptr.inner {
|
||||
if cx.types.rust.contains(&ident.rust) {
|
||||
cx.error(ptr, "shared_ptr of a Rust type is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
match Atom::from(&ident.rust) {
|
||||
None | Some(Bool) | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize)
|
||||
| Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32)
|
||||
| Some(F64) | Some(CxxString) => return,
|
||||
Some(Char) | Some(RustString) => {}
|
||||
}
|
||||
} else if let Type::CxxVector(_) = &ptr.inner {
|
||||
cx.error(ptr, "std::shared_ptr<std::vector> is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
cx.error(ptr, "unsupported shared_ptr target type");
|
||||
}
|
||||
|
||||
fn check_type_weak_ptr(cx: &mut Check, ptr: &Ty1) {
|
||||
if let Type::Ident(ident) = &ptr.inner {
|
||||
if cx.types.rust.contains(&ident.rust) {
|
||||
cx.error(ptr, "weak_ptr of a Rust type is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
match Atom::from(&ident.rust) {
|
||||
None | Some(Bool) | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize)
|
||||
| Some(I8) | Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32)
|
||||
| Some(F64) | Some(CxxString) => return,
|
||||
Some(Char) | Some(RustString) => {}
|
||||
}
|
||||
} else if let Type::CxxVector(_) = &ptr.inner {
|
||||
cx.error(ptr, "std::weak_ptr<std::vector> is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
cx.error(ptr, "unsupported weak_ptr target type");
|
||||
}
|
||||
|
||||
fn check_type_cxx_vector(cx: &mut Check, ptr: &Ty1) {
|
||||
if let Type::Ident(ident) = &ptr.inner {
|
||||
if cx.types.rust.contains(&ident.rust) {
|
||||
cx.error(
|
||||
ptr,
|
||||
"C++ vector containing a Rust type is not supported yet",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
match Atom::from(&ident.rust) {
|
||||
None | Some(U8) | Some(U16) | Some(U32) | Some(U64) | Some(Usize) | Some(I8)
|
||||
| Some(I16) | Some(I32) | Some(I64) | Some(Isize) | Some(F32) | Some(F64)
|
||||
| Some(CxxString) => return,
|
||||
Some(Char) => { /* todo */ }
|
||||
Some(Bool) | Some(RustString) => {}
|
||||
}
|
||||
}
|
||||
|
||||
cx.error(ptr, "unsupported vector element type");
|
||||
}
|
||||
|
||||
fn check_type_ref(cx: &mut Check, ty: &Ref) {
|
||||
if ty.mutable && !ty.pinned {
|
||||
if let Some(requires_pin) = match &ty.inner {
|
||||
Type::Ident(ident) if ident.rust == CxxString || is_opaque_cxx(cx, &ident.rust) => {
|
||||
Some(ident.rust.to_string())
|
||||
}
|
||||
Type::CxxVector(_) => Some("CxxVector<...>".to_owned()),
|
||||
_ => None,
|
||||
} {
|
||||
cx.error(
|
||||
ty,
|
||||
format!(
|
||||
"mutable reference to C++ type requires a pin -- use Pin<&mut {}>",
|
||||
requires_pin,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
match ty.inner {
|
||||
Type::Fn(_) | Type::Void(_) => {}
|
||||
Type::Ref(_) => {
|
||||
cx.error(ty, "C++ does not allow references to references");
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
cx.error(ty, "unsupported reference type");
|
||||
}
|
||||
|
||||
fn check_type_ptr(cx: &mut Check, ty: &Ptr) {
|
||||
match ty.inner {
|
||||
Type::Fn(_) | Type::Void(_) => {}
|
||||
Type::Ref(_) => {
|
||||
cx.error(ty, "C++ does not allow pointer to reference as a type");
|
||||
return;
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
cx.error(ty, "unsupported pointer type");
|
||||
}
|
||||
|
||||
fn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) {
|
||||
let supported = !is_unsized(cx, &ty.inner)
|
||||
|| match &ty.inner {
|
||||
Type::Ident(ident) => {
|
||||
cx.types.rust.contains(&ident.rust) || cx.types.aliases.contains_key(&ident.rust)
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !supported {
|
||||
let mutable = if ty.mutable { "mut " } else { "" };
|
||||
let mut msg = format!("unsupported &{}[T] element type", mutable);
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
if is_opaque_cxx(cx, &ident.rust) {
|
||||
msg += ": opaque C++ type is not supported yet";
|
||||
}
|
||||
}
|
||||
cx.error(ty, msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_type_array(cx: &mut Check, ty: &Array) {
|
||||
let supported = !is_unsized(cx, &ty.inner);
|
||||
|
||||
if !supported {
|
||||
cx.error(ty, "unsupported array element type");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_type_fn(cx: &mut Check, ty: &Signature) {
|
||||
if ty.throws {
|
||||
cx.error(ty, "function pointer returning Result is not supported yet");
|
||||
}
|
||||
|
||||
for arg in &ty.args {
|
||||
if let Type::Ptr(_) = arg.ty {
|
||||
if ty.unsafety.is_none() {
|
||||
cx.error(
|
||||
arg,
|
||||
"pointer argument requires that the function pointer be marked unsafe",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_api_struct(cx: &mut Check, strct: &Struct) {
|
||||
let name = &strct.name;
|
||||
check_reserved_name(cx, &name.rust);
|
||||
check_lifetimes(cx, &strct.generics);
|
||||
|
||||
if strct.fields.is_empty() {
|
||||
let span = span_for_struct_error(strct);
|
||||
cx.error(span, "structs without any fields are not supported");
|
||||
}
|
||||
|
||||
if cx.types.cxx.contains(&name.rust) {
|
||||
if let Some(ety) = cx.types.untrusted.get(&name.rust) {
|
||||
let msg = "extern shared struct must be declared in an `unsafe extern` block";
|
||||
cx.error(ety, msg);
|
||||
}
|
||||
}
|
||||
|
||||
for derive in &strct.derives {
|
||||
if derive.what == Trait::ExternType {
|
||||
let msg = format!("derive({}) on shared struct is not supported", derive);
|
||||
cx.error(derive, msg);
|
||||
}
|
||||
}
|
||||
|
||||
for field in &strct.fields {
|
||||
if let Type::Fn(_) = field.ty {
|
||||
cx.error(
|
||||
field,
|
||||
"function pointers in a struct field are not implemented yet",
|
||||
);
|
||||
} else if is_unsized(cx, &field.ty) {
|
||||
let desc = describe(cx, &field.ty);
|
||||
let msg = format!("using {} by value is not supported", desc);
|
||||
cx.error(field, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_api_enum(cx: &mut Check, enm: &Enum) {
|
||||
check_reserved_name(cx, &enm.name.rust);
|
||||
check_lifetimes(cx, &enm.generics);
|
||||
|
||||
if enm.variants.is_empty() && !enm.explicit_repr && !enm.variants_from_header {
|
||||
let span = span_for_enum_error(enm);
|
||||
cx.error(
|
||||
span,
|
||||
"explicit #[repr(...)] is required for enum without any variants",
|
||||
);
|
||||
}
|
||||
|
||||
for derive in &enm.derives {
|
||||
if derive.what == Trait::Default || derive.what == Trait::ExternType {
|
||||
let msg = format!("derive({}) on shared enum is not supported", derive);
|
||||
cx.error(derive, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_api_type(cx: &mut Check, ety: &ExternType) {
|
||||
check_reserved_name(cx, &ety.name.rust);
|
||||
check_lifetimes(cx, &ety.generics);
|
||||
|
||||
for derive in &ety.derives {
|
||||
if derive.what == Trait::ExternType && ety.lang == Lang::Rust {
|
||||
continue;
|
||||
}
|
||||
let lang = match ety.lang {
|
||||
Lang::Rust => "Rust",
|
||||
Lang::Cxx => "C++",
|
||||
};
|
||||
let msg = format!(
|
||||
"derive({}) on opaque {} type is not supported yet",
|
||||
derive, lang,
|
||||
);
|
||||
cx.error(derive, msg);
|
||||
}
|
||||
|
||||
if !ety.bounds.is_empty() {
|
||||
let bounds = &ety.bounds;
|
||||
let span = quote!(#(#bounds)*);
|
||||
cx.error(span, "extern type bounds are not implemented yet");
|
||||
}
|
||||
|
||||
if let Some(reasons) = cx.types.required_trivial.get(&ety.name.rust) {
|
||||
let msg = format!(
|
||||
"needs a cxx::ExternType impl in order to be used as {}",
|
||||
trivial::as_what(&ety.name, reasons),
|
||||
);
|
||||
cx.error(ety, msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_api_fn(cx: &mut Check, efn: &ExternFn) {
|
||||
match efn.lang {
|
||||
Lang::Cxx => {
|
||||
if !efn.generics.params.is_empty() && !efn.trusted {
|
||||
let ref span = span_for_generics_error(efn);
|
||||
cx.error(span, "extern C++ function with lifetimes must be declared in `unsafe extern \"C++\"` block");
|
||||
}
|
||||
}
|
||||
Lang::Rust => {
|
||||
if !efn.generics.params.is_empty() && efn.unsafety.is_none() {
|
||||
let ref span = span_for_generics_error(efn);
|
||||
let message = format!(
|
||||
"must be `unsafe fn {}` in order to expose explicit lifetimes to C++",
|
||||
efn.name.rust,
|
||||
);
|
||||
cx.error(span, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_generics(cx, &efn.sig.generics);
|
||||
|
||||
if let Some(receiver) = &efn.receiver {
|
||||
let ref span = span_for_receiver_error(receiver);
|
||||
|
||||
if receiver.ty.rust == "Self" {
|
||||
let mutability = match receiver.mutable {
|
||||
true => "mut ",
|
||||
false => "",
|
||||
};
|
||||
let msg = format!(
|
||||
"unnamed receiver type is only allowed if the surrounding extern block contains exactly one extern type; use `self: &{mutability}TheType`",
|
||||
mutability = mutability,
|
||||
);
|
||||
cx.error(span, msg);
|
||||
} else if cx.types.enums.contains_key(&receiver.ty.rust) {
|
||||
cx.error(
|
||||
span,
|
||||
"unsupported receiver type; C++ does not allow member functions on enums",
|
||||
);
|
||||
} else if !cx.types.structs.contains_key(&receiver.ty.rust)
|
||||
&& !cx.types.cxx.contains(&receiver.ty.rust)
|
||||
&& !cx.types.rust.contains(&receiver.ty.rust)
|
||||
{
|
||||
cx.error(span, "unrecognized receiver type");
|
||||
} else if receiver.mutable && !receiver.pinned && is_opaque_cxx(cx, &receiver.ty.rust) {
|
||||
cx.error(
|
||||
span,
|
||||
format!(
|
||||
"mutable reference to opaque C++ type requires a pin -- use `self: Pin<&mut {}>`",
|
||||
receiver.ty.rust,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for arg in &efn.args {
|
||||
if let Type::Fn(_) = arg.ty {
|
||||
if efn.lang == Lang::Rust {
|
||||
cx.error(
|
||||
arg,
|
||||
"passing a function pointer from C++ to Rust is not implemented yet",
|
||||
);
|
||||
}
|
||||
} else if let Type::Ptr(_) = arg.ty {
|
||||
if efn.sig.unsafety.is_none() {
|
||||
cx.error(
|
||||
arg,
|
||||
"pointer argument requires that the function be marked unsafe",
|
||||
);
|
||||
}
|
||||
} else if is_unsized(cx, &arg.ty) {
|
||||
let desc = describe(cx, &arg.ty);
|
||||
let msg = format!("passing {} by value is not supported", desc);
|
||||
cx.error(arg, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ty) = &efn.ret {
|
||||
if let Type::Fn(_) = ty {
|
||||
cx.error(ty, "returning a function pointer is not implemented yet");
|
||||
} else if is_unsized(cx, ty) {
|
||||
let desc = describe(cx, ty);
|
||||
let msg = format!("returning {} by value is not supported", desc);
|
||||
cx.error(ty, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if efn.lang == Lang::Cxx {
|
||||
check_mut_return_restriction(cx, efn);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_api_type_alias(cx: &mut Check, alias: &TypeAlias) {
|
||||
check_lifetimes(cx, &alias.generics);
|
||||
|
||||
for derive in &alias.derives {
|
||||
let msg = format!("derive({}) on extern type alias is not supported", derive);
|
||||
cx.error(derive, msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_api_impl(cx: &mut Check, imp: &Impl) {
|
||||
let ty = &imp.ty;
|
||||
|
||||
check_lifetimes(cx, &imp.impl_generics);
|
||||
|
||||
if let Some(negative) = imp.negative_token {
|
||||
let span = quote!(#negative #ty);
|
||||
cx.error(span, "negative impl is not supported yet");
|
||||
return;
|
||||
}
|
||||
|
||||
match ty {
|
||||
Type::RustBox(ty)
|
||||
| Type::RustVec(ty)
|
||||
| Type::UniquePtr(ty)
|
||||
| Type::SharedPtr(ty)
|
||||
| Type::WeakPtr(ty)
|
||||
| Type::CxxVector(ty) => {
|
||||
if let Type::Ident(inner) = &ty.inner {
|
||||
if Atom::from(&inner.rust).is_none() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
cx.error(imp, "unsupported Self type of explicit impl");
|
||||
}
|
||||
|
||||
fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
|
||||
if efn.sig.unsafety.is_some() {
|
||||
// Unrestricted as long as the function is made unsafe-to-call.
|
||||
return;
|
||||
}
|
||||
|
||||
match &efn.ret {
|
||||
Some(Type::Ref(ty)) if ty.mutable => {}
|
||||
Some(Type::SliceRef(slice)) if slice.mutable => {}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
if let Some(receiver) = &efn.receiver {
|
||||
if receiver.mutable {
|
||||
return;
|
||||
}
|
||||
let resolve = match cx.types.try_resolve(&receiver.ty) {
|
||||
Some(resolve) => resolve,
|
||||
None => return,
|
||||
};
|
||||
if !resolve.generics.lifetimes.is_empty() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct FindLifetimeMut<'a> {
|
||||
cx: &'a Check<'a>,
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'t, 'a> Visit<'t> for FindLifetimeMut<'a> {
|
||||
fn visit_type(&mut self, ty: &'t Type) {
|
||||
self.found |= match ty {
|
||||
Type::Ref(ty) => ty.mutable,
|
||||
Type::SliceRef(slice) => slice.mutable,
|
||||
Type::Ident(ident) if Atom::from(&ident.rust).is_none() => {
|
||||
match self.cx.types.try_resolve(ident) {
|
||||
Some(resolve) => !resolve.generics.lifetimes.is_empty(),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
visit::visit_type(self, ty);
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = FindLifetimeMut { cx, found: false };
|
||||
|
||||
for arg in &efn.args {
|
||||
visitor.visit_type(&arg.ty);
|
||||
}
|
||||
|
||||
if visitor.found {
|
||||
return;
|
||||
}
|
||||
|
||||
cx.error(
|
||||
efn,
|
||||
"&mut return type is not allowed unless there is a &mut argument",
|
||||
);
|
||||
}
|
||||
|
||||
fn check_reserved_name(cx: &mut Check, ident: &Ident) {
|
||||
if ident == "Box"
|
||||
|| ident == "UniquePtr"
|
||||
|| ident == "SharedPtr"
|
||||
|| ident == "WeakPtr"
|
||||
|| ident == "Vec"
|
||||
|| ident == "CxxVector"
|
||||
|| ident == "str"
|
||||
|| Atom::from(ident).is_some()
|
||||
{
|
||||
cx.error(ident, "reserved name");
|
||||
}
|
||||
}
|
||||
|
||||
fn check_reserved_lifetime(cx: &mut Check, lifetime: &Lifetime) {
|
||||
if lifetime.ident == "static" {
|
||||
match cx.generator {
|
||||
Generator::Macro => { /* rustc already reports this */ }
|
||||
Generator::Build => {
|
||||
cx.error(lifetime, error::RESERVED_LIFETIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lifetimes(cx: &mut Check, generics: &Lifetimes) {
|
||||
for lifetime in &generics.lifetimes {
|
||||
check_reserved_lifetime(cx, lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_generics(cx: &mut Check, generics: &Generics) {
|
||||
for generic_param in &generics.params {
|
||||
if let GenericParam::Lifetime(def) = generic_param {
|
||||
check_reserved_lifetime(cx, &def.lifetime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
|
||||
match ty {
|
||||
Type::Ident(ident) => {
|
||||
let ident = &ident.rust;
|
||||
ident == CxxString || is_opaque_cxx(cx, ident) || cx.types.rust.contains(ident)
|
||||
}
|
||||
Type::Array(array) => is_unsized(cx, &array.inner),
|
||||
Type::CxxVector(_) | Type::Fn(_) | Type::Void(_) => true,
|
||||
Type::RustBox(_)
|
||||
| Type::RustVec(_)
|
||||
| Type::UniquePtr(_)
|
||||
| Type::SharedPtr(_)
|
||||
| Type::WeakPtr(_)
|
||||
| Type::Ref(_)
|
||||
| Type::Ptr(_)
|
||||
| Type::Str(_)
|
||||
| Type::SliceRef(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_opaque_cxx(cx: &mut Check, ty: &Ident) -> bool {
|
||||
cx.types.cxx.contains(ty)
|
||||
&& !cx.types.structs.contains_key(ty)
|
||||
&& !cx.types.enums.contains_key(ty)
|
||||
&& !(cx.types.aliases.contains_key(ty) && cx.types.required_trivial.contains_key(ty))
|
||||
}
|
||||
|
||||
fn span_for_struct_error(strct: &Struct) -> TokenStream {
|
||||
let struct_token = strct.struct_token;
|
||||
let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
|
||||
brace_token.set_span(strct.brace_token.span);
|
||||
quote!(#struct_token #brace_token)
|
||||
}
|
||||
|
||||
fn span_for_enum_error(enm: &Enum) -> TokenStream {
|
||||
let enum_token = enm.enum_token;
|
||||
let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
|
||||
brace_token.set_span(enm.brace_token.span);
|
||||
quote!(#enum_token #brace_token)
|
||||
}
|
||||
|
||||
fn span_for_receiver_error(receiver: &Receiver) -> TokenStream {
|
||||
let ampersand = receiver.ampersand;
|
||||
let lifetime = &receiver.lifetime;
|
||||
let mutability = receiver.mutability;
|
||||
if receiver.shorthand {
|
||||
let var = receiver.var;
|
||||
quote!(#ampersand #lifetime #mutability #var)
|
||||
} else {
|
||||
let ty = &receiver.ty;
|
||||
quote!(#ampersand #lifetime #mutability #ty)
|
||||
}
|
||||
}
|
||||
|
||||
fn span_for_generics_error(efn: &ExternFn) -> TokenStream {
|
||||
let unsafety = efn.unsafety;
|
||||
let fn_token = efn.fn_token;
|
||||
let generics = &efn.generics;
|
||||
quote!(#unsafety #fn_token #generics)
|
||||
}
|
||||
|
||||
fn describe(cx: &mut Check, ty: &Type) -> String {
|
||||
match ty {
|
||||
Type::Ident(ident) => {
|
||||
if cx.types.structs.contains_key(&ident.rust) {
|
||||
"struct".to_owned()
|
||||
} else if cx.types.enums.contains_key(&ident.rust) {
|
||||
"enum".to_owned()
|
||||
} else if cx.types.aliases.contains_key(&ident.rust) {
|
||||
"C++ type".to_owned()
|
||||
} else if cx.types.cxx.contains(&ident.rust) {
|
||||
"opaque C++ type".to_owned()
|
||||
} else if cx.types.rust.contains(&ident.rust) {
|
||||
"opaque Rust type".to_owned()
|
||||
} else if Atom::from(&ident.rust) == Some(CxxString) {
|
||||
"C++ string".to_owned()
|
||||
} else if Atom::from(&ident.rust) == Some(Char) {
|
||||
"C char".to_owned()
|
||||
} else {
|
||||
ident.rust.to_string()
|
||||
}
|
||||
}
|
||||
Type::RustBox(_) => "Box".to_owned(),
|
||||
Type::RustVec(_) => "Vec".to_owned(),
|
||||
Type::UniquePtr(_) => "unique_ptr".to_owned(),
|
||||
Type::SharedPtr(_) => "shared_ptr".to_owned(),
|
||||
Type::WeakPtr(_) => "weak_ptr".to_owned(),
|
||||
Type::Ref(_) => "reference".to_owned(),
|
||||
Type::Ptr(_) => "raw pointer".to_owned(),
|
||||
Type::Str(_) => "&str".to_owned(),
|
||||
Type::CxxVector(_) => "C++ vector".to_owned(),
|
||||
Type::SliceRef(_) => "slice".to_owned(),
|
||||
Type::Fn(_) => "function pointer".to_owned(),
|
||||
Type::Void(_) => "()".to_owned(),
|
||||
Type::Array(_) => "array".to_owned(),
|
||||
}
|
||||
}
|
||||
81
vendor/cxx-build/src/syntax/derive.rs
vendored
Normal file
81
vendor/cxx-build/src/syntax/derive.rs
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use proc_macro2::{Ident, Span};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Derive {
|
||||
pub what: Trait,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Trait {
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Eq,
|
||||
ExternType,
|
||||
Hash,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
}
|
||||
|
||||
impl Derive {
|
||||
pub fn from(ident: &Ident) -> Option<Self> {
|
||||
let what = match ident.to_string().as_str() {
|
||||
"Clone" => Trait::Clone,
|
||||
"Copy" => Trait::Copy,
|
||||
"Debug" => Trait::Debug,
|
||||
"Default" => Trait::Default,
|
||||
"Eq" => Trait::Eq,
|
||||
"ExternType" => Trait::ExternType,
|
||||
"Hash" => Trait::Hash,
|
||||
"Ord" => Trait::Ord,
|
||||
"PartialEq" => Trait::PartialEq,
|
||||
"PartialOrd" => Trait::PartialOrd,
|
||||
"Serialize" => Trait::Serialize,
|
||||
"Deserialize" => Trait::Deserialize,
|
||||
_ => return None,
|
||||
};
|
||||
let span = ident.span();
|
||||
Some(Derive { what, span })
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Trait> for Derive {
|
||||
fn eq(&self, other: &Trait) -> bool {
|
||||
self.what == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Trait {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
Trait::Clone => "Clone",
|
||||
Trait::Copy => "Copy",
|
||||
Trait::Debug => "Debug",
|
||||
Trait::Default => "Default",
|
||||
Trait::Eq => "Eq",
|
||||
Trait::ExternType => "ExternType",
|
||||
Trait::Hash => "Hash",
|
||||
Trait::Ord => "Ord",
|
||||
Trait::PartialEq => "PartialEq",
|
||||
Trait::PartialOrd => "PartialOrd",
|
||||
Trait::Serialize => "Serialize",
|
||||
Trait::Deserialize => "Deserialize",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Derive {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(self.what.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(derives: &[Derive], query: Trait) -> bool {
|
||||
derives.iter().any(|derive| derive.what == query)
|
||||
}
|
||||
336
vendor/cxx-build/src/syntax/discriminant.rs
vendored
Normal file
336
vendor/cxx-build/src/syntax/discriminant.rs
vendored
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
use crate::syntax::Atom::{self, *};
|
||||
use proc_macro2::{Literal, Span, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::{self, Display};
|
||||
use std::str::FromStr;
|
||||
use std::u64;
|
||||
use syn::{Error, Expr, Lit, Result, Token, UnOp};
|
||||
|
||||
pub struct DiscriminantSet {
|
||||
repr: Option<Atom>,
|
||||
values: BTreeSet<Discriminant>,
|
||||
previous: Option<Discriminant>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Discriminant {
|
||||
sign: Sign,
|
||||
magnitude: u64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
enum Sign {
|
||||
Negative,
|
||||
Positive,
|
||||
}
|
||||
|
||||
impl DiscriminantSet {
|
||||
pub fn new(repr: Option<Atom>) -> Self {
|
||||
DiscriminantSet {
|
||||
repr,
|
||||
values: BTreeSet::new(),
|
||||
previous: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, expr: &Expr) -> Result<Discriminant> {
|
||||
let (discriminant, repr) = expr_to_discriminant(expr)?;
|
||||
match (self.repr, repr) {
|
||||
(None, Some(new_repr)) => {
|
||||
if let Some(limits) = Limits::of(new_repr) {
|
||||
for &past in &self.values {
|
||||
if limits.min <= past && past <= limits.max {
|
||||
continue;
|
||||
}
|
||||
let msg = format!(
|
||||
"discriminant value `{}` is outside the limits of {}",
|
||||
past, new_repr,
|
||||
);
|
||||
return Err(Error::new(Span::call_site(), msg));
|
||||
}
|
||||
}
|
||||
self.repr = Some(new_repr);
|
||||
}
|
||||
(Some(prev), Some(repr)) if prev != repr => {
|
||||
let msg = format!("expected {}, found {}", prev, repr);
|
||||
return Err(Error::new(Span::call_site(), msg));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
insert(self, discriminant)
|
||||
}
|
||||
|
||||
pub fn insert_next(&mut self) -> Result<Discriminant> {
|
||||
let discriminant = match self.previous {
|
||||
None => Discriminant::zero(),
|
||||
Some(mut discriminant) => match discriminant.sign {
|
||||
Sign::Negative => {
|
||||
discriminant.magnitude -= 1;
|
||||
if discriminant.magnitude == 0 {
|
||||
discriminant.sign = Sign::Positive;
|
||||
}
|
||||
discriminant
|
||||
}
|
||||
Sign::Positive => {
|
||||
if discriminant.magnitude == u64::MAX {
|
||||
let msg = format!("discriminant overflow on value after {}", u64::MAX);
|
||||
return Err(Error::new(Span::call_site(), msg));
|
||||
}
|
||||
discriminant.magnitude += 1;
|
||||
discriminant
|
||||
}
|
||||
},
|
||||
};
|
||||
insert(self, discriminant)
|
||||
}
|
||||
|
||||
pub fn inferred_repr(&self) -> Result<Atom> {
|
||||
if let Some(repr) = self.repr {
|
||||
return Ok(repr);
|
||||
}
|
||||
if self.values.is_empty() {
|
||||
return Ok(U8);
|
||||
}
|
||||
let min = *self.values.iter().next().unwrap();
|
||||
let max = *self.values.iter().next_back().unwrap();
|
||||
for limits in &LIMITS {
|
||||
if limits.min <= min && max <= limits.max {
|
||||
return Ok(limits.repr);
|
||||
}
|
||||
}
|
||||
let msg = "these discriminant values do not fit in any supported enum repr type";
|
||||
Err(Error::new(Span::call_site(), msg))
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_to_discriminant(expr: &Expr) -> Result<(Discriminant, Option<Atom>)> {
|
||||
match expr {
|
||||
Expr::Lit(expr) => {
|
||||
if let Lit::Int(lit) = &expr.lit {
|
||||
let discriminant = lit.base10_parse::<Discriminant>()?;
|
||||
let repr = parse_int_suffix(lit.suffix())?;
|
||||
return Ok((discriminant, repr));
|
||||
}
|
||||
}
|
||||
Expr::Unary(unary) => {
|
||||
if let UnOp::Neg(_) = unary.op {
|
||||
let (mut discriminant, repr) = expr_to_discriminant(&unary.expr)?;
|
||||
discriminant.sign = match discriminant.sign {
|
||||
Sign::Positive => Sign::Negative,
|
||||
Sign::Negative => Sign::Positive,
|
||||
};
|
||||
return Ok((discriminant, repr));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Err(Error::new_spanned(
|
||||
expr,
|
||||
"enums with non-integer literal discriminants are not supported yet",
|
||||
))
|
||||
}
|
||||
|
||||
fn insert(set: &mut DiscriminantSet, discriminant: Discriminant) -> Result<Discriminant> {
|
||||
if let Some(expected_repr) = set.repr {
|
||||
if let Some(limits) = Limits::of(expected_repr) {
|
||||
if discriminant < limits.min || limits.max < discriminant {
|
||||
let msg = format!(
|
||||
"discriminant value `{}` is outside the limits of {}",
|
||||
discriminant, expected_repr,
|
||||
);
|
||||
return Err(Error::new(Span::call_site(), msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
set.values.insert(discriminant);
|
||||
set.previous = Some(discriminant);
|
||||
Ok(discriminant)
|
||||
}
|
||||
|
||||
impl Discriminant {
|
||||
pub const fn zero() -> Self {
|
||||
Discriminant {
|
||||
sign: Sign::Positive,
|
||||
magnitude: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const fn pos(u: u64) -> Self {
|
||||
Discriminant {
|
||||
sign: Sign::Positive,
|
||||
magnitude: u,
|
||||
}
|
||||
}
|
||||
|
||||
const fn neg(i: i64) -> Self {
|
||||
Discriminant {
|
||||
sign: if i < 0 {
|
||||
Sign::Negative
|
||||
} else {
|
||||
Sign::Positive
|
||||
},
|
||||
// This is `i.abs() as u64` but without overflow on MIN. Uses the
|
||||
// fact that MIN.wrapping_abs() wraps back to MIN whose binary
|
||||
// representation is 1<<63, and thus the `as u64` conversion
|
||||
// produces 1<<63 too which happens to be the correct unsigned
|
||||
// magnitude.
|
||||
magnitude: i.wrapping_abs() as u64,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental-enum-variants-from-header")]
|
||||
pub const fn checked_succ(self) -> Option<Self> {
|
||||
match self.sign {
|
||||
Sign::Negative => {
|
||||
if self.magnitude == 1 {
|
||||
Some(Discriminant::zero())
|
||||
} else {
|
||||
Some(Discriminant {
|
||||
sign: Sign::Negative,
|
||||
magnitude: self.magnitude - 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
Sign::Positive => match self.magnitude.checked_add(1) {
|
||||
Some(magnitude) => Some(Discriminant {
|
||||
sign: Sign::Positive,
|
||||
magnitude,
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Discriminant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.sign == Sign::Negative {
|
||||
f.write_str("-")?;
|
||||
}
|
||||
write!(f, "{}", self.magnitude)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Discriminant {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
if self.sign == Sign::Negative {
|
||||
Token).to_tokens(tokens);
|
||||
}
|
||||
Literal::u64_unsuffixed(self.magnitude).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Discriminant {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(mut s: &str) -> Result<Self> {
|
||||
let sign = if s.starts_with('-') {
|
||||
s = &s[1..];
|
||||
Sign::Negative
|
||||
} else {
|
||||
Sign::Positive
|
||||
};
|
||||
match s.parse::<u64>() {
|
||||
Ok(magnitude) => Ok(Discriminant { sign, magnitude }),
|
||||
Err(_) => Err(Error::new(
|
||||
Span::call_site(),
|
||||
"discriminant value outside of supported range",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Discriminant {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
use self::Sign::{Negative, Positive};
|
||||
match (self.sign, other.sign) {
|
||||
(Negative, Negative) => self.magnitude.cmp(&other.magnitude).reverse(),
|
||||
(Negative, Positive) => Ordering::Less, // negative < positive
|
||||
(Positive, Negative) => Ordering::Greater, // positive > negative
|
||||
(Positive, Positive) => self.magnitude.cmp(&other.magnitude),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Discriminant {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_int_suffix(suffix: &str) -> Result<Option<Atom>> {
|
||||
if suffix.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
if let Some(atom) = Atom::from_str(suffix) {
|
||||
match atom {
|
||||
U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64 | Isize => return Ok(Some(atom)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let msg = format!("unrecognized integer suffix: `{}`", suffix);
|
||||
Err(Error::new(Span::call_site(), msg))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Limits {
|
||||
repr: Atom,
|
||||
min: Discriminant,
|
||||
max: Discriminant,
|
||||
}
|
||||
|
||||
impl Limits {
|
||||
fn of(repr: Atom) -> Option<Limits> {
|
||||
for limits in &LIMITS {
|
||||
if limits.repr == repr {
|
||||
return Some(*limits);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const LIMITS: [Limits; 8] = [
|
||||
Limits {
|
||||
repr: U8,
|
||||
min: Discriminant::zero(),
|
||||
max: Discriminant::pos(std::u8::MAX as u64),
|
||||
},
|
||||
Limits {
|
||||
repr: I8,
|
||||
min: Discriminant::neg(std::i8::MIN as i64),
|
||||
max: Discriminant::pos(std::i8::MAX as u64),
|
||||
},
|
||||
Limits {
|
||||
repr: U16,
|
||||
min: Discriminant::zero(),
|
||||
max: Discriminant::pos(std::u16::MAX as u64),
|
||||
},
|
||||
Limits {
|
||||
repr: I16,
|
||||
min: Discriminant::neg(std::i16::MIN as i64),
|
||||
max: Discriminant::pos(std::i16::MAX as u64),
|
||||
},
|
||||
Limits {
|
||||
repr: U32,
|
||||
min: Discriminant::zero(),
|
||||
max: Discriminant::pos(std::u32::MAX as u64),
|
||||
},
|
||||
Limits {
|
||||
repr: I32,
|
||||
min: Discriminant::neg(std::i32::MIN as i64),
|
||||
max: Discriminant::pos(std::i32::MAX as u64),
|
||||
},
|
||||
Limits {
|
||||
repr: U64,
|
||||
min: Discriminant::zero(),
|
||||
max: Discriminant::pos(std::u64::MAX),
|
||||
},
|
||||
Limits {
|
||||
repr: I64,
|
||||
min: Discriminant::neg(std::i64::MIN),
|
||||
max: Discriminant::pos(std::i64::MAX as u64),
|
||||
},
|
||||
];
|
||||
46
vendor/cxx-build/src/syntax/doc.rs
vendored
Normal file
46
vendor/cxx-build/src/syntax/doc.rs
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::LitStr;
|
||||
|
||||
pub struct Doc {
|
||||
pub(crate) hidden: bool,
|
||||
fragments: Vec<LitStr>,
|
||||
}
|
||||
|
||||
impl Doc {
|
||||
pub fn new() -> Self {
|
||||
Doc {
|
||||
hidden: false,
|
||||
fragments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, lit: LitStr) {
|
||||
self.fragments.push(lit);
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // only used by cxx-build, not cxxbridge-macro
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.fragments.is_empty()
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // only used by cxx-build, not cxxbridge-macro
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut doc = String::new();
|
||||
for lit in &self.fragments {
|
||||
doc += &lit.value();
|
||||
doc.push('\n');
|
||||
}
|
||||
doc
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Doc {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let fragments = &self.fragments;
|
||||
tokens.extend(quote! { #(#[doc = #fragments])* });
|
||||
if self.hidden {
|
||||
tokens.extend(quote! { #[doc(hidden)] });
|
||||
}
|
||||
}
|
||||
}
|
||||
98
vendor/cxx-build/src/syntax/error.rs
vendored
Normal file
98
vendor/cxx-build/src/syntax/error.rs
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Error {
|
||||
pub msg: &'static str,
|
||||
pub label: Option<&'static str>,
|
||||
pub note: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.msg.fmt(formatter)
|
||||
}
|
||||
}
|
||||
|
||||
pub static ERRORS: &[Error] = &[
|
||||
BOX_CXX_TYPE,
|
||||
CXXBRIDGE_RESERVED,
|
||||
CXX_STRING_BY_VALUE,
|
||||
CXX_TYPE_BY_VALUE,
|
||||
DISCRIMINANT_OVERFLOW,
|
||||
DOT_INCLUDE,
|
||||
DOUBLE_UNDERSCORE,
|
||||
RESERVED_LIFETIME,
|
||||
RUST_TYPE_BY_VALUE,
|
||||
UNSUPPORTED_TYPE,
|
||||
USE_NOT_ALLOWED,
|
||||
];
|
||||
|
||||
pub static BOX_CXX_TYPE: Error = Error {
|
||||
msg: "Box of a C++ type is not supported yet",
|
||||
label: None,
|
||||
note: Some("hint: use UniquePtr<> or SharedPtr<>"),
|
||||
};
|
||||
|
||||
pub static CXXBRIDGE_RESERVED: Error = Error {
|
||||
msg: "identifiers starting with cxxbridge are reserved",
|
||||
label: Some("reserved identifier"),
|
||||
note: Some("identifiers starting with cxxbridge are reserved"),
|
||||
};
|
||||
|
||||
pub static CXX_STRING_BY_VALUE: Error = Error {
|
||||
msg: "C++ string by value is not supported",
|
||||
label: None,
|
||||
note: Some("hint: wrap it in a UniquePtr<>"),
|
||||
};
|
||||
|
||||
pub static CXX_TYPE_BY_VALUE: Error = Error {
|
||||
msg: "C++ type by value is not supported",
|
||||
label: None,
|
||||
note: Some("hint: wrap it in a UniquePtr<> or SharedPtr<>"),
|
||||
};
|
||||
|
||||
pub static DISCRIMINANT_OVERFLOW: Error = Error {
|
||||
msg: "discriminant overflow on value after ",
|
||||
label: Some("discriminant overflow"),
|
||||
note: Some("note: explicitly set `= 0` if that is desired outcome"),
|
||||
};
|
||||
|
||||
pub static DOT_INCLUDE: Error = Error {
|
||||
msg: "#include relative to `.` or `..` is not supported in Cargo builds",
|
||||
label: Some("#include relative to `.` or `..` is not supported in Cargo builds"),
|
||||
note: Some("note: use a path starting with the crate name"),
|
||||
};
|
||||
|
||||
pub static DOUBLE_UNDERSCORE: Error = Error {
|
||||
msg: "identifiers containing double underscore are reserved in C++",
|
||||
label: Some("reserved identifier"),
|
||||
note: Some("identifiers containing double underscore are reserved in C++"),
|
||||
};
|
||||
|
||||
pub static RESERVED_LIFETIME: Error = Error {
|
||||
msg: "invalid lifetime parameter name: `'static`",
|
||||
label: Some("'static is a reserved lifetime name"),
|
||||
note: None,
|
||||
};
|
||||
|
||||
pub static RUST_TYPE_BY_VALUE: Error = Error {
|
||||
msg: "opaque Rust type by value is not supported",
|
||||
label: None,
|
||||
note: Some("hint: wrap it in a Box<>"),
|
||||
};
|
||||
|
||||
pub static UNSUPPORTED_TYPE: Error = Error {
|
||||
msg: "unsupported type: ",
|
||||
label: Some("unsupported type"),
|
||||
note: None,
|
||||
};
|
||||
|
||||
pub static USE_NOT_ALLOWED: Error = Error {
|
||||
msg: "`use` items are not allowed within cxx bridge",
|
||||
label: Some("not allowed"),
|
||||
note: Some(
|
||||
"`use` items are not allowed within cxx bridge; only types defined\n\
|
||||
within your bridge, primitive types, or types exported by the cxx\n\
|
||||
crate may be used",
|
||||
),
|
||||
};
|
||||
127
vendor/cxx-build/src/syntax/file.rs
vendored
Normal file
127
vendor/cxx-build/src/syntax/file.rs
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
use crate::syntax::cfg::CfgExpr;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use quote::quote;
|
||||
use syn::parse::{Error, Parse, ParseStream, Result};
|
||||
use syn::{
|
||||
braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl,
|
||||
ItemStruct, ItemUse, LitStr, Token, Visibility,
|
||||
};
|
||||
|
||||
pub struct Module {
|
||||
pub cfg: CfgExpr,
|
||||
pub namespace: Namespace,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub vis: Visibility,
|
||||
pub unsafety: Option<Token![unsafe]>,
|
||||
pub mod_token: Token![mod],
|
||||
pub ident: Ident,
|
||||
pub brace_token: token::Brace,
|
||||
pub content: Vec<Item>,
|
||||
}
|
||||
|
||||
pub enum Item {
|
||||
Struct(ItemStruct),
|
||||
Enum(ItemEnum),
|
||||
ForeignMod(ItemForeignMod),
|
||||
Use(ItemUse),
|
||||
Impl(ItemImpl),
|
||||
Other(RustItem),
|
||||
}
|
||||
|
||||
pub struct ItemForeignMod {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub unsafety: Option<Token![unsafe]>,
|
||||
pub abi: Abi,
|
||||
pub brace_token: token::Brace,
|
||||
pub items: Vec<ForeignItem>,
|
||||
}
|
||||
|
||||
impl Parse for Module {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let cfg = CfgExpr::Unconditional;
|
||||
let namespace = Namespace::ROOT;
|
||||
let mut attrs = input.call(Attribute::parse_outer)?;
|
||||
let vis: Visibility = input.parse()?;
|
||||
let unsafety: Option<Token![unsafe]> = input.parse()?;
|
||||
let mod_token: Token![mod] = input.parse()?;
|
||||
let ident: Ident = input.parse()?;
|
||||
|
||||
let semi: Option<Token![;]> = input.parse()?;
|
||||
if let Some(semi) = semi {
|
||||
let span = quote!(#vis #mod_token #semi);
|
||||
return Err(Error::new_spanned(
|
||||
span,
|
||||
"#[cxx::bridge] module must have inline contents",
|
||||
));
|
||||
}
|
||||
|
||||
let content;
|
||||
let brace_token = braced!(content in input);
|
||||
attrs.extend(content.call(Attribute::parse_inner)?);
|
||||
|
||||
let mut items = Vec::new();
|
||||
while !content.is_empty() {
|
||||
items.push(content.parse()?);
|
||||
}
|
||||
|
||||
Ok(Module {
|
||||
cfg,
|
||||
namespace,
|
||||
attrs,
|
||||
vis,
|
||||
unsafety,
|
||||
mod_token,
|
||||
ident,
|
||||
brace_token,
|
||||
content: items,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Item {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
|
||||
let ahead = input.fork();
|
||||
let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some()
|
||||
&& ahead.parse::<Option<Token![extern]>>()?.is_some()
|
||||
&& ahead.parse::<Option<LitStr>>().is_ok()
|
||||
&& ahead.peek(token::Brace)
|
||||
{
|
||||
Some(input.parse()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let item = input.parse()?;
|
||||
match item {
|
||||
RustItem::Struct(mut item) => {
|
||||
item.attrs.splice(..0, attrs);
|
||||
Ok(Item::Struct(item))
|
||||
}
|
||||
RustItem::Enum(mut item) => {
|
||||
item.attrs.splice(..0, attrs);
|
||||
Ok(Item::Enum(item))
|
||||
}
|
||||
RustItem::ForeignMod(mut item) => {
|
||||
item.attrs.splice(..0, attrs);
|
||||
Ok(Item::ForeignMod(ItemForeignMod {
|
||||
attrs: item.attrs,
|
||||
unsafety,
|
||||
abi: item.abi,
|
||||
brace_token: item.brace_token,
|
||||
items: item.items,
|
||||
}))
|
||||
}
|
||||
RustItem::Impl(mut item) => {
|
||||
item.attrs.splice(..0, attrs);
|
||||
Ok(Item::Impl(item))
|
||||
}
|
||||
RustItem::Use(mut item) => {
|
||||
item.attrs.splice(..0, attrs);
|
||||
Ok(Item::Use(item))
|
||||
}
|
||||
other => Ok(Item::Other(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
57
vendor/cxx-build/src/syntax/ident.rs
vendored
Normal file
57
vendor/cxx-build/src/syntax/ident.rs
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use crate::syntax::check::Check;
|
||||
use crate::syntax::{error, Api, Pair};
|
||||
|
||||
fn check(cx: &mut Check, name: &Pair) {
|
||||
for segment in &name.namespace {
|
||||
check_cxx_ident(cx, &segment.to_string());
|
||||
}
|
||||
check_cxx_ident(cx, &name.cxx.to_string());
|
||||
check_rust_ident(cx, &name.rust.to_string());
|
||||
|
||||
fn check_cxx_ident(cx: &mut Check, ident: &str) {
|
||||
if ident.starts_with("cxxbridge") {
|
||||
cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
|
||||
}
|
||||
if ident.contains("__") {
|
||||
cx.error(ident, error::DOUBLE_UNDERSCORE.msg);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_rust_ident(cx: &mut Check, ident: &str) {
|
||||
if ident.starts_with("cxxbridge") {
|
||||
cx.error(ident, error::CXXBRIDGE_RESERVED.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_all(cx: &mut Check, apis: &[Api]) {
|
||||
for api in apis {
|
||||
match api {
|
||||
Api::Include(_) | Api::Impl(_) => {}
|
||||
Api::Struct(strct) => {
|
||||
check(cx, &strct.name);
|
||||
for field in &strct.fields {
|
||||
check(cx, &field.name);
|
||||
}
|
||||
}
|
||||
Api::Enum(enm) => {
|
||||
check(cx, &enm.name);
|
||||
for variant in &enm.variants {
|
||||
check(cx, &variant.name);
|
||||
}
|
||||
}
|
||||
Api::CxxType(ety) | Api::RustType(ety) => {
|
||||
check(cx, &ety.name);
|
||||
}
|
||||
Api::CxxFunction(efn) | Api::RustFunction(efn) => {
|
||||
check(cx, &efn.name);
|
||||
for arg in &efn.args {
|
||||
check(cx, &arg.name);
|
||||
}
|
||||
}
|
||||
Api::TypeAlias(alias) => {
|
||||
check(cx, &alias.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
450
vendor/cxx-build/src/syntax/impls.rs
vendored
Normal file
450
vendor/cxx-build/src/syntax/impls.rs
vendored
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
use crate::syntax::{
|
||||
Array, ExternFn, Include, Lifetimes, Ptr, Receiver, Ref, Signature, SliceRef, Ty1, Type, Var,
|
||||
};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
impl PartialEq for Include {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Include {
|
||||
cfg: _,
|
||||
path,
|
||||
kind,
|
||||
begin_span: _,
|
||||
end_span: _,
|
||||
} = self;
|
||||
let Include {
|
||||
cfg: _,
|
||||
path: path2,
|
||||
kind: kind2,
|
||||
begin_span: _,
|
||||
end_span: _,
|
||||
} = other;
|
||||
path == path2 && kind == kind2
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ExternFn {
|
||||
type Target = Signature;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.sig
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ExternFn {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.sig
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Type {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
mem::discriminant(self).hash(state);
|
||||
match self {
|
||||
Type::Ident(t) => t.hash(state),
|
||||
Type::RustBox(t) => t.hash(state),
|
||||
Type::UniquePtr(t) => t.hash(state),
|
||||
Type::SharedPtr(t) => t.hash(state),
|
||||
Type::WeakPtr(t) => t.hash(state),
|
||||
Type::Ref(t) => t.hash(state),
|
||||
Type::Ptr(t) => t.hash(state),
|
||||
Type::Str(t) => t.hash(state),
|
||||
Type::RustVec(t) => t.hash(state),
|
||||
Type::CxxVector(t) => t.hash(state),
|
||||
Type::Fn(t) => t.hash(state),
|
||||
Type::SliceRef(t) => t.hash(state),
|
||||
Type::Array(t) => t.hash(state),
|
||||
Type::Void(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Type {}
|
||||
|
||||
impl PartialEq for Type {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Type::Ident(lhs), Type::Ident(rhs)) => lhs == rhs,
|
||||
(Type::RustBox(lhs), Type::RustBox(rhs)) => lhs == rhs,
|
||||
(Type::UniquePtr(lhs), Type::UniquePtr(rhs)) => lhs == rhs,
|
||||
(Type::SharedPtr(lhs), Type::SharedPtr(rhs)) => lhs == rhs,
|
||||
(Type::WeakPtr(lhs), Type::WeakPtr(rhs)) => lhs == rhs,
|
||||
(Type::Ref(lhs), Type::Ref(rhs)) => lhs == rhs,
|
||||
(Type::Str(lhs), Type::Str(rhs)) => lhs == rhs,
|
||||
(Type::RustVec(lhs), Type::RustVec(rhs)) => lhs == rhs,
|
||||
(Type::CxxVector(lhs), Type::CxxVector(rhs)) => lhs == rhs,
|
||||
(Type::Fn(lhs), Type::Fn(rhs)) => lhs == rhs,
|
||||
(Type::SliceRef(lhs), Type::SliceRef(rhs)) => lhs == rhs,
|
||||
(Type::Void(_), Type::Void(_)) => true,
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Lifetimes {}
|
||||
|
||||
impl PartialEq for Lifetimes {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Lifetimes {
|
||||
lt_token: _,
|
||||
lifetimes,
|
||||
gt_token: _,
|
||||
} = self;
|
||||
let Lifetimes {
|
||||
lt_token: _,
|
||||
lifetimes: lifetimes2,
|
||||
gt_token: _,
|
||||
} = other;
|
||||
lifetimes.iter().eq(lifetimes2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Lifetimes {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Lifetimes {
|
||||
lt_token: _,
|
||||
lifetimes,
|
||||
gt_token: _,
|
||||
} = self;
|
||||
lifetimes.len().hash(state);
|
||||
for lifetime in lifetimes {
|
||||
lifetime.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Ty1 {}
|
||||
|
||||
impl PartialEq for Ty1 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Ty1 {
|
||||
name,
|
||||
langle: _,
|
||||
inner,
|
||||
rangle: _,
|
||||
} = self;
|
||||
let Ty1 {
|
||||
name: name2,
|
||||
langle: _,
|
||||
inner: inner2,
|
||||
rangle: _,
|
||||
} = other;
|
||||
name == name2 && inner == inner2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Ty1 {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Ty1 {
|
||||
name,
|
||||
langle: _,
|
||||
inner,
|
||||
rangle: _,
|
||||
} = self;
|
||||
name.hash(state);
|
||||
inner.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Ref {}
|
||||
|
||||
impl PartialEq for Ref {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Ref {
|
||||
pinned,
|
||||
ampersand: _,
|
||||
lifetime,
|
||||
mutable,
|
||||
inner,
|
||||
pin_tokens: _,
|
||||
mutability: _,
|
||||
} = self;
|
||||
let Ref {
|
||||
pinned: pinned2,
|
||||
ampersand: _,
|
||||
lifetime: lifetime2,
|
||||
mutable: mutable2,
|
||||
inner: inner2,
|
||||
pin_tokens: _,
|
||||
mutability: _,
|
||||
} = other;
|
||||
pinned == pinned2 && lifetime == lifetime2 && mutable == mutable2 && inner == inner2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Ref {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Ref {
|
||||
pinned,
|
||||
ampersand: _,
|
||||
lifetime,
|
||||
mutable,
|
||||
inner,
|
||||
pin_tokens: _,
|
||||
mutability: _,
|
||||
} = self;
|
||||
pinned.hash(state);
|
||||
lifetime.hash(state);
|
||||
mutable.hash(state);
|
||||
inner.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Ptr {}
|
||||
|
||||
impl PartialEq for Ptr {
|
||||
fn eq(&self, other: &Ptr) -> bool {
|
||||
let Ptr {
|
||||
star: _,
|
||||
mutable,
|
||||
inner,
|
||||
mutability: _,
|
||||
constness: _,
|
||||
} = self;
|
||||
let Ptr {
|
||||
star: _,
|
||||
mutable: mutable2,
|
||||
inner: inner2,
|
||||
mutability: _,
|
||||
constness: _,
|
||||
} = other;
|
||||
mutable == mutable2 && inner == inner2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Ptr {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Ptr {
|
||||
star: _,
|
||||
mutable,
|
||||
inner,
|
||||
mutability: _,
|
||||
constness: _,
|
||||
} = self;
|
||||
mutable.hash(state);
|
||||
inner.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SliceRef {}
|
||||
|
||||
impl PartialEq for SliceRef {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let SliceRef {
|
||||
ampersand: _,
|
||||
lifetime,
|
||||
mutable,
|
||||
bracket: _,
|
||||
inner,
|
||||
mutability: _,
|
||||
} = self;
|
||||
let SliceRef {
|
||||
ampersand: _,
|
||||
lifetime: lifetime2,
|
||||
mutable: mutable2,
|
||||
bracket: _,
|
||||
inner: inner2,
|
||||
mutability: _,
|
||||
} = other;
|
||||
lifetime == lifetime2 && mutable == mutable2 && inner == inner2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for SliceRef {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let SliceRef {
|
||||
ampersand: _,
|
||||
lifetime,
|
||||
mutable,
|
||||
bracket: _,
|
||||
inner,
|
||||
mutability: _,
|
||||
} = self;
|
||||
lifetime.hash(state);
|
||||
mutable.hash(state);
|
||||
inner.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Array {}
|
||||
|
||||
impl PartialEq for Array {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Array {
|
||||
bracket: _,
|
||||
inner,
|
||||
semi_token: _,
|
||||
len,
|
||||
len_token: _,
|
||||
} = self;
|
||||
let Array {
|
||||
bracket: _,
|
||||
inner: inner2,
|
||||
semi_token: _,
|
||||
len: len2,
|
||||
len_token: _,
|
||||
} = other;
|
||||
inner == inner2 && len == len2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Array {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Array {
|
||||
bracket: _,
|
||||
inner,
|
||||
semi_token: _,
|
||||
len,
|
||||
len_token: _,
|
||||
} = self;
|
||||
inner.hash(state);
|
||||
len.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Signature {}
|
||||
|
||||
impl PartialEq for Signature {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Signature {
|
||||
asyncness,
|
||||
unsafety,
|
||||
fn_token: _,
|
||||
generics: _,
|
||||
receiver,
|
||||
args,
|
||||
ret,
|
||||
throws,
|
||||
paren_token: _,
|
||||
throws_tokens: _,
|
||||
} = self;
|
||||
let Signature {
|
||||
asyncness: asyncness2,
|
||||
unsafety: unsafety2,
|
||||
fn_token: _,
|
||||
generics: _,
|
||||
receiver: receiver2,
|
||||
args: args2,
|
||||
ret: ret2,
|
||||
throws: throws2,
|
||||
paren_token: _,
|
||||
throws_tokens: _,
|
||||
} = other;
|
||||
asyncness.is_some() == asyncness2.is_some()
|
||||
&& unsafety.is_some() == unsafety2.is_some()
|
||||
&& receiver == receiver2
|
||||
&& ret == ret2
|
||||
&& throws == throws2
|
||||
&& args.len() == args2.len()
|
||||
&& args.iter().zip(args2).all(|(arg, arg2)| {
|
||||
let Var {
|
||||
cfg: _,
|
||||
doc: _,
|
||||
attrs: _,
|
||||
visibility: _,
|
||||
name: _,
|
||||
colon_token: _,
|
||||
ty,
|
||||
} = arg;
|
||||
let Var {
|
||||
cfg: _,
|
||||
doc: _,
|
||||
attrs: _,
|
||||
visibility: _,
|
||||
name: _,
|
||||
colon_token: _,
|
||||
ty: ty2,
|
||||
} = arg2;
|
||||
ty == ty2
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Signature {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Signature {
|
||||
asyncness,
|
||||
unsafety,
|
||||
fn_token: _,
|
||||
generics: _,
|
||||
receiver,
|
||||
args,
|
||||
ret,
|
||||
throws,
|
||||
paren_token: _,
|
||||
throws_tokens: _,
|
||||
} = self;
|
||||
asyncness.is_some().hash(state);
|
||||
unsafety.is_some().hash(state);
|
||||
receiver.hash(state);
|
||||
for arg in args {
|
||||
let Var {
|
||||
cfg: _,
|
||||
doc: _,
|
||||
attrs: _,
|
||||
visibility: _,
|
||||
name: _,
|
||||
colon_token: _,
|
||||
ty,
|
||||
} = arg;
|
||||
ty.hash(state);
|
||||
}
|
||||
ret.hash(state);
|
||||
throws.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Receiver {}
|
||||
|
||||
impl PartialEq for Receiver {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let Receiver {
|
||||
pinned,
|
||||
ampersand: _,
|
||||
lifetime,
|
||||
mutable,
|
||||
var: _,
|
||||
colon_token: _,
|
||||
ty,
|
||||
shorthand: _,
|
||||
pin_tokens: _,
|
||||
mutability: _,
|
||||
} = self;
|
||||
let Receiver {
|
||||
pinned: pinned2,
|
||||
ampersand: _,
|
||||
lifetime: lifetime2,
|
||||
mutable: mutable2,
|
||||
var: _,
|
||||
colon_token: _,
|
||||
ty: ty2,
|
||||
shorthand: _,
|
||||
pin_tokens: _,
|
||||
mutability: _,
|
||||
} = other;
|
||||
pinned == pinned2 && lifetime == lifetime2 && mutable == mutable2 && ty == ty2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Receiver {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Receiver {
|
||||
pinned,
|
||||
ampersand: _,
|
||||
lifetime,
|
||||
mutable,
|
||||
var: _,
|
||||
colon_token: _,
|
||||
ty,
|
||||
shorthand: _,
|
||||
pin_tokens: _,
|
||||
mutability: _,
|
||||
} = self;
|
||||
pinned.hash(state);
|
||||
lifetime.hash(state);
|
||||
mutable.hash(state);
|
||||
ty.hash(state);
|
||||
}
|
||||
}
|
||||
39
vendor/cxx-build/src/syntax/improper.rs
vendored
Normal file
39
vendor/cxx-build/src/syntax/improper.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use self::ImproperCtype::*;
|
||||
use crate::syntax::atom::Atom::{self, *};
|
||||
use crate::syntax::{Type, Types};
|
||||
use proc_macro2::Ident;
|
||||
|
||||
pub enum ImproperCtype<'a> {
|
||||
Definite(bool),
|
||||
Depends(&'a Ident),
|
||||
}
|
||||
|
||||
impl<'a> Types<'a> {
|
||||
// yes, no, maybe
|
||||
pub fn determine_improper_ctype(&self, ty: &Type) -> ImproperCtype<'a> {
|
||||
match ty {
|
||||
Type::Ident(ident) => {
|
||||
let ident = &ident.rust;
|
||||
if let Some(atom) = Atom::from(ident) {
|
||||
Definite(atom == RustString)
|
||||
} else if let Some(strct) = self.structs.get(ident) {
|
||||
Depends(&strct.name.rust) // iterate to fixed-point
|
||||
} else {
|
||||
Definite(self.rust.contains(ident) || self.aliases.contains_key(ident))
|
||||
}
|
||||
}
|
||||
Type::RustBox(_)
|
||||
| Type::RustVec(_)
|
||||
| Type::Str(_)
|
||||
| Type::Fn(_)
|
||||
| Type::Void(_)
|
||||
| Type::SliceRef(_) => Definite(true),
|
||||
Type::UniquePtr(_) | Type::SharedPtr(_) | Type::WeakPtr(_) | Type::CxxVector(_) => {
|
||||
Definite(false)
|
||||
}
|
||||
Type::Ref(ty) => self.determine_improper_ctype(&ty.inner),
|
||||
Type::Ptr(ty) => self.determine_improper_ctype(&ty.inner),
|
||||
Type::Array(ty) => self.determine_improper_ctype(&ty.inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
80
vendor/cxx-build/src/syntax/instantiate.rs
vendored
Normal file
80
vendor/cxx-build/src/syntax/instantiate.rs
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
use crate::syntax::{NamedType, Ty1, Type};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use syn::Token;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ImplKey<'a> {
|
||||
RustBox(NamedImplKey<'a>),
|
||||
RustVec(NamedImplKey<'a>),
|
||||
UniquePtr(NamedImplKey<'a>),
|
||||
SharedPtr(NamedImplKey<'a>),
|
||||
WeakPtr(NamedImplKey<'a>),
|
||||
CxxVector(NamedImplKey<'a>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NamedImplKey<'a> {
|
||||
pub begin_span: Span,
|
||||
pub rust: &'a Ident,
|
||||
pub lt_token: Option<Token![<]>,
|
||||
pub gt_token: Option<Token![>]>,
|
||||
pub end_span: Span,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub(crate) fn impl_key(&self) -> Option<ImplKey> {
|
||||
if let Type::RustBox(ty) = self {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
return Some(ImplKey::RustBox(NamedImplKey::new(ty, ident)));
|
||||
}
|
||||
} else if let Type::RustVec(ty) = self {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
return Some(ImplKey::RustVec(NamedImplKey::new(ty, ident)));
|
||||
}
|
||||
} else if let Type::UniquePtr(ty) = self {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
return Some(ImplKey::UniquePtr(NamedImplKey::new(ty, ident)));
|
||||
}
|
||||
} else if let Type::SharedPtr(ty) = self {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
return Some(ImplKey::SharedPtr(NamedImplKey::new(ty, ident)));
|
||||
}
|
||||
} else if let Type::WeakPtr(ty) = self {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
return Some(ImplKey::WeakPtr(NamedImplKey::new(ty, ident)));
|
||||
}
|
||||
} else if let Type::CxxVector(ty) = self {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
return Some(ImplKey::CxxVector(NamedImplKey::new(ty, ident)));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for NamedImplKey<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
PartialEq::eq(self.rust, other.rust)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Eq for NamedImplKey<'a> {}
|
||||
|
||||
impl<'a> Hash for NamedImplKey<'a> {
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
self.rust.hash(hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NamedImplKey<'a> {
|
||||
fn new(outer: &Ty1, inner: &'a NamedType) -> Self {
|
||||
NamedImplKey {
|
||||
begin_span: outer.name.span(),
|
||||
rust: &inner.rust,
|
||||
lt_token: inner.generics.lt_token,
|
||||
gt_token: inner.generics.gt_token,
|
||||
end_span: outer.rangle.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
120
vendor/cxx-build/src/syntax/mangle.rs
vendored
Normal file
120
vendor/cxx-build/src/syntax/mangle.rs
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Mangled symbol arrangements:
|
||||
//
|
||||
// (a) One-off internal symbol.
|
||||
// pattern: {CXXBRIDGE} $ {NAME}
|
||||
// examples:
|
||||
// - cxxbridge1$exception
|
||||
// defining characteristics:
|
||||
// - 2 segments
|
||||
// - starts with cxxbridge
|
||||
//
|
||||
// (b) Behavior on a builtin binding without generic parameter.
|
||||
// pattern: {CXXBRIDGE} $ {TYPE} $ {NAME}
|
||||
// examples:
|
||||
// - cxxbridge1$string$len
|
||||
// defining characteristics:
|
||||
// - 3 segments
|
||||
// - starts with cxxbridge
|
||||
//
|
||||
// (c) Behavior on a builtin binding with generic parameter.
|
||||
// pattern: {CXXBRIDGE} $ {TYPE} $ {PARAM...} $ {NAME}
|
||||
// examples:
|
||||
// - cxxbridge1$box$org$rust$Struct$alloc
|
||||
// - cxxbridge1$unique_ptr$std$vector$u8$drop
|
||||
// defining characteristics:
|
||||
// - 4+ segments
|
||||
// - starts with cxxbridge
|
||||
//
|
||||
// (d) User-defined extern function.
|
||||
// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {NAME}
|
||||
// examples:
|
||||
// - cxxbridge1$new_client
|
||||
// - org$rust$cxxbridge1$new_client
|
||||
// defining characteristics:
|
||||
// - cxxbridge is second from end
|
||||
// FIXME: conflict with (a) if they collide with one of our one-off symbol names in the global namespace
|
||||
//
|
||||
// (e) User-defined extern member function.
|
||||
// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ {NAME}
|
||||
// examples:
|
||||
// - org$cxxbridge1$Struct$get
|
||||
// defining characteristics:
|
||||
// - cxxbridge is third from end
|
||||
// FIXME: conflict with (b) if e.g. user binds a type in global namespace that collides with our builtin type names
|
||||
//
|
||||
// (f) Operator overload.
|
||||
// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE} $ operator $ {NAME}
|
||||
// examples:
|
||||
// - org$rust$cxxbridge1$Struct$operator$eq
|
||||
// defining characteristics:
|
||||
// - second segment from end is `operator` (not possible in type or namespace names)
|
||||
//
|
||||
// (g) Closure trampoline.
|
||||
// pattern: {NAMESPACE...} $ {CXXBRIDGE} $ {TYPE?} $ {NAME} $ {ARGUMENT} $ {DIRECTION}
|
||||
// examples:
|
||||
// - org$rust$cxxbridge1$Struct$invoke$f$0
|
||||
// defining characteristics:
|
||||
// - last symbol is `0` (C half) or `1` (Rust half) which are not legal identifiers on their own
|
||||
//
|
||||
//
|
||||
// Mangled preprocessor variable arrangements:
|
||||
//
|
||||
// (A) One-off internal variable.
|
||||
// pattern: {CXXBRIDGE} _ {NAME}
|
||||
// examples:
|
||||
// - CXXBRIDGE1_PANIC
|
||||
// - CXXBRIDGE1_RUST_STRING
|
||||
// defining characteristics:
|
||||
// - NAME does not begin with STRUCT or ENUM
|
||||
//
|
||||
// (B) Guard around user-defined type.
|
||||
// pattern: {CXXBRIDGE} _ {STRUCT or ENUM} _ {NAMESPACE...} $ {TYPE}
|
||||
// examples:
|
||||
// - CXXBRIDGE1_STRUCT_org$rust$Struct
|
||||
// - CXXBRIDGE1_ENUM_Enabled
|
||||
|
||||
use crate::syntax::symbol::{self, Symbol};
|
||||
use crate::syntax::{ExternFn, Pair, Types};
|
||||
|
||||
const CXXBRIDGE: &str = "cxxbridge1";
|
||||
|
||||
macro_rules! join {
|
||||
($($segment:expr),+ $(,)?) => {
|
||||
symbol::join(&[$(&$segment),+])
|
||||
};
|
||||
}
|
||||
|
||||
pub fn extern_fn(efn: &ExternFn, types: &Types) -> Symbol {
|
||||
match &efn.receiver {
|
||||
Some(receiver) => {
|
||||
let receiver_ident = types.resolve(&receiver.ty);
|
||||
join!(
|
||||
efn.name.namespace,
|
||||
CXXBRIDGE,
|
||||
receiver_ident.name.cxx,
|
||||
efn.name.rust,
|
||||
)
|
||||
}
|
||||
None => join!(efn.name.namespace, CXXBRIDGE, efn.name.rust),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn operator(receiver: &Pair, operator: &'static str) -> Symbol {
|
||||
join!(
|
||||
receiver.namespace,
|
||||
CXXBRIDGE,
|
||||
receiver.cxx,
|
||||
"operator",
|
||||
operator,
|
||||
)
|
||||
}
|
||||
|
||||
// The C half of a function pointer trampoline.
|
||||
pub fn c_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
|
||||
join!(extern_fn(efn, types), var.rust, 0)
|
||||
}
|
||||
|
||||
// The Rust half of a function pointer trampoline.
|
||||
pub fn r_trampoline(efn: &ExternFn, var: &Pair, types: &Types) -> Symbol {
|
||||
join!(extern_fn(efn, types), var.rust, 1)
|
||||
}
|
||||
180
vendor/cxx-build/src/syntax/map.rs
vendored
Normal file
180
vendor/cxx-build/src/syntax/map.rs
vendored
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Index;
|
||||
use std::slice;
|
||||
|
||||
pub use self::ordered::OrderedMap;
|
||||
pub use self::unordered::UnorderedMap;
|
||||
pub use std::collections::hash_map::Entry;
|
||||
|
||||
mod ordered {
|
||||
use super::{Entry, Iter, UnorderedMap};
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
use std::mem;
|
||||
|
||||
pub struct OrderedMap<K, V> {
|
||||
map: UnorderedMap<K, usize>,
|
||||
vec: Vec<(K, V)>,
|
||||
}
|
||||
|
||||
impl<K, V> OrderedMap<K, V> {
|
||||
pub fn new() -> Self {
|
||||
OrderedMap {
|
||||
map: UnorderedMap::new(),
|
||||
vec: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter(self.vec.iter())
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> impl Iterator<Item = &K> {
|
||||
self.vec.iter().map(|(k, _v)| k)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> OrderedMap<K, V>
|
||||
where
|
||||
K: Copy + Hash + Eq,
|
||||
{
|
||||
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
|
||||
match self.map.entry(key) {
|
||||
Entry::Occupied(entry) => {
|
||||
let i = &mut self.vec[*entry.get()];
|
||||
Some(mem::replace(&mut i.1, value))
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(self.vec.len());
|
||||
self.vec.push((key, value));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_key<Q>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.map.contains_key(key)
|
||||
}
|
||||
|
||||
pub fn get<Q>(&self, key: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let i = *self.map.get(key)?;
|
||||
Some(&self.vec[i].1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> IntoIterator for &'a OrderedMap<K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
type IntoIter = Iter<'a, K, V>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod unordered {
|
||||
use crate::syntax::set::UnorderedSet;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::hash::Hash;
|
||||
|
||||
// Wrapper prohibits accidentally introducing iteration over the map, which
|
||||
// could lead to nondeterministic generated code.
|
||||
pub struct UnorderedMap<K, V>(HashMap<K, V>);
|
||||
|
||||
impl<K, V> UnorderedMap<K, V> {
|
||||
pub fn new() -> Self {
|
||||
UnorderedMap(HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> UnorderedMap<K, V>
|
||||
where
|
||||
K: Hash + Eq,
|
||||
{
|
||||
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
|
||||
self.0.insert(key, value)
|
||||
}
|
||||
|
||||
pub fn contains_key<Q>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.0.contains_key(key)
|
||||
}
|
||||
|
||||
pub fn get<Q>(&self, key: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.0.get(key)
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||
self.0.entry(key)
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // only used by cxx-build, not cxxbridge-macro
|
||||
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.0.remove(key)
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> UnorderedSet<K>
|
||||
where
|
||||
K: Copy,
|
||||
{
|
||||
let mut set = UnorderedSet::new();
|
||||
for key in self.0.keys() {
|
||||
set.insert(*key);
|
||||
}
|
||||
set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'a, K, V>(slice::Iter<'a, (K, V)>);
|
||||
|
||||
impl<'a, K, V> Iterator for Iter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let (k, v) = self.0.next()?;
|
||||
Some((k, v))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Default for UnorderedMap<K, V> {
|
||||
fn default() -> Self {
|
||||
UnorderedMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Q, K, V> Index<&Q> for UnorderedMap<K, V>
|
||||
where
|
||||
K: Borrow<Q> + Hash + Eq,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
type Output = V;
|
||||
|
||||
fn index(&self, key: &Q) -> &V {
|
||||
self.get(key).unwrap()
|
||||
}
|
||||
}
|
||||
306
vendor/cxx-build/src/syntax/mod.rs
vendored
Normal file
306
vendor/cxx-build/src/syntax/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
// Functionality that is shared between the cxxbridge macro and the cmd.
|
||||
|
||||
pub mod atom;
|
||||
pub mod attrs;
|
||||
pub mod cfg;
|
||||
pub mod check;
|
||||
pub mod derive;
|
||||
mod discriminant;
|
||||
mod doc;
|
||||
pub mod error;
|
||||
pub mod file;
|
||||
pub mod ident;
|
||||
mod impls;
|
||||
mod improper;
|
||||
pub mod instantiate;
|
||||
pub mod mangle;
|
||||
pub mod map;
|
||||
mod names;
|
||||
pub mod namespace;
|
||||
mod parse;
|
||||
mod pod;
|
||||
pub mod qualified;
|
||||
pub mod report;
|
||||
pub mod resolve;
|
||||
pub mod set;
|
||||
pub mod symbol;
|
||||
mod tokens;
|
||||
mod toposort;
|
||||
pub mod trivial;
|
||||
pub mod types;
|
||||
mod visit;
|
||||
|
||||
use self::attrs::OtherAttrs;
|
||||
use self::cfg::CfgExpr;
|
||||
use self::namespace::Namespace;
|
||||
use self::parse::kw;
|
||||
use self::symbol::Symbol;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::token::{Brace, Bracket, Paren};
|
||||
use syn::{Attribute, Expr, Generics, Lifetime, LitInt, Token, Type as RustType};
|
||||
|
||||
pub use self::atom::Atom;
|
||||
pub use self::derive::{Derive, Trait};
|
||||
pub use self::discriminant::Discriminant;
|
||||
pub use self::doc::Doc;
|
||||
pub use self::names::ForeignName;
|
||||
pub use self::parse::parse_items;
|
||||
pub use self::types::Types;
|
||||
|
||||
pub enum Api {
|
||||
Include(Include),
|
||||
Struct(Struct),
|
||||
Enum(Enum),
|
||||
CxxType(ExternType),
|
||||
CxxFunction(ExternFn),
|
||||
RustType(ExternType),
|
||||
RustFunction(ExternFn),
|
||||
TypeAlias(TypeAlias),
|
||||
Impl(Impl),
|
||||
}
|
||||
|
||||
pub struct Include {
|
||||
pub cfg: CfgExpr,
|
||||
pub path: String,
|
||||
pub kind: IncludeKind,
|
||||
pub begin_span: Span,
|
||||
pub end_span: Span,
|
||||
}
|
||||
|
||||
/// Whether to emit `#include "path"` or `#include <path>`.
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum IncludeKind {
|
||||
/// `#include "quoted/path/to"`
|
||||
Quoted,
|
||||
/// `#include <bracketed/path/to>`
|
||||
Bracketed,
|
||||
}
|
||||
|
||||
pub struct ExternType {
|
||||
pub cfg: CfgExpr,
|
||||
pub lang: Lang,
|
||||
pub doc: Doc,
|
||||
pub derives: Vec<Derive>,
|
||||
pub attrs: OtherAttrs,
|
||||
pub visibility: Token![pub],
|
||||
pub type_token: Token![type],
|
||||
pub name: Pair,
|
||||
pub generics: Lifetimes,
|
||||
pub colon_token: Option<Token![:]>,
|
||||
pub bounds: Vec<Derive>,
|
||||
pub semi_token: Token![;],
|
||||
pub trusted: bool,
|
||||
}
|
||||
|
||||
pub struct Struct {
|
||||
pub cfg: CfgExpr,
|
||||
pub doc: Doc,
|
||||
pub derives: Vec<Derive>,
|
||||
pub attrs: OtherAttrs,
|
||||
pub visibility: Token![pub],
|
||||
pub struct_token: Token![struct],
|
||||
pub name: Pair,
|
||||
pub generics: Lifetimes,
|
||||
pub brace_token: Brace,
|
||||
pub fields: Vec<Var>,
|
||||
}
|
||||
|
||||
pub struct Enum {
|
||||
pub cfg: CfgExpr,
|
||||
pub doc: Doc,
|
||||
pub derives: Vec<Derive>,
|
||||
pub attrs: OtherAttrs,
|
||||
pub visibility: Token![pub],
|
||||
pub enum_token: Token![enum],
|
||||
pub name: Pair,
|
||||
pub generics: Lifetimes,
|
||||
pub brace_token: Brace,
|
||||
pub variants: Vec<Variant>,
|
||||
pub variants_from_header: bool,
|
||||
pub variants_from_header_attr: Option<Attribute>,
|
||||
pub repr: EnumRepr,
|
||||
pub explicit_repr: bool,
|
||||
}
|
||||
|
||||
pub enum EnumRepr {
|
||||
Native {
|
||||
atom: Atom,
|
||||
repr_type: Type,
|
||||
},
|
||||
#[cfg(feature = "experimental-enum-variants-from-header")]
|
||||
Foreign {
|
||||
rust_type: syn::Path,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct ExternFn {
|
||||
pub cfg: CfgExpr,
|
||||
pub lang: Lang,
|
||||
pub doc: Doc,
|
||||
pub attrs: OtherAttrs,
|
||||
pub visibility: Token![pub],
|
||||
pub name: Pair,
|
||||
pub sig: Signature,
|
||||
pub semi_token: Token![;],
|
||||
pub trusted: bool,
|
||||
}
|
||||
|
||||
pub struct TypeAlias {
|
||||
pub cfg: CfgExpr,
|
||||
pub doc: Doc,
|
||||
pub derives: Vec<Derive>,
|
||||
pub attrs: OtherAttrs,
|
||||
pub visibility: Token![pub],
|
||||
pub type_token: Token![type],
|
||||
pub name: Pair,
|
||||
pub generics: Lifetimes,
|
||||
pub eq_token: Token![=],
|
||||
pub ty: RustType,
|
||||
pub semi_token: Token![;],
|
||||
}
|
||||
|
||||
pub struct Impl {
|
||||
pub cfg: CfgExpr,
|
||||
pub impl_token: Token![impl],
|
||||
pub impl_generics: Lifetimes,
|
||||
pub negative: bool,
|
||||
pub ty: Type,
|
||||
pub ty_generics: Lifetimes,
|
||||
pub brace_token: Brace,
|
||||
pub negative_token: Option<Token![!]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Lifetimes {
|
||||
pub lt_token: Option<Token![<]>,
|
||||
pub lifetimes: Punctuated<Lifetime, Token![,]>,
|
||||
pub gt_token: Option<Token![>]>,
|
||||
}
|
||||
|
||||
pub struct Signature {
|
||||
pub asyncness: Option<Token![async]>,
|
||||
pub unsafety: Option<Token![unsafe]>,
|
||||
pub fn_token: Token![fn],
|
||||
pub generics: Generics,
|
||||
pub receiver: Option<Receiver>,
|
||||
pub args: Punctuated<Var, Token![,]>,
|
||||
pub ret: Option<Type>,
|
||||
pub throws: bool,
|
||||
pub paren_token: Paren,
|
||||
pub throws_tokens: Option<(kw::Result, Token![<], Token![>])>,
|
||||
}
|
||||
|
||||
pub struct Var {
|
||||
pub cfg: CfgExpr,
|
||||
pub doc: Doc,
|
||||
pub attrs: OtherAttrs,
|
||||
pub visibility: Token![pub],
|
||||
pub name: Pair,
|
||||
pub colon_token: Token![:],
|
||||
pub ty: Type,
|
||||
}
|
||||
|
||||
pub struct Receiver {
|
||||
pub pinned: bool,
|
||||
pub ampersand: Token![&],
|
||||
pub lifetime: Option<Lifetime>,
|
||||
pub mutable: bool,
|
||||
pub var: Token![self],
|
||||
pub ty: NamedType,
|
||||
pub colon_token: Token![:],
|
||||
pub shorthand: bool,
|
||||
pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
|
||||
pub mutability: Option<Token![mut]>,
|
||||
}
|
||||
|
||||
pub struct Variant {
|
||||
pub cfg: CfgExpr,
|
||||
pub doc: Doc,
|
||||
pub attrs: OtherAttrs,
|
||||
pub name: Pair,
|
||||
pub discriminant: Discriminant,
|
||||
pub expr: Option<Expr>,
|
||||
}
|
||||
|
||||
pub enum Type {
|
||||
Ident(NamedType),
|
||||
RustBox(Box<Ty1>),
|
||||
RustVec(Box<Ty1>),
|
||||
UniquePtr(Box<Ty1>),
|
||||
SharedPtr(Box<Ty1>),
|
||||
WeakPtr(Box<Ty1>),
|
||||
Ref(Box<Ref>),
|
||||
Ptr(Box<Ptr>),
|
||||
Str(Box<Ref>),
|
||||
CxxVector(Box<Ty1>),
|
||||
Fn(Box<Signature>),
|
||||
Void(Span),
|
||||
SliceRef(Box<SliceRef>),
|
||||
Array(Box<Array>),
|
||||
}
|
||||
|
||||
pub struct Ty1 {
|
||||
pub name: Ident,
|
||||
pub langle: Token![<],
|
||||
pub inner: Type,
|
||||
pub rangle: Token![>],
|
||||
}
|
||||
|
||||
pub struct Ref {
|
||||
pub pinned: bool,
|
||||
pub ampersand: Token![&],
|
||||
pub lifetime: Option<Lifetime>,
|
||||
pub mutable: bool,
|
||||
pub inner: Type,
|
||||
pub pin_tokens: Option<(kw::Pin, Token![<], Token![>])>,
|
||||
pub mutability: Option<Token![mut]>,
|
||||
}
|
||||
|
||||
pub struct Ptr {
|
||||
pub star: Token![*],
|
||||
pub mutable: bool,
|
||||
pub inner: Type,
|
||||
pub mutability: Option<Token![mut]>,
|
||||
pub constness: Option<Token![const]>,
|
||||
}
|
||||
|
||||
pub struct SliceRef {
|
||||
pub ampersand: Token![&],
|
||||
pub lifetime: Option<Lifetime>,
|
||||
pub mutable: bool,
|
||||
pub bracket: Bracket,
|
||||
pub inner: Type,
|
||||
pub mutability: Option<Token![mut]>,
|
||||
}
|
||||
|
||||
pub struct Array {
|
||||
pub bracket: Bracket,
|
||||
pub inner: Type,
|
||||
pub semi_token: Token![;],
|
||||
pub len: usize,
|
||||
pub len_token: LitInt,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Lang {
|
||||
Cxx,
|
||||
Rust,
|
||||
}
|
||||
|
||||
// An association of a defined Rust name with a fully resolved, namespace
|
||||
// qualified C++ name.
|
||||
#[derive(Clone)]
|
||||
pub struct Pair {
|
||||
pub namespace: Namespace,
|
||||
pub cxx: ForeignName,
|
||||
pub rust: Ident,
|
||||
}
|
||||
|
||||
// Wrapper for a type which needs to be resolved before it can be printed in
|
||||
// C++.
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
pub struct NamedType {
|
||||
pub rust: Ident,
|
||||
pub generics: Lifetimes,
|
||||
}
|
||||
64
vendor/cxx-build/src/syntax/names.rs
vendored
Normal file
64
vendor/cxx-build/src/syntax/names.rs
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
use crate::syntax::symbol::Segment;
|
||||
use crate::syntax::{Lifetimes, NamedType, Pair, Symbol};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter;
|
||||
use syn::parse::{Error, Result};
|
||||
use syn::punctuated::Punctuated;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ForeignName {
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl Pair {
|
||||
pub fn to_symbol(&self) -> Symbol {
|
||||
let segments = self
|
||||
.namespace
|
||||
.iter()
|
||||
.map(|ident| ident as &dyn Segment)
|
||||
.chain(iter::once(&self.cxx as &dyn Segment));
|
||||
Symbol::from_idents(segments)
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedType {
|
||||
pub fn new(rust: Ident) -> Self {
|
||||
let generics = Lifetimes {
|
||||
lt_token: None,
|
||||
lifetimes: Punctuated::new(),
|
||||
gt_token: None,
|
||||
};
|
||||
NamedType { rust, generics }
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
self.rust.span()
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignName {
|
||||
pub fn parse(text: &str, span: Span) -> Result<Self> {
|
||||
// TODO: support C++ names containing whitespace (`unsigned int`) or
|
||||
// non-alphanumeric characters (`operator++`).
|
||||
match syn::parse_str::<Ident>(text) {
|
||||
Ok(ident) => {
|
||||
let text = ident.to_string();
|
||||
Ok(ForeignName { text })
|
||||
}
|
||||
Err(err) => Err(Error::new(span, err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ForeignName {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(&self.text)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for ForeignName {
|
||||
fn eq(&self, rhs: &str) -> bool {
|
||||
self.text == rhs
|
||||
}
|
||||
}
|
||||
85
vendor/cxx-build/src/syntax/namespace.rs
vendored
Normal file
85
vendor/cxx-build/src/syntax/namespace.rs
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
use crate::syntax::qualified::QualifiedName;
|
||||
use quote::IdentFragment;
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter::FromIterator;
|
||||
use std::slice::Iter;
|
||||
use syn::parse::{Parse, ParseStream, Result};
|
||||
use syn::{Ident, Token};
|
||||
|
||||
mod kw {
|
||||
syn::custom_keyword!(namespace);
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Namespace {
|
||||
segments: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
pub const ROOT: Self = Namespace {
|
||||
segments: Vec::new(),
|
||||
};
|
||||
|
||||
pub fn iter(&self) -> Iter<Ident> {
|
||||
self.segments.iter()
|
||||
}
|
||||
|
||||
pub fn parse_bridge_attr_namespace(input: ParseStream) -> Result<Namespace> {
|
||||
if input.is_empty() {
|
||||
return Ok(Namespace::ROOT);
|
||||
}
|
||||
|
||||
input.parse::<kw::namespace>()?;
|
||||
input.parse::<Token![=]>()?;
|
||||
let namespace = input.parse::<Namespace>()?;
|
||||
input.parse::<Option<Token![,]>>()?;
|
||||
Ok(namespace)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &Namespace {
|
||||
fn default() -> Self {
|
||||
const ROOT: &Namespace = &Namespace::ROOT;
|
||||
ROOT
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Namespace {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let segments = QualifiedName::parse_quoted_or_unquoted(input)?.segments;
|
||||
Ok(Namespace { segments })
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Namespace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for segment in self {
|
||||
write!(f, "{}$", segment)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl IdentFragment for Namespace {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a Namespace {
|
||||
type Item = &'a Ident;
|
||||
type IntoIter = Iter<'a, Ident>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<&'a Ident> for Namespace {
|
||||
fn from_iter<I>(idents: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = &'a Ident>,
|
||||
{
|
||||
let segments = idents.into_iter().cloned().collect();
|
||||
Namespace { segments }
|
||||
}
|
||||
}
|
||||
1492
vendor/cxx-build/src/syntax/parse.rs
vendored
Normal file
1492
vendor/cxx-build/src/syntax/parse.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
36
vendor/cxx-build/src/syntax/pod.rs
vendored
Normal file
36
vendor/cxx-build/src/syntax/pod.rs
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use crate::syntax::atom::Atom::{self, *};
|
||||
use crate::syntax::{derive, Trait, Type, Types};
|
||||
|
||||
impl<'a> Types<'a> {
|
||||
pub fn is_guaranteed_pod(&self, ty: &Type) -> bool {
|
||||
match ty {
|
||||
Type::Ident(ident) => {
|
||||
let ident = &ident.rust;
|
||||
if let Some(atom) = Atom::from(ident) {
|
||||
match atom {
|
||||
Bool | Char | U8 | U16 | U32 | U64 | Usize | I8 | I16 | I32 | I64
|
||||
| Isize | F32 | F64 => true,
|
||||
CxxString | RustString => false,
|
||||
}
|
||||
} else if let Some(strct) = self.structs.get(ident) {
|
||||
derive::contains(&strct.derives, Trait::Copy)
|
||||
|| strct
|
||||
.fields
|
||||
.iter()
|
||||
.all(|field| self.is_guaranteed_pod(&field.ty))
|
||||
} else {
|
||||
self.enums.contains_key(ident)
|
||||
}
|
||||
}
|
||||
Type::RustBox(_)
|
||||
| Type::RustVec(_)
|
||||
| Type::UniquePtr(_)
|
||||
| Type::SharedPtr(_)
|
||||
| Type::WeakPtr(_)
|
||||
| Type::CxxVector(_)
|
||||
| Type::Void(_) => false,
|
||||
Type::Ref(_) | Type::Str(_) | Type::Fn(_) | Type::SliceRef(_) | Type::Ptr(_) => true,
|
||||
Type::Array(array) => self.is_guaranteed_pod(&array.inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
59
vendor/cxx-build/src/syntax/qualified.rs
vendored
Normal file
59
vendor/cxx-build/src/syntax/qualified.rs
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use syn::ext::IdentExt;
|
||||
use syn::parse::{Error, ParseStream, Result};
|
||||
use syn::{Ident, LitStr, Token};
|
||||
|
||||
pub struct QualifiedName {
|
||||
pub segments: Vec<Ident>,
|
||||
}
|
||||
|
||||
impl QualifiedName {
|
||||
pub fn parse_unquoted(input: ParseStream) -> Result<Self> {
|
||||
let allow_raw = true;
|
||||
parse_unquoted(input, allow_raw)
|
||||
}
|
||||
|
||||
pub fn parse_quoted_or_unquoted(input: ParseStream) -> Result<Self> {
|
||||
if input.peek(LitStr) {
|
||||
let lit: LitStr = input.parse()?;
|
||||
if lit.value().is_empty() {
|
||||
let segments = Vec::new();
|
||||
Ok(QualifiedName { segments })
|
||||
} else {
|
||||
lit.parse_with(|input: ParseStream| {
|
||||
let allow_raw = false;
|
||||
parse_unquoted(input, allow_raw)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Self::parse_unquoted(input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_unquoted(input: ParseStream, allow_raw: bool) -> Result<QualifiedName> {
|
||||
let mut segments = Vec::new();
|
||||
let mut trailing_punct = true;
|
||||
let leading_colons: Option<Token![::]> = input.parse()?;
|
||||
while trailing_punct && input.peek(Ident::peek_any) {
|
||||
let mut ident = Ident::parse_any(input)?;
|
||||
if let Some(unraw) = ident.to_string().strip_prefix("r#") {
|
||||
if !allow_raw {
|
||||
let msg = format!(
|
||||
"raw identifier `{}` is not allowed in a quoted namespace; use `{}`, or remove quotes",
|
||||
ident, unraw,
|
||||
);
|
||||
return Err(Error::new(ident.span(), msg));
|
||||
}
|
||||
ident = Ident::new(unraw, ident.span());
|
||||
}
|
||||
segments.push(ident);
|
||||
let colons: Option<Token![::]> = input.parse()?;
|
||||
trailing_punct = colons.is_some();
|
||||
}
|
||||
if segments.is_empty() && leading_colons.is_none() {
|
||||
return Err(input.error("expected path"));
|
||||
} else if trailing_punct {
|
||||
return Err(input.error("expected path segment"));
|
||||
}
|
||||
Ok(QualifiedName { segments })
|
||||
}
|
||||
33
vendor/cxx-build/src/syntax/report.rs
vendored
Normal file
33
vendor/cxx-build/src/syntax/report.rs
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use quote::ToTokens;
|
||||
use std::fmt::Display;
|
||||
use syn::{Error, Result};
|
||||
|
||||
pub struct Errors {
|
||||
errors: Vec<Error>,
|
||||
}
|
||||
|
||||
impl Errors {
|
||||
pub fn new() -> Self {
|
||||
Errors { errors: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn error(&mut self, sp: impl ToTokens, msg: impl Display) {
|
||||
self.errors.push(Error::new_spanned(sp, msg));
|
||||
}
|
||||
|
||||
pub fn push(&mut self, error: Error) {
|
||||
self.errors.push(error);
|
||||
}
|
||||
|
||||
pub fn propagate(&mut self) -> Result<()> {
|
||||
let mut iter = self.errors.drain(..);
|
||||
let mut all_errors = match iter.next() {
|
||||
Some(err) => err,
|
||||
None => return Ok(()),
|
||||
};
|
||||
for err in iter {
|
||||
all_errors.combine(err);
|
||||
}
|
||||
Err(all_errors)
|
||||
}
|
||||
}
|
||||
46
vendor/cxx-build/src/syntax/resolve.rs
vendored
Normal file
46
vendor/cxx-build/src/syntax/resolve.rs
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use crate::syntax::instantiate::NamedImplKey;
|
||||
use crate::syntax::{Lifetimes, NamedType, Pair, Types};
|
||||
use proc_macro2::Ident;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Resolution<'a> {
|
||||
pub name: &'a Pair,
|
||||
pub generics: &'a Lifetimes,
|
||||
}
|
||||
|
||||
impl<'a> Types<'a> {
|
||||
pub fn resolve(&self, ident: &impl UnresolvedName) -> Resolution<'a> {
|
||||
let ident = ident.ident();
|
||||
match self.try_resolve(ident) {
|
||||
Some(resolution) => resolution,
|
||||
None => panic!("Unable to resolve type `{}`", ident),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_resolve(&self, ident: &impl UnresolvedName) -> Option<Resolution<'a>> {
|
||||
let ident = ident.ident();
|
||||
self.resolutions.get(ident).copied()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UnresolvedName {
|
||||
fn ident(&self) -> &Ident;
|
||||
}
|
||||
|
||||
impl UnresolvedName for Ident {
|
||||
fn ident(&self) -> &Ident {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl UnresolvedName for NamedType {
|
||||
fn ident(&self) -> &Ident {
|
||||
&self.rust
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnresolvedName for NamedImplKey<'a> {
|
||||
fn ident(&self) -> &Ident {
|
||||
self.rust
|
||||
}
|
||||
}
|
||||
136
vendor/cxx-build/src/syntax/set.rs
vendored
Normal file
136
vendor/cxx-build/src/syntax/set.rs
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
use std::fmt::{self, Debug};
|
||||
use std::slice;
|
||||
|
||||
pub use self::ordered::OrderedSet;
|
||||
pub use self::unordered::UnorderedSet;
|
||||
|
||||
mod ordered {
|
||||
use super::{Iter, UnorderedSet};
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
|
||||
pub struct OrderedSet<T> {
|
||||
set: UnorderedSet<T>,
|
||||
vec: Vec<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> OrderedSet<&'a T>
|
||||
where
|
||||
T: Hash + Eq,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
OrderedSet {
|
||||
set: UnorderedSet::new(),
|
||||
vec: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, value: &'a T) -> bool {
|
||||
let new = self.set.insert(value);
|
||||
if new {
|
||||
self.vec.push(value);
|
||||
}
|
||||
new
|
||||
}
|
||||
|
||||
pub fn contains<Q>(&self, value: &Q) -> bool
|
||||
where
|
||||
&'a T: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.set.contains(value)
|
||||
}
|
||||
|
||||
pub fn get<Q>(&self, value: &Q) -> Option<&'a T>
|
||||
where
|
||||
&'a T: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.set.get(value).copied()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> OrderedSet<&'a T> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.vec.is_empty()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<'_, 'a, T> {
|
||||
Iter(self.vec.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, 'a, T> IntoIterator for &'s OrderedSet<&'a T> {
|
||||
type Item = &'a T;
|
||||
type IntoIter = Iter<'s, 'a, T>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod unordered {
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
|
||||
// Wrapper prohibits accidentally introducing iteration over the set, which
|
||||
// could lead to nondeterministic generated code.
|
||||
pub struct UnorderedSet<T>(HashSet<T>);
|
||||
|
||||
impl<T> UnorderedSet<T>
|
||||
where
|
||||
T: Hash + Eq,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
UnorderedSet(HashSet::new())
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, value: T) -> bool {
|
||||
self.0.insert(value)
|
||||
}
|
||||
|
||||
pub fn contains<Q>(&self, value: &Q) -> bool
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.0.contains(value)
|
||||
}
|
||||
|
||||
pub fn get<Q>(&self, value: &Q) -> Option<&T>
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
self.0.get(value)
|
||||
}
|
||||
|
||||
pub fn retain(&mut self, f: impl FnMut(&T) -> bool) {
|
||||
self.0.retain(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<'s, 'a, T>(slice::Iter<'s, &'a T>);
|
||||
|
||||
impl<'s, 'a, T> Iterator for Iter<'s, 'a, T> {
|
||||
type Item = &'a T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next().copied()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.0.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Debug for OrderedSet<&'a T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.debug_set().entries(self).finish()
|
||||
}
|
||||
}
|
||||
110
vendor/cxx-build/src/syntax/symbol.rs
vendored
Normal file
110
vendor/cxx-build/src/syntax/symbol.rs
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::{ForeignName, Pair};
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::ToTokens;
|
||||
use std::fmt::{self, Display, Write};
|
||||
|
||||
// A mangled symbol consisting of segments separated by '$'.
|
||||
// For example: cxxbridge1$string$new
|
||||
pub struct Symbol(String);
|
||||
|
||||
impl Display for Symbol {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.0, formatter)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Symbol {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
ToTokens::to_tokens(&self.0, tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
fn push(&mut self, segment: &dyn Display) {
|
||||
let len_before = self.0.len();
|
||||
if !self.0.is_empty() {
|
||||
self.0.push('$');
|
||||
}
|
||||
self.0.write_fmt(format_args!("{}", segment)).unwrap();
|
||||
assert!(self.0.len() > len_before);
|
||||
}
|
||||
|
||||
pub fn from_idents<'a>(it: impl Iterator<Item = &'a dyn Segment>) -> Self {
|
||||
let mut symbol = Symbol(String::new());
|
||||
for segment in it {
|
||||
segment.write(&mut symbol);
|
||||
}
|
||||
assert!(!symbol.0.is_empty());
|
||||
symbol
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Segment {
|
||||
fn write(&self, symbol: &mut Symbol);
|
||||
}
|
||||
|
||||
impl Segment for str {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
symbol.push(&self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Segment for usize {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
symbol.push(&self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Segment for Ident {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
symbol.push(&self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Segment for Symbol {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
symbol.push(&self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Segment for Namespace {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
for segment in self {
|
||||
symbol.push(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Segment for Pair {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
self.namespace.write(symbol);
|
||||
self.cxx.write(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
impl Segment for ForeignName {
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
// TODO: support C++ names containing whitespace (`unsigned int`) or
|
||||
// non-alphanumeric characters (`operator++`).
|
||||
self.to_string().write(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Segment for &'_ T
|
||||
where
|
||||
T: ?Sized + Segment + Display,
|
||||
{
|
||||
fn write(&self, symbol: &mut Symbol) {
|
||||
(**self).write(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(segments: &[&dyn Segment]) -> Symbol {
|
||||
let mut symbol = Symbol(String::new());
|
||||
for segment in segments {
|
||||
segment.write(&mut symbol);
|
||||
}
|
||||
assert!(!symbol.0.is_empty());
|
||||
symbol
|
||||
}
|
||||
308
vendor/cxx-build/src/syntax/tokens.rs
vendored
Normal file
308
vendor/cxx-build/src/syntax/tokens.rs
vendored
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
use crate::syntax::atom::Atom::*;
|
||||
use crate::syntax::{
|
||||
Array, Atom, Derive, Enum, EnumRepr, ExternFn, ExternType, Impl, Lifetimes, NamedType, Ptr,
|
||||
Ref, Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
|
||||
};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote_spanned, ToTokens};
|
||||
use syn::{token, Token};
|
||||
|
||||
impl ToTokens for Type {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
Type::Ident(ident) => {
|
||||
if ident.rust == Char {
|
||||
let span = ident.rust.span();
|
||||
tokens.extend(quote_spanned!(span=> ::cxx::private::));
|
||||
} else if ident.rust == CxxString {
|
||||
let span = ident.rust.span();
|
||||
tokens.extend(quote_spanned!(span=> ::cxx::));
|
||||
} else if ident.rust == RustString {
|
||||
let span = ident.rust.span();
|
||||
tokens.extend(quote_spanned!(span=> ::cxx::alloc::string::));
|
||||
}
|
||||
ident.to_tokens(tokens);
|
||||
}
|
||||
Type::RustBox(ty)
|
||||
| Type::UniquePtr(ty)
|
||||
| Type::SharedPtr(ty)
|
||||
| Type::WeakPtr(ty)
|
||||
| Type::CxxVector(ty)
|
||||
| Type::RustVec(ty) => ty.to_tokens(tokens),
|
||||
Type::Ref(r) | Type::Str(r) => r.to_tokens(tokens),
|
||||
Type::Ptr(p) => p.to_tokens(tokens),
|
||||
Type::Array(a) => a.to_tokens(tokens),
|
||||
Type::Fn(f) => f.to_tokens(tokens),
|
||||
Type::Void(span) => tokens.extend(quote_spanned!(*span=> ())),
|
||||
Type::SliceRef(r) => r.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Var {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Var {
|
||||
cfg: _,
|
||||
doc: _,
|
||||
attrs: _,
|
||||
visibility: _,
|
||||
name,
|
||||
colon_token: _,
|
||||
ty,
|
||||
} = self;
|
||||
name.rust.to_tokens(tokens);
|
||||
Token).to_tokens(tokens);
|
||||
ty.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Ty1 {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Ty1 {
|
||||
name,
|
||||
langle,
|
||||
inner,
|
||||
rangle,
|
||||
} = self;
|
||||
let span = name.span();
|
||||
match name.to_string().as_str() {
|
||||
"UniquePtr" | "SharedPtr" | "WeakPtr" | "CxxVector" => {
|
||||
tokens.extend(quote_spanned!(span=> ::cxx::));
|
||||
}
|
||||
"Box" => {
|
||||
tokens.extend(quote_spanned!(span=> ::cxx::alloc::boxed::));
|
||||
}
|
||||
"Vec" => {
|
||||
tokens.extend(quote_spanned!(span=> ::cxx::alloc::vec::));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
name.to_tokens(tokens);
|
||||
langle.to_tokens(tokens);
|
||||
inner.to_tokens(tokens);
|
||||
rangle.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Ref {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Ref {
|
||||
pinned: _,
|
||||
ampersand,
|
||||
lifetime,
|
||||
mutable: _,
|
||||
inner,
|
||||
pin_tokens,
|
||||
mutability,
|
||||
} = self;
|
||||
if let Some((pin, langle, _rangle)) = pin_tokens {
|
||||
tokens.extend(quote_spanned!(pin.span=> ::cxx::core::pin::Pin));
|
||||
langle.to_tokens(tokens);
|
||||
}
|
||||
ampersand.to_tokens(tokens);
|
||||
lifetime.to_tokens(tokens);
|
||||
mutability.to_tokens(tokens);
|
||||
inner.to_tokens(tokens);
|
||||
if let Some((_pin, _langle, rangle)) = pin_tokens {
|
||||
rangle.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Ptr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Ptr {
|
||||
star,
|
||||
mutable: _,
|
||||
inner,
|
||||
mutability,
|
||||
constness,
|
||||
} = self;
|
||||
star.to_tokens(tokens);
|
||||
mutability.to_tokens(tokens);
|
||||
constness.to_tokens(tokens);
|
||||
inner.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for SliceRef {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let SliceRef {
|
||||
ampersand,
|
||||
lifetime,
|
||||
mutable: _,
|
||||
bracket,
|
||||
inner,
|
||||
mutability,
|
||||
} = self;
|
||||
ampersand.to_tokens(tokens);
|
||||
lifetime.to_tokens(tokens);
|
||||
mutability.to_tokens(tokens);
|
||||
bracket.surround(tokens, |tokens| {
|
||||
inner.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Array {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Array {
|
||||
bracket,
|
||||
inner,
|
||||
semi_token,
|
||||
len: _,
|
||||
len_token,
|
||||
} = self;
|
||||
bracket.surround(tokens, |tokens| {
|
||||
inner.to_tokens(tokens);
|
||||
semi_token.to_tokens(tokens);
|
||||
len_token.to_tokens(tokens);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Atom {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
Ident::new(self.as_ref(), Span::call_site()).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Derive {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
Ident::new(self.what.as_ref(), self.span).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ExternType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
// Notional token range for error reporting purposes.
|
||||
self.type_token.to_tokens(tokens);
|
||||
self.name.rust.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for TypeAlias {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
// Notional token range for error reporting purposes.
|
||||
self.type_token.to_tokens(tokens);
|
||||
self.name.rust.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Struct {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
// Notional token range for error reporting purposes.
|
||||
self.struct_token.to_tokens(tokens);
|
||||
self.name.rust.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Enum {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
// Notional token range for error reporting purposes.
|
||||
self.enum_token.to_tokens(tokens);
|
||||
self.name.rust.to_tokens(tokens);
|
||||
self.generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ExternFn {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
// Notional token range for error reporting purposes.
|
||||
self.unsafety.to_tokens(tokens);
|
||||
self.sig.fn_token.to_tokens(tokens);
|
||||
self.semi_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Impl {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Impl {
|
||||
cfg: _,
|
||||
impl_token,
|
||||
impl_generics,
|
||||
negative: _,
|
||||
ty,
|
||||
ty_generics: _,
|
||||
brace_token,
|
||||
negative_token,
|
||||
} = self;
|
||||
impl_token.to_tokens(tokens);
|
||||
impl_generics.to_tokens(tokens);
|
||||
negative_token.to_tokens(tokens);
|
||||
ty.to_tokens(tokens);
|
||||
brace_token.surround(tokens, |_tokens| {});
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Lifetimes {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Lifetimes {
|
||||
lt_token,
|
||||
lifetimes,
|
||||
gt_token,
|
||||
} = self;
|
||||
lt_token.to_tokens(tokens);
|
||||
lifetimes.to_tokens(tokens);
|
||||
gt_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Signature {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Signature {
|
||||
asyncness: _,
|
||||
unsafety: _,
|
||||
fn_token,
|
||||
generics: _,
|
||||
receiver: _,
|
||||
args,
|
||||
ret,
|
||||
throws: _,
|
||||
paren_token,
|
||||
throws_tokens,
|
||||
} = self;
|
||||
fn_token.to_tokens(tokens);
|
||||
paren_token.surround(tokens, |tokens| {
|
||||
args.to_tokens(tokens);
|
||||
});
|
||||
if let Some(ret) = ret {
|
||||
Token.to_tokens(tokens);
|
||||
if let Some((result, langle, rangle)) = throws_tokens {
|
||||
result.to_tokens(tokens);
|
||||
langle.to_tokens(tokens);
|
||||
ret.to_tokens(tokens);
|
||||
rangle.to_tokens(tokens);
|
||||
} else {
|
||||
ret.to_tokens(tokens);
|
||||
}
|
||||
} else if let Some((result, langle, rangle)) = throws_tokens {
|
||||
Token.to_tokens(tokens);
|
||||
result.to_tokens(tokens);
|
||||
langle.to_tokens(tokens);
|
||||
token::Paren(langle.span).surround(tokens, |_| ());
|
||||
rangle.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for EnumRepr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
EnumRepr::Native { atom, repr_type: _ } => atom.to_tokens(tokens),
|
||||
#[cfg(feature = "experimental-enum-variants-from-header")]
|
||||
EnumRepr::Foreign { rust_type } => rust_type.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for NamedType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let NamedType { rust, generics } = self;
|
||||
rust.to_tokens(tokens);
|
||||
generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
51
vendor/cxx-build/src/syntax/toposort.rs
vendored
Normal file
51
vendor/cxx-build/src/syntax/toposort.rs
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use crate::syntax::map::{Entry, UnorderedMap as Map};
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::{Api, Struct, Type, Types};
|
||||
|
||||
enum Mark {
|
||||
Visiting,
|
||||
Visited,
|
||||
}
|
||||
|
||||
pub fn sort<'a>(cx: &mut Errors, apis: &'a [Api], types: &Types<'a>) -> Vec<&'a Struct> {
|
||||
let mut sorted = Vec::new();
|
||||
let ref mut marks = Map::new();
|
||||
for api in apis {
|
||||
if let Api::Struct(strct) = api {
|
||||
let _ = visit(cx, strct, &mut sorted, marks, types);
|
||||
}
|
||||
}
|
||||
sorted
|
||||
}
|
||||
|
||||
fn visit<'a>(
|
||||
cx: &mut Errors,
|
||||
strct: &'a Struct,
|
||||
sorted: &mut Vec<&'a Struct>,
|
||||
marks: &mut Map<*const Struct, Mark>,
|
||||
types: &Types<'a>,
|
||||
) -> Result<(), ()> {
|
||||
match marks.entry(strct) {
|
||||
Entry::Occupied(entry) => match entry.get() {
|
||||
Mark::Visiting => return Err(()), // not a DAG
|
||||
Mark::Visited => return Ok(()),
|
||||
},
|
||||
Entry::Vacant(entry) => {
|
||||
entry.insert(Mark::Visiting);
|
||||
}
|
||||
}
|
||||
let mut result = Ok(());
|
||||
for field in &strct.fields {
|
||||
if let Type::Ident(ident) = &field.ty {
|
||||
if let Some(inner) = types.structs.get(&ident.rust) {
|
||||
if visit(cx, inner, sorted, marks, types).is_err() {
|
||||
cx.error(field, "unsupported cyclic data structure");
|
||||
result = Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
marks.insert(strct, Mark::Visited);
|
||||
sorted.push(strct);
|
||||
result
|
||||
}
|
||||
312
vendor/cxx-build/src/syntax/trivial.rs
vendored
Normal file
312
vendor/cxx-build/src/syntax/trivial.rs
vendored
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
use crate::syntax::map::UnorderedMap;
|
||||
use crate::syntax::set::{OrderedSet as Set, UnorderedSet};
|
||||
use crate::syntax::{Api, Enum, ExternFn, NamedType, Pair, Struct, Type};
|
||||
use proc_macro2::Ident;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum TrivialReason<'a> {
|
||||
StructField(&'a Struct),
|
||||
FunctionArgument(&'a ExternFn),
|
||||
FunctionReturn(&'a ExternFn),
|
||||
BoxTarget,
|
||||
VecElement,
|
||||
SliceElement { mutable: bool },
|
||||
UnpinnedMut(&'a ExternFn),
|
||||
}
|
||||
|
||||
pub fn required_trivial_reasons<'a>(
|
||||
apis: &'a [Api],
|
||||
all: &Set<&'a Type>,
|
||||
structs: &UnorderedMap<&'a Ident, &'a Struct>,
|
||||
enums: &UnorderedMap<&'a Ident, &'a Enum>,
|
||||
cxx: &UnorderedSet<&'a Ident>,
|
||||
) -> UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>> {
|
||||
let mut required_trivial = UnorderedMap::new();
|
||||
|
||||
let mut insist_extern_types_are_trivial = |ident: &'a NamedType, reason| {
|
||||
if cxx.contains(&ident.rust)
|
||||
&& !structs.contains_key(&ident.rust)
|
||||
&& !enums.contains_key(&ident.rust)
|
||||
{
|
||||
required_trivial
|
||||
.entry(&ident.rust)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(reason);
|
||||
}
|
||||
};
|
||||
|
||||
for api in apis {
|
||||
match api {
|
||||
Api::Struct(strct) => {
|
||||
for field in &strct.fields {
|
||||
if let Type::Ident(ident) = &field.ty {
|
||||
let reason = TrivialReason::StructField(strct);
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
Api::CxxFunction(efn) | Api::RustFunction(efn) => {
|
||||
if let Some(receiver) = &efn.receiver {
|
||||
if receiver.mutable && !receiver.pinned {
|
||||
let reason = TrivialReason::UnpinnedMut(efn);
|
||||
insist_extern_types_are_trivial(&receiver.ty, reason);
|
||||
}
|
||||
}
|
||||
for arg in &efn.args {
|
||||
match &arg.ty {
|
||||
Type::Ident(ident) => {
|
||||
let reason = TrivialReason::FunctionArgument(efn);
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
Type::Ref(ty) => {
|
||||
if ty.mutable && !ty.pinned {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
let reason = TrivialReason::UnpinnedMut(efn);
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if let Some(ret) = &efn.ret {
|
||||
match ret {
|
||||
Type::Ident(ident) => {
|
||||
let reason = TrivialReason::FunctionReturn(efn);
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
Type::Ref(ty) => {
|
||||
if ty.mutable && !ty.pinned {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
let reason = TrivialReason::UnpinnedMut(efn);
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
for ty in all {
|
||||
match ty {
|
||||
Type::RustBox(ty) => {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
let reason = TrivialReason::BoxTarget;
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
}
|
||||
Type::RustVec(ty) => {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
let reason = TrivialReason::VecElement;
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
}
|
||||
Type::SliceRef(ty) => {
|
||||
if let Type::Ident(ident) = &ty.inner {
|
||||
let reason = TrivialReason::SliceElement {
|
||||
mutable: ty.mutable,
|
||||
};
|
||||
insist_extern_types_are_trivial(ident, reason);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
required_trivial
|
||||
}
|
||||
|
||||
// Context:
|
||||
// "type {type} should be trivially move constructible and trivially destructible in C++ to be used as {what} in Rust"
|
||||
// "needs a cxx::ExternType impl in order to be used as {what}"
|
||||
pub fn as_what<'a>(name: &'a Pair, reasons: &'a [TrivialReason]) -> impl Display + 'a {
|
||||
struct Description<'a> {
|
||||
name: &'a Pair,
|
||||
reasons: &'a [TrivialReason<'a>],
|
||||
}
|
||||
|
||||
impl<'a> Display for Description<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut field_of = Set::new();
|
||||
let mut argument_of = Set::new();
|
||||
let mut return_of = Set::new();
|
||||
let mut box_target = false;
|
||||
let mut vec_element = false;
|
||||
let mut slice_shared_element = false;
|
||||
let mut slice_mut_element = false;
|
||||
let mut unpinned_mut = Set::new();
|
||||
|
||||
for reason in self.reasons {
|
||||
match reason {
|
||||
TrivialReason::StructField(strct) => {
|
||||
field_of.insert(&strct.name.rust);
|
||||
}
|
||||
TrivialReason::FunctionArgument(efn) => {
|
||||
argument_of.insert(&efn.name.rust);
|
||||
}
|
||||
TrivialReason::FunctionReturn(efn) => {
|
||||
return_of.insert(&efn.name.rust);
|
||||
}
|
||||
TrivialReason::BoxTarget => box_target = true,
|
||||
TrivialReason::VecElement => vec_element = true,
|
||||
TrivialReason::SliceElement { mutable } => {
|
||||
if *mutable {
|
||||
slice_mut_element = true;
|
||||
} else {
|
||||
slice_shared_element = true;
|
||||
}
|
||||
}
|
||||
TrivialReason::UnpinnedMut(efn) => {
|
||||
unpinned_mut.insert(&efn.name.rust);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut clauses = Vec::new();
|
||||
if !field_of.is_empty() {
|
||||
clauses.push(Clause::Set {
|
||||
article: "a",
|
||||
desc: "field of",
|
||||
set: &field_of,
|
||||
});
|
||||
}
|
||||
if !argument_of.is_empty() {
|
||||
clauses.push(Clause::Set {
|
||||
article: "an",
|
||||
desc: "argument of",
|
||||
set: &argument_of,
|
||||
});
|
||||
}
|
||||
if !return_of.is_empty() {
|
||||
clauses.push(Clause::Set {
|
||||
article: "a",
|
||||
desc: "return value of",
|
||||
set: &return_of,
|
||||
});
|
||||
}
|
||||
if box_target {
|
||||
clauses.push(Clause::Ty1 {
|
||||
article: "type",
|
||||
desc: "Box",
|
||||
param: self.name,
|
||||
});
|
||||
}
|
||||
if vec_element {
|
||||
clauses.push(Clause::Ty1 {
|
||||
article: "a",
|
||||
desc: "vector element in Vec",
|
||||
param: self.name,
|
||||
});
|
||||
}
|
||||
if slice_shared_element || slice_mut_element {
|
||||
clauses.push(Clause::Slice {
|
||||
article: "a",
|
||||
desc: "slice element in",
|
||||
shared: slice_shared_element,
|
||||
mutable: slice_mut_element,
|
||||
param: self.name,
|
||||
});
|
||||
}
|
||||
if !unpinned_mut.is_empty() {
|
||||
clauses.push(Clause::Set {
|
||||
article: "a",
|
||||
desc: "non-pinned mutable reference in signature of",
|
||||
set: &unpinned_mut,
|
||||
});
|
||||
}
|
||||
|
||||
for (i, clause) in clauses.iter().enumerate() {
|
||||
if i == 0 {
|
||||
write!(f, "{} ", clause.article())?;
|
||||
} else if i + 1 < clauses.len() {
|
||||
write!(f, ", ")?;
|
||||
} else {
|
||||
write!(f, " or ")?;
|
||||
}
|
||||
clause.fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
enum Clause<'a> {
|
||||
Set {
|
||||
article: &'a str,
|
||||
desc: &'a str,
|
||||
set: &'a Set<&'a Ident>,
|
||||
},
|
||||
Ty1 {
|
||||
article: &'a str,
|
||||
desc: &'a str,
|
||||
param: &'a Pair,
|
||||
},
|
||||
Slice {
|
||||
article: &'a str,
|
||||
desc: &'a str,
|
||||
shared: bool,
|
||||
mutable: bool,
|
||||
param: &'a Pair,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Clause<'a> {
|
||||
fn article(&self) -> &'a str {
|
||||
match self {
|
||||
Clause::Set { article, .. }
|
||||
| Clause::Ty1 { article, .. }
|
||||
| Clause::Slice { article, .. } => article,
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Clause::Set {
|
||||
article: _,
|
||||
desc,
|
||||
set,
|
||||
} => {
|
||||
write!(f, "{} ", desc)?;
|
||||
for (i, ident) in set.iter().take(3).enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "`{}`", ident)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Clause::Ty1 {
|
||||
article: _,
|
||||
desc,
|
||||
param,
|
||||
} => write!(f, "{}<{}>", desc, param.rust),
|
||||
Clause::Slice {
|
||||
article: _,
|
||||
desc,
|
||||
shared,
|
||||
mutable,
|
||||
param,
|
||||
} => {
|
||||
write!(f, "{} ", desc)?;
|
||||
if *shared {
|
||||
write!(f, "&[{}]", param.rust)?;
|
||||
}
|
||||
if *shared && *mutable {
|
||||
write!(f, " and ")?;
|
||||
}
|
||||
if *mutable {
|
||||
write!(f, "&mut [{}]", param.rust)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Description { name, reasons }
|
||||
}
|
||||
285
vendor/cxx-build/src/syntax/types.rs
vendored
Normal file
285
vendor/cxx-build/src/syntax/types.rs
vendored
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
use crate::syntax::improper::ImproperCtype;
|
||||
use crate::syntax::instantiate::ImplKey;
|
||||
use crate::syntax::map::{OrderedMap, UnorderedMap};
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::resolve::Resolution;
|
||||
use crate::syntax::set::{OrderedSet, UnorderedSet};
|
||||
use crate::syntax::trivial::{self, TrivialReason};
|
||||
use crate::syntax::visit::{self, Visit};
|
||||
use crate::syntax::{
|
||||
toposort, Api, Atom, Enum, EnumRepr, ExternType, Impl, Lifetimes, Pair, Struct, Type, TypeAlias,
|
||||
};
|
||||
use proc_macro2::Ident;
|
||||
use quote::ToTokens;
|
||||
|
||||
pub struct Types<'a> {
|
||||
pub all: OrderedSet<&'a Type>,
|
||||
pub structs: UnorderedMap<&'a Ident, &'a Struct>,
|
||||
pub enums: UnorderedMap<&'a Ident, &'a Enum>,
|
||||
pub cxx: UnorderedSet<&'a Ident>,
|
||||
pub rust: UnorderedSet<&'a Ident>,
|
||||
pub aliases: UnorderedMap<&'a Ident, &'a TypeAlias>,
|
||||
pub untrusted: UnorderedMap<&'a Ident, &'a ExternType>,
|
||||
pub required_trivial: UnorderedMap<&'a Ident, Vec<TrivialReason<'a>>>,
|
||||
pub impls: OrderedMap<ImplKey<'a>, Option<&'a Impl>>,
|
||||
pub resolutions: UnorderedMap<&'a Ident, Resolution<'a>>,
|
||||
pub struct_improper_ctypes: UnorderedSet<&'a Ident>,
|
||||
pub toposorted_structs: Vec<&'a Struct>,
|
||||
}
|
||||
|
||||
impl<'a> Types<'a> {
|
||||
pub fn collect(cx: &mut Errors, apis: &'a [Api]) -> Self {
|
||||
let mut all = OrderedSet::new();
|
||||
let mut structs = UnorderedMap::new();
|
||||
let mut enums = UnorderedMap::new();
|
||||
let mut cxx = UnorderedSet::new();
|
||||
let mut rust = UnorderedSet::new();
|
||||
let mut aliases = UnorderedMap::new();
|
||||
let mut untrusted = UnorderedMap::new();
|
||||
let mut impls = OrderedMap::new();
|
||||
let mut resolutions = UnorderedMap::new();
|
||||
let struct_improper_ctypes = UnorderedSet::new();
|
||||
let toposorted_structs = Vec::new();
|
||||
|
||||
fn visit<'a>(all: &mut OrderedSet<&'a Type>, ty: &'a Type) {
|
||||
struct CollectTypes<'s, 'a>(&'s mut OrderedSet<&'a Type>);
|
||||
|
||||
impl<'s, 'a> Visit<'a> for CollectTypes<'s, 'a> {
|
||||
fn visit_type(&mut self, ty: &'a Type) {
|
||||
self.0.insert(ty);
|
||||
visit::visit_type(self, ty);
|
||||
}
|
||||
}
|
||||
|
||||
CollectTypes(all).visit_type(ty);
|
||||
}
|
||||
|
||||
let mut add_resolution = |name: &'a Pair, generics: &'a Lifetimes| {
|
||||
resolutions.insert(&name.rust, Resolution { name, generics });
|
||||
};
|
||||
|
||||
let mut type_names = UnorderedSet::new();
|
||||
let mut function_names = UnorderedSet::new();
|
||||
for api in apis {
|
||||
// The same identifier is permitted to be declared as both a shared
|
||||
// enum and extern C++ type, or shared struct and extern C++ type.
|
||||
// That indicates to not emit the C++ enum/struct definition because
|
||||
// it's defined by the included headers already.
|
||||
//
|
||||
// All other cases of duplicate identifiers are reported as an error.
|
||||
match api {
|
||||
Api::Include(_) => {}
|
||||
Api::Struct(strct) => {
|
||||
let ident = &strct.name.rust;
|
||||
if !type_names.insert(ident)
|
||||
&& (!cxx.contains(ident)
|
||||
|| structs.contains_key(ident)
|
||||
|| enums.contains_key(ident))
|
||||
{
|
||||
// If already declared as a struct or enum, or if
|
||||
// colliding with something other than an extern C++
|
||||
// type, then error.
|
||||
duplicate_name(cx, strct, ident);
|
||||
}
|
||||
structs.insert(&strct.name.rust, strct);
|
||||
for field in &strct.fields {
|
||||
visit(&mut all, &field.ty);
|
||||
}
|
||||
add_resolution(&strct.name, &strct.generics);
|
||||
}
|
||||
Api::Enum(enm) => {
|
||||
match &enm.repr {
|
||||
EnumRepr::Native { atom: _, repr_type } => {
|
||||
all.insert(repr_type);
|
||||
}
|
||||
#[cfg(feature = "experimental-enum-variants-from-header")]
|
||||
EnumRepr::Foreign { rust_type: _ } => {}
|
||||
}
|
||||
let ident = &enm.name.rust;
|
||||
if !type_names.insert(ident)
|
||||
&& (!cxx.contains(ident)
|
||||
|| structs.contains_key(ident)
|
||||
|| enums.contains_key(ident))
|
||||
{
|
||||
// If already declared as a struct or enum, or if
|
||||
// colliding with something other than an extern C++
|
||||
// type, then error.
|
||||
duplicate_name(cx, enm, ident);
|
||||
}
|
||||
enums.insert(ident, enm);
|
||||
if enm.variants_from_header {
|
||||
// #![variants_from_header] enums are implicitly extern
|
||||
// C++ type.
|
||||
cxx.insert(&enm.name.rust);
|
||||
}
|
||||
add_resolution(&enm.name, &enm.generics);
|
||||
}
|
||||
Api::CxxType(ety) => {
|
||||
let ident = &ety.name.rust;
|
||||
if !type_names.insert(ident)
|
||||
&& (cxx.contains(ident)
|
||||
|| !structs.contains_key(ident) && !enums.contains_key(ident))
|
||||
{
|
||||
// If already declared as an extern C++ type, or if
|
||||
// colliding with something which is neither struct nor
|
||||
// enum, then error.
|
||||
duplicate_name(cx, ety, ident);
|
||||
}
|
||||
cxx.insert(ident);
|
||||
if !ety.trusted {
|
||||
untrusted.insert(ident, ety);
|
||||
}
|
||||
add_resolution(&ety.name, &ety.generics);
|
||||
}
|
||||
Api::RustType(ety) => {
|
||||
let ident = &ety.name.rust;
|
||||
if !type_names.insert(ident) {
|
||||
duplicate_name(cx, ety, ident);
|
||||
}
|
||||
rust.insert(ident);
|
||||
add_resolution(&ety.name, &ety.generics);
|
||||
}
|
||||
Api::CxxFunction(efn) | Api::RustFunction(efn) => {
|
||||
// Note: duplication of the C++ name is fine because C++ has
|
||||
// function overloading.
|
||||
if !function_names.insert((&efn.receiver, &efn.name.rust)) {
|
||||
duplicate_name(cx, efn, &efn.name.rust);
|
||||
}
|
||||
for arg in &efn.args {
|
||||
visit(&mut all, &arg.ty);
|
||||
}
|
||||
if let Some(ret) = &efn.ret {
|
||||
visit(&mut all, ret);
|
||||
}
|
||||
}
|
||||
Api::TypeAlias(alias) => {
|
||||
let ident = &alias.name.rust;
|
||||
if !type_names.insert(ident) {
|
||||
duplicate_name(cx, alias, ident);
|
||||
}
|
||||
cxx.insert(ident);
|
||||
aliases.insert(ident, alias);
|
||||
add_resolution(&alias.name, &alias.generics);
|
||||
}
|
||||
Api::Impl(imp) => {
|
||||
visit(&mut all, &imp.ty);
|
||||
if let Some(key) = imp.ty.impl_key() {
|
||||
impls.insert(key, Some(imp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ty in &all {
|
||||
let impl_key = match ty.impl_key() {
|
||||
Some(impl_key) => impl_key,
|
||||
None => continue,
|
||||
};
|
||||
let implicit_impl = match impl_key {
|
||||
ImplKey::RustBox(ident)
|
||||
| ImplKey::RustVec(ident)
|
||||
| ImplKey::UniquePtr(ident)
|
||||
| ImplKey::SharedPtr(ident)
|
||||
| ImplKey::WeakPtr(ident)
|
||||
| ImplKey::CxxVector(ident) => {
|
||||
Atom::from(ident.rust).is_none() && !aliases.contains_key(ident.rust)
|
||||
}
|
||||
};
|
||||
if implicit_impl && !impls.contains_key(&impl_key) {
|
||||
impls.insert(impl_key, None);
|
||||
}
|
||||
}
|
||||
|
||||
// All these APIs may contain types passed by value. We need to ensure
|
||||
// we check that this is permissible. We do this _after_ scanning all
|
||||
// the APIs above, in case some function or struct references a type
|
||||
// which is declared subsequently.
|
||||
let required_trivial =
|
||||
trivial::required_trivial_reasons(apis, &all, &structs, &enums, &cxx);
|
||||
|
||||
let mut types = Types {
|
||||
all,
|
||||
structs,
|
||||
enums,
|
||||
cxx,
|
||||
rust,
|
||||
aliases,
|
||||
untrusted,
|
||||
required_trivial,
|
||||
impls,
|
||||
resolutions,
|
||||
struct_improper_ctypes,
|
||||
toposorted_structs,
|
||||
};
|
||||
|
||||
types.toposorted_structs = toposort::sort(cx, apis, &types);
|
||||
|
||||
let mut unresolved_structs = types.structs.keys();
|
||||
let mut new_information = true;
|
||||
while new_information {
|
||||
new_information = false;
|
||||
unresolved_structs.retain(|ident| {
|
||||
let mut retain = false;
|
||||
for var in &types.structs[ident].fields {
|
||||
if match types.determine_improper_ctype(&var.ty) {
|
||||
ImproperCtype::Depends(inner) => {
|
||||
retain = true;
|
||||
types.struct_improper_ctypes.contains(inner)
|
||||
}
|
||||
ImproperCtype::Definite(improper) => improper,
|
||||
} {
|
||||
types.struct_improper_ctypes.insert(ident);
|
||||
new_information = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If all fields definite false, remove from unresolved_structs.
|
||||
retain
|
||||
});
|
||||
}
|
||||
|
||||
types
|
||||
}
|
||||
|
||||
pub fn needs_indirect_abi(&self, ty: &Type) -> bool {
|
||||
match ty {
|
||||
Type::RustBox(_) | Type::UniquePtr(_) => false,
|
||||
Type::Array(_) => true,
|
||||
_ => !self.is_guaranteed_pod(ty),
|
||||
}
|
||||
}
|
||||
|
||||
// Types that trigger rustc's default #[warn(improper_ctypes)] lint, even if
|
||||
// they may be otherwise unproblematic to mention in an extern signature.
|
||||
// For example in a signature like `extern "C" fn(*const String)`, rustc
|
||||
// refuses to believe that C could know how to supply us with a pointer to a
|
||||
// Rust String, even though C could easily have obtained that pointer
|
||||
// legitimately from a Rust call.
|
||||
pub fn is_considered_improper_ctype(&self, ty: &Type) -> bool {
|
||||
match self.determine_improper_ctype(ty) {
|
||||
ImproperCtype::Definite(improper) => improper,
|
||||
ImproperCtype::Depends(ident) => self.struct_improper_ctypes.contains(ident),
|
||||
}
|
||||
}
|
||||
|
||||
// Types which we need to assume could possibly exist by value on the Rust
|
||||
// side.
|
||||
pub fn is_maybe_trivial(&self, ty: &Ident) -> bool {
|
||||
self.structs.contains_key(ty)
|
||||
|| self.enums.contains_key(ty)
|
||||
|| self.aliases.contains_key(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t, 'a> IntoIterator for &'t Types<'a> {
|
||||
type Item = &'a Type;
|
||||
type IntoIter = crate::syntax::set::Iter<'t, 'a, Type>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.all.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {
|
||||
let msg = format!("the name `{}` is defined multiple times", ident);
|
||||
cx.error(sp, msg);
|
||||
}
|
||||
34
vendor/cxx-build/src/syntax/visit.rs
vendored
Normal file
34
vendor/cxx-build/src/syntax/visit.rs
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
use crate::syntax::Type;
|
||||
|
||||
pub trait Visit<'a> {
|
||||
fn visit_type(&mut self, ty: &'a Type) {
|
||||
visit_type(self, ty);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn visit_type<'a, V>(visitor: &mut V, ty: &'a Type)
|
||||
where
|
||||
V: Visit<'a> + ?Sized,
|
||||
{
|
||||
match ty {
|
||||
Type::Ident(_) | Type::Str(_) | Type::Void(_) => {}
|
||||
Type::RustBox(ty)
|
||||
| Type::UniquePtr(ty)
|
||||
| Type::SharedPtr(ty)
|
||||
| Type::WeakPtr(ty)
|
||||
| Type::CxxVector(ty)
|
||||
| Type::RustVec(ty) => visitor.visit_type(&ty.inner),
|
||||
Type::Ref(r) => visitor.visit_type(&r.inner),
|
||||
Type::Ptr(p) => visitor.visit_type(&p.inner),
|
||||
Type::Array(a) => visitor.visit_type(&a.inner),
|
||||
Type::SliceRef(s) => visitor.visit_type(&s.inner),
|
||||
Type::Fn(fun) => {
|
||||
if let Some(ret) = &fun.ret {
|
||||
visitor.visit_type(ret);
|
||||
}
|
||||
for arg in &fun.args {
|
||||
visitor.visit_type(&arg.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
49
vendor/cxx-build/src/target.rs
vendored
Normal file
49
vendor/cxx-build/src/target.rs
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub(crate) enum TargetDir {
|
||||
Path(PathBuf),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
pub(crate) fn find_target_dir(out_dir: &Path) -> TargetDir {
|
||||
if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") {
|
||||
let target_dir = PathBuf::from(target_dir);
|
||||
if target_dir.is_absolute() {
|
||||
return TargetDir::Path(target_dir);
|
||||
} else {
|
||||
return TargetDir::Unknown;
|
||||
};
|
||||
}
|
||||
|
||||
// fs::canonicalize on Windows produces UNC paths which cl.exe is unable to
|
||||
// handle in includes.
|
||||
// https://github.com/rust-lang/rust/issues/42869
|
||||
// https://github.com/alexcrichton/cc-rs/issues/169
|
||||
let mut also_try_canonical = cfg!(not(windows));
|
||||
|
||||
let mut dir = out_dir.to_owned();
|
||||
loop {
|
||||
if dir.join(".rustc_info.json").exists()
|
||||
|| dir.join("CACHEDIR.TAG").exists()
|
||||
|| dir.file_name() == Some(OsStr::new("target"))
|
||||
&& dir
|
||||
.parent()
|
||||
.map_or(false, |parent| parent.join("Cargo.toml").exists())
|
||||
{
|
||||
return TargetDir::Path(dir);
|
||||
}
|
||||
if dir.pop() {
|
||||
continue;
|
||||
}
|
||||
if also_try_canonical {
|
||||
if let Ok(canonical_dir) = out_dir.canonicalize() {
|
||||
dir = canonical_dir;
|
||||
also_try_canonical = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return TargetDir::Unknown;
|
||||
}
|
||||
}
|
||||
50
vendor/cxx-build/src/vec.rs
vendored
Normal file
50
vendor/cxx-build/src/vec.rs
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use crate::intern::{self, InternedString};
|
||||
use std::path::Path;
|
||||
|
||||
pub trait InternedVec<T>
|
||||
where
|
||||
T: ?Sized,
|
||||
{
|
||||
fn vec(&self) -> Vec<&'static T>;
|
||||
}
|
||||
|
||||
impl<T> InternedVec<T> for Vec<InternedString>
|
||||
where
|
||||
T: ?Sized + Element,
|
||||
{
|
||||
fn vec(&self) -> Vec<&'static T> {
|
||||
self.iter().copied().map(Element::unintern).collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intern<T>(elements: &[&T]) -> Vec<InternedString>
|
||||
where
|
||||
T: ?Sized + Element,
|
||||
{
|
||||
elements.iter().copied().map(Element::intern).collect()
|
||||
}
|
||||
|
||||
pub trait Element {
|
||||
fn intern(&self) -> InternedString;
|
||||
fn unintern(_: InternedString) -> &'static Self;
|
||||
}
|
||||
|
||||
impl Element for str {
|
||||
fn intern(&self) -> InternedString {
|
||||
intern::intern(self)
|
||||
}
|
||||
|
||||
fn unintern(interned: InternedString) -> &'static Self {
|
||||
interned.str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for Path {
|
||||
fn intern(&self) -> InternedString {
|
||||
intern::intern(&self.to_string_lossy())
|
||||
}
|
||||
|
||||
fn unintern(interned: InternedString) -> &'static Self {
|
||||
Path::new(interned.str())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue