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/cxxbridge-macro/.cargo-checksum.json
vendored
Normal file
1
vendor/cxxbridge-macro/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"0be1acfa0e5ade7db052e363cb204a4a9293897ce2b9cec6bf2636e616c43c7b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","src/clang.rs":"c80e15e0423d405d4cf0e436db08f804dfc47b185b534e270ad3029687d3872f","src/derive.rs":"38ccd4642486d1ae94695d8a364d0df5e8c88218923712da298cd29889251b65","src/expand.rs":"c257cfbbc805113dac07ef464bfd188d796477912125ea31299dc24e6df699c6","src/generics.rs":"128aeaac4de300361dc97f0fd89c803cc55a2cc5a4c3ddf54515eb5bf4f5696b","src/lib.rs":"ce1f594783033e2ddd92970bccaa77f038bcd12d396d094113b37403730ddbef","src/load.rs":"4c0ff4ae075a06824d1411dff9297539727396148ca5d77a0a18a855bc1f9b97","src/syntax/atom.rs":"a289630b603f615f79156627a8498d795b9b388d241a318b0e2be530e879cd37","src/syntax/attrs.rs":"7a6725b7e458980f0e18c9828f03d42dc186d9fec7ca2273dcf409ab47263f75","src/syntax/cfg.rs":"a329854326108bc97509e213d363ef516baed7420696ad85ba6a25590295d11b","src/syntax/check.rs":"a4368b03ac9d1d36b3d4605ac350eb96910e9da5d44eb177df299f96e2b4b13f","src/syntax/derive.rs":"004f4aea489955c1b5a72f6fb2106a1d12df874420d2e0d103a202821c5f75db","src/syntax/discriminant.rs":"1b73eadd935d86f11cf1bf6d06d9de77167042e1ce3e574fe231d0897a623045","src/syntax/doc.rs":"a8aca64ee87a220da603ef9f78c1556ecc9b1991032d1d9fc49349b00ed15e51","src/syntax/error.rs":"04f1628b32bc1152a332a7e0c4d72b23acddd313c41069e47aae98a19e13a4dd","src/syntax/file.rs":"43a17146a5b8571d6c7aebdf606ceaedcd4fafd3c296b98c8a697071cf35701c","src/syntax/ident.rs":"a7804ff658cccebedc8e95b714c5738672c671e0c4c741625b750d7542ca258d","src/syntax/impls.rs":"9bab5656bec90cafc6ff488d6ea5c8aeced32737b0a244be6f9873207039d190","src/syntax/improper.rs":"280735758913534c71a811759aaf3a5b514f6ed3634c65c5d3b43e6e5bdfe2f6","src/syntax/instantiate.rs":"55fb1aeccdbd7f449410962eb454f9f5ce9f4b8d1d4724e77772e3c4c95b2d71","src/syntax/mangle.rs":"51db2c2528759d224b26e49619d3f0f188531c1d0944df0775607f4dcdef645b","src/syntax/map.rs":"fc4dfa0270063d221c682c94bdeb56359cdc3241f605e28a103f87ad59813265","src/syntax/mod.rs":"9a6338892cdd67b5fdb7944a6a92f61b7ccf79274e629da8ed3af99623ed31de","src/syntax/names.rs":"6938e960790331cd356ebb347057de3a319a03cc2ee382a975b22747324585e1","src/syntax/namespace.rs":"67408e0ab90979165e19de7a5fd557b2df2b97d127f37879ef1812c97f98e15b","src/syntax/parse.rs":"4d776a33d35715de27a36ab5cd235f7076a75627f4631894b607f491d360bd3f","src/syntax/pod.rs":"82c0171f90e289615184cf98f86bf814855f81c9b7ecd20d5b54ece4c57b8599","src/syntax/qualified.rs":"86e49af8d3ae46489fa37ff08358e001cf5345503f6c03becec36b88984d678d","src/syntax/report.rs":"e6c35148802a1581ad1204d34f49a40f9dca9f0b863bd3d9b56389a63fba1969","src/syntax/resolve.rs":"6a25e3cdaf9176cf72de6ced354a2d941d11ab36fe7d2afca51ec707034a1819","src/syntax/set.rs":"6440cd155cd2c5cd36becb76456f74ab14f83f108b0e12555860c7b778e8a0d2","src/syntax/symbol.rs":"045e685ca33192dd73bb995a2e4cda0a4b8f37ae90674d142a1994bba43baf03","src/syntax/tokens.rs":"ce7ca8a560ec79264cc1bb49d9b00cf6e059bc0c7463dfed7607478c596a34bc","src/syntax/toposort.rs":"1ff97c49743369808bd866d176759bd7939b2b4afc31ffea65929d1e2ccc611d","src/syntax/trivial.rs":"3e47542b526ae74ccab254040499ff6c5cdd11e309ee3d7e8857b92f6be2e5ee","src/syntax/types.rs":"89686498d1d14ffe843795ad54933363f6019d1063c74b519dcf3890bd24272c","src/syntax/visit.rs":"35ff95ed4e13a463531694d7c78199ad83249d7ba3dd8984e591b26f39b1eb3b","src/tokens.rs":"c9bac9556260005bf5dc9faddbf04fb512e1665276dfd3846335638aa3337c53","src/type_id.rs":"5517bc0da5d9dc469c126bd3e47e383f0a29dc28c7fae30e8243789b65eabde9"},"package":"3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"}
|
||||
78
vendor/cxxbridge-macro/Cargo.toml
vendored
Normal file
78
vendor/cxxbridge-macro/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# 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 = "cxxbridge-macro"
|
||||
version = "1.0.85"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
exclude = [
|
||||
"build.rs",
|
||||
"README.md",
|
||||
]
|
||||
description = "Implementation detail of the `cxx` crate."
|
||||
homepage = "https://cxx.rs"
|
||||
readme = "README.md"
|
||||
keywords = ["ffi"]
|
||||
categories = ["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]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.clang-ast]
|
||||
version = "0.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.flate2]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.memmap]
|
||||
version = "0.7"
|
||||
optional = true
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0.39"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
|
||||
[dependencies.serde_json]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.syn]
|
||||
version = "1.0.95"
|
||||
features = ["full"]
|
||||
|
||||
[dev-dependencies.cxx]
|
||||
version = "1.0"
|
||||
|
||||
[features]
|
||||
experimental-async-fn = []
|
||||
experimental-enum-variants-from-header = [
|
||||
"clang-ast",
|
||||
"flate2",
|
||||
"memmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
201
vendor/cxxbridge-macro/LICENSE-APACHE
vendored
Normal file
201
vendor/cxxbridge-macro/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/cxxbridge-macro/LICENSE-MIT
vendored
Normal file
23
vendor/cxxbridge-macro/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.
|
||||
51
vendor/cxxbridge-macro/src/clang.rs
vendored
Normal file
51
vendor/cxxbridge-macro/src/clang.rs
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type Node = clang_ast::Node<Clang>;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum Clang {
|
||||
NamespaceDecl(NamespaceDecl),
|
||||
EnumDecl(EnumDecl),
|
||||
EnumConstantDecl(EnumConstantDecl),
|
||||
ImplicitCastExpr,
|
||||
ConstantExpr(ConstantExpr),
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct NamespaceDecl {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<Box<str>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct EnumDecl {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<Box<str>>,
|
||||
#[serde(
|
||||
rename = "fixedUnderlyingType",
|
||||
skip_serializing_if = "Option::is_none"
|
||||
)]
|
||||
pub fixed_underlying_type: Option<Type>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct EnumConstantDecl {
|
||||
pub name: Box<str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ConstantExpr {
|
||||
pub value: Box<str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct Type {
|
||||
#[serde(rename = "qualType")]
|
||||
pub qual_type: Box<str>,
|
||||
#[serde(rename = "desugaredQualType", skip_serializing_if = "Option::is_none")]
|
||||
pub desugared_qual_type: Option<Box<str>>,
|
||||
}
|
||||
|
||||
#[cfg(all(test, target_pointer_width = "64"))]
|
||||
const _: [(); core::mem::size_of::<Node>()] = [(); 88];
|
||||
286
vendor/cxxbridge-macro/src/derive.rs
vendored
Normal file
286
vendor/cxxbridge-macro/src/derive.rs
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
use crate::syntax::{derive, Enum, Struct, Trait};
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
|
||||
pub use crate::syntax::derive::*;
|
||||
|
||||
pub fn expand_struct(strct: &Struct, actual_derives: &mut Option<TokenStream>) -> TokenStream {
|
||||
let mut expanded = TokenStream::new();
|
||||
let mut traits = Vec::new();
|
||||
|
||||
for derive in &strct.derives {
|
||||
let span = derive.span;
|
||||
match derive.what {
|
||||
Trait::Copy => expanded.extend(struct_copy(strct, span)),
|
||||
Trait::Clone => expanded.extend(struct_clone(strct, span)),
|
||||
Trait::Debug => expanded.extend(struct_debug(strct, span)),
|
||||
Trait::Default => expanded.extend(struct_default(strct, span)),
|
||||
Trait::Eq => traits.push(quote_spanned!(span=> ::cxx::core::cmp::Eq)),
|
||||
Trait::ExternType => unreachable!(),
|
||||
Trait::Hash => traits.push(quote_spanned!(span=> ::cxx::core::hash::Hash)),
|
||||
Trait::Ord => expanded.extend(struct_ord(strct, span)),
|
||||
Trait::PartialEq => traits.push(quote_spanned!(span=> ::cxx::core::cmp::PartialEq)),
|
||||
Trait::PartialOrd => expanded.extend(struct_partial_ord(strct, span)),
|
||||
Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)),
|
||||
Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)),
|
||||
}
|
||||
}
|
||||
|
||||
if traits.is_empty() {
|
||||
*actual_derives = None;
|
||||
} else {
|
||||
*actual_derives = Some(quote!(#[derive(#(#traits),*)]));
|
||||
}
|
||||
|
||||
expanded
|
||||
}
|
||||
|
||||
pub fn expand_enum(enm: &Enum, actual_derives: &mut Option<TokenStream>) -> TokenStream {
|
||||
let mut expanded = TokenStream::new();
|
||||
let mut traits = Vec::new();
|
||||
let mut has_copy = false;
|
||||
let mut has_clone = false;
|
||||
let mut has_eq = false;
|
||||
let mut has_partial_eq = false;
|
||||
|
||||
for derive in &enm.derives {
|
||||
let span = derive.span;
|
||||
match derive.what {
|
||||
Trait::Copy => {
|
||||
expanded.extend(enum_copy(enm, span));
|
||||
has_copy = true;
|
||||
}
|
||||
Trait::Clone => {
|
||||
expanded.extend(enum_clone(enm, span));
|
||||
has_clone = true;
|
||||
}
|
||||
Trait::Debug => expanded.extend(enum_debug(enm, span)),
|
||||
Trait::Default => unreachable!(),
|
||||
Trait::Eq => {
|
||||
traits.push(quote_spanned!(span=> ::cxx::core::cmp::Eq));
|
||||
has_eq = true;
|
||||
}
|
||||
Trait::ExternType => unreachable!(),
|
||||
Trait::Hash => traits.push(quote_spanned!(span=> ::cxx::core::hash::Hash)),
|
||||
Trait::Ord => expanded.extend(enum_ord(enm, span)),
|
||||
Trait::PartialEq => {
|
||||
traits.push(quote_spanned!(span=> ::cxx::core::cmp::PartialEq));
|
||||
has_partial_eq = true;
|
||||
}
|
||||
Trait::PartialOrd => expanded.extend(enum_partial_ord(enm, span)),
|
||||
Trait::Serialize => traits.push(quote_spanned!(span=> ::serde::Serialize)),
|
||||
Trait::Deserialize => traits.push(quote_spanned!(span=> ::serde::Deserialize)),
|
||||
}
|
||||
}
|
||||
|
||||
let span = enm.name.rust.span();
|
||||
if !has_copy {
|
||||
expanded.extend(enum_copy(enm, span));
|
||||
}
|
||||
if !has_clone {
|
||||
expanded.extend(enum_clone(enm, span));
|
||||
}
|
||||
if !has_eq {
|
||||
// Required to be derived in order for the enum's "variants" to be
|
||||
// usable in patterns.
|
||||
traits.push(quote!(::cxx::core::cmp::Eq));
|
||||
}
|
||||
if !has_partial_eq {
|
||||
traits.push(quote!(::cxx::core::cmp::PartialEq));
|
||||
}
|
||||
|
||||
*actual_derives = Some(quote!(#[derive(#(#traits),*)]));
|
||||
|
||||
expanded
|
||||
}
|
||||
|
||||
fn struct_copy(strct: &Struct, span: Span) -> TokenStream {
|
||||
let ident = &strct.name.rust;
|
||||
let generics = &strct.generics;
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl #generics ::cxx::core::marker::Copy for #ident #generics {}
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_clone(strct: &Struct, span: Span) -> TokenStream {
|
||||
let ident = &strct.name.rust;
|
||||
let generics = &strct.generics;
|
||||
|
||||
let body = if derive::contains(&strct.derives, Trait::Copy) {
|
||||
quote!(*self)
|
||||
} else {
|
||||
let fields = strct.fields.iter().map(|field| &field.name.rust);
|
||||
let values = strct.fields.iter().map(|field| {
|
||||
let ident = &field.name.rust;
|
||||
let ty = field.ty.to_token_stream();
|
||||
let span = ty.into_iter().last().unwrap().span();
|
||||
quote_spanned!(span=> &self.#ident)
|
||||
});
|
||||
quote_spanned!(span=> #ident {
|
||||
#(#fields: ::cxx::core::clone::Clone::clone(#values),)*
|
||||
})
|
||||
};
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl #generics ::cxx::core::clone::Clone for #ident #generics {
|
||||
fn clone(&self) -> Self {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_debug(strct: &Struct, span: Span) -> TokenStream {
|
||||
let ident = &strct.name.rust;
|
||||
let generics = &strct.generics;
|
||||
let struct_name = ident.to_string();
|
||||
let fields = strct.fields.iter().map(|field| &field.name.rust);
|
||||
let field_names = fields.clone().map(Ident::to_string);
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl #generics ::cxx::core::fmt::Debug for #ident #generics {
|
||||
fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
|
||||
formatter.debug_struct(#struct_name)
|
||||
#(.field(#field_names, &self.#fields))*
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_default(strct: &Struct, span: Span) -> TokenStream {
|
||||
let ident = &strct.name.rust;
|
||||
let generics = &strct.generics;
|
||||
let fields = strct.fields.iter().map(|field| &field.name.rust);
|
||||
|
||||
quote_spanned! {span=>
|
||||
#[allow(clippy::derivable_impls)] // different spans than the derived impl
|
||||
impl #generics ::cxx::core::default::Default for #ident #generics {
|
||||
fn default() -> Self {
|
||||
#ident {
|
||||
#(
|
||||
#fields: ::cxx::core::default::Default::default(),
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_ord(strct: &Struct, span: Span) -> TokenStream {
|
||||
let ident = &strct.name.rust;
|
||||
let generics = &strct.generics;
|
||||
let fields = strct.fields.iter().map(|field| &field.name.rust);
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl #generics ::cxx::core::cmp::Ord for #ident #generics {
|
||||
fn cmp(&self, other: &Self) -> ::cxx::core::cmp::Ordering {
|
||||
#(
|
||||
match ::cxx::core::cmp::Ord::cmp(&self.#fields, &other.#fields) {
|
||||
::cxx::core::cmp::Ordering::Equal => {}
|
||||
ordering => return ordering,
|
||||
}
|
||||
)*
|
||||
::cxx::core::cmp::Ordering::Equal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_partial_ord(strct: &Struct, span: Span) -> TokenStream {
|
||||
let ident = &strct.name.rust;
|
||||
let generics = &strct.generics;
|
||||
|
||||
let body = if derive::contains(&strct.derives, Trait::Ord) {
|
||||
quote! {
|
||||
::cxx::core::option::Option::Some(::cxx::core::cmp::Ord::cmp(self, other))
|
||||
}
|
||||
} else {
|
||||
let fields = strct.fields.iter().map(|field| &field.name.rust);
|
||||
quote! {
|
||||
#(
|
||||
match ::cxx::core::cmp::PartialOrd::partial_cmp(&self.#fields, &other.#fields) {
|
||||
::cxx::core::option::Option::Some(::cxx::core::cmp::Ordering::Equal) => {}
|
||||
ordering => return ordering,
|
||||
}
|
||||
)*
|
||||
::cxx::core::option::Option::Some(::cxx::core::cmp::Ordering::Equal)
|
||||
}
|
||||
};
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl #generics ::cxx::core::cmp::PartialOrd for #ident #generics {
|
||||
fn partial_cmp(&self, other: &Self) -> ::cxx::core::option::Option<::cxx::core::cmp::Ordering> {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_copy(enm: &Enum, span: Span) -> TokenStream {
|
||||
let ident = &enm.name.rust;
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl ::cxx::core::marker::Copy for #ident {}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_clone(enm: &Enum, span: Span) -> TokenStream {
|
||||
let ident = &enm.name.rust;
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl ::cxx::core::clone::Clone for #ident {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_debug(enm: &Enum, span: Span) -> TokenStream {
|
||||
let ident = &enm.name.rust;
|
||||
let variants = enm.variants.iter().map(|variant| {
|
||||
let variant = &variant.name.rust;
|
||||
let name = variant.to_string();
|
||||
quote_spanned! {span=>
|
||||
#ident::#variant => formatter.write_str(#name),
|
||||
}
|
||||
});
|
||||
let fallback = format!("{}({{}})", ident);
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl ::cxx::core::fmt::Debug for #ident {
|
||||
fn fmt(&self, formatter: &mut ::cxx::core::fmt::Formatter<'_>) -> ::cxx::core::fmt::Result {
|
||||
match *self {
|
||||
#(#variants)*
|
||||
_ => ::cxx::core::write!(formatter, #fallback, self.repr),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_ord(enm: &Enum, span: Span) -> TokenStream {
|
||||
let ident = &enm.name.rust;
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl ::cxx::core::cmp::Ord for #ident {
|
||||
fn cmp(&self, other: &Self) -> ::cxx::core::cmp::Ordering {
|
||||
::cxx::core::cmp::Ord::cmp(&self.repr, &other.repr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_partial_ord(enm: &Enum, span: Span) -> TokenStream {
|
||||
let ident = &enm.name.rust;
|
||||
|
||||
quote_spanned! {span=>
|
||||
impl ::cxx::core::cmp::PartialOrd for #ident {
|
||||
fn partial_cmp(&self, other: &Self) -> ::cxx::core::option::Option<::cxx::core::cmp::Ordering> {
|
||||
::cxx::core::cmp::PartialOrd::partial_cmp(&self.repr, &other.repr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1819
vendor/cxxbridge-macro/src/expand.rs
vendored
Normal file
1819
vendor/cxxbridge-macro/src/expand.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
91
vendor/cxxbridge-macro/src/generics.rs
vendored
Normal file
91
vendor/cxxbridge-macro/src/generics.rs
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
use crate::syntax::instantiate::NamedImplKey;
|
||||
use crate::syntax::resolve::Resolution;
|
||||
use crate::syntax::{Impl, Lifetimes};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{Lifetime, Token};
|
||||
|
||||
pub struct ImplGenerics<'a> {
|
||||
explicit_impl: Option<&'a Impl>,
|
||||
resolve: Resolution<'a>,
|
||||
}
|
||||
|
||||
pub struct TyGenerics<'a> {
|
||||
key: NamedImplKey<'a>,
|
||||
explicit_impl: Option<&'a Impl>,
|
||||
resolve: Resolution<'a>,
|
||||
}
|
||||
|
||||
pub fn split_for_impl<'a>(
|
||||
key: NamedImplKey<'a>,
|
||||
explicit_impl: Option<&'a Impl>,
|
||||
resolve: Resolution<'a>,
|
||||
) -> (ImplGenerics<'a>, TyGenerics<'a>) {
|
||||
let impl_generics = ImplGenerics {
|
||||
explicit_impl,
|
||||
resolve,
|
||||
};
|
||||
let ty_generics = TyGenerics {
|
||||
key,
|
||||
explicit_impl,
|
||||
resolve,
|
||||
};
|
||||
(impl_generics, ty_generics)
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for ImplGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
if let Some(imp) = self.explicit_impl {
|
||||
imp.impl_generics.to_tokens(tokens);
|
||||
} else {
|
||||
self.resolve.generics.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for TyGenerics<'a> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
if let Some(imp) = self.explicit_impl {
|
||||
imp.ty_generics.to_tokens(tokens);
|
||||
} else if !self.resolve.generics.lifetimes.is_empty() {
|
||||
let span = self.key.rust.span();
|
||||
self.key
|
||||
.lt_token
|
||||
.unwrap_or_else(|| Token)
|
||||
.to_tokens(tokens);
|
||||
self.resolve.generics.lifetimes.to_tokens(tokens);
|
||||
self.key
|
||||
.gt_token
|
||||
.unwrap_or_else(|| Token)
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UnderscoreLifetimes<'a> {
|
||||
generics: &'a Lifetimes,
|
||||
}
|
||||
|
||||
impl Lifetimes {
|
||||
pub fn to_underscore_lifetimes(&self) -> UnderscoreLifetimes {
|
||||
UnderscoreLifetimes { generics: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToTokens for UnderscoreLifetimes<'a> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Lifetimes {
|
||||
lt_token,
|
||||
lifetimes,
|
||||
gt_token,
|
||||
} = self.generics;
|
||||
lt_token.to_tokens(tokens);
|
||||
for pair in lifetimes.pairs() {
|
||||
let (lifetime, punct) = pair.into_tuple();
|
||||
let lifetime = Lifetime::new("'_", lifetime.span());
|
||||
lifetime.to_tokens(tokens);
|
||||
punct.to_tokens(tokens);
|
||||
}
|
||||
gt_token.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
105
vendor/cxxbridge-macro/src/lib.rs
vendored
Normal file
105
vendor/cxxbridge-macro/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#![allow(
|
||||
clippy::cast_sign_loss,
|
||||
clippy::default_trait_access,
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::doc_markdown,
|
||||
clippy::enum_glob_use,
|
||||
clippy::if_same_then_else,
|
||||
clippy::inherent_to_string,
|
||||
clippy::items_after_statements,
|
||||
clippy::large_enum_variant,
|
||||
clippy::match_bool,
|
||||
clippy::match_same_arms,
|
||||
clippy::module_name_repetitions,
|
||||
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::similar_names,
|
||||
clippy::single_match,
|
||||
clippy::single_match_else,
|
||||
clippy::too_many_arguments,
|
||||
clippy::too_many_lines,
|
||||
clippy::toplevel_ref_arg,
|
||||
clippy::useless_let_if_seq,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6983
|
||||
clippy::wrong_self_convention
|
||||
)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
mod derive;
|
||||
mod expand;
|
||||
mod generics;
|
||||
mod syntax;
|
||||
mod tokens;
|
||||
mod type_id;
|
||||
|
||||
#[cfg(feature = "experimental-enum-variants-from-header")]
|
||||
mod clang;
|
||||
#[cfg(feature = "experimental-enum-variants-from-header")]
|
||||
mod load;
|
||||
|
||||
use crate::syntax::file::Module;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::qualified::QualifiedName;
|
||||
use crate::type_id::Crate;
|
||||
use proc_macro::TokenStream;
|
||||
use syn::parse::{Parse, ParseStream, Parser, Result};
|
||||
use syn::parse_macro_input;
|
||||
|
||||
/// `#[cxx::bridge] mod ffi { ... }`
|
||||
///
|
||||
/// Refer to the crate-level documentation for the explanation of how this macro
|
||||
/// is intended to be used.
|
||||
///
|
||||
/// The only additional thing to note here is namespace support — if the
|
||||
/// types and functions on the `extern "C++"` side of our bridge are in a
|
||||
/// namespace, specify that namespace as an argument of the cxx::bridge
|
||||
/// attribute macro.
|
||||
///
|
||||
/// ```
|
||||
/// #[cxx::bridge(namespace = "mycompany::rust")]
|
||||
/// # mod ffi {}
|
||||
/// ```
|
||||
///
|
||||
/// The types and functions from the `extern "Rust"` side of the bridge will be
|
||||
/// placed into that same namespace in the generated C++ code.
|
||||
#[proc_macro_attribute]
|
||||
pub fn bridge(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let _ = syntax::error::ERRORS;
|
||||
|
||||
let namespace = match Namespace::parse_bridge_attr_namespace.parse(args) {
|
||||
Ok(namespace) => namespace,
|
||||
Err(err) => return err.to_compile_error().into(),
|
||||
};
|
||||
let mut ffi = parse_macro_input!(input as Module);
|
||||
ffi.namespace = namespace;
|
||||
|
||||
expand::bridge(ffi)
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[proc_macro]
|
||||
pub fn type_id(input: TokenStream) -> TokenStream {
|
||||
struct TypeId {
|
||||
krate: Crate,
|
||||
path: QualifiedName,
|
||||
}
|
||||
|
||||
impl Parse for TypeId {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let krate = input.parse().map(Crate::DollarCrate)?;
|
||||
let path = QualifiedName::parse_quoted_or_unquoted(input)?;
|
||||
Ok(TypeId { krate, path })
|
||||
}
|
||||
}
|
||||
|
||||
let arg = parse_macro_input!(input as TypeId);
|
||||
type_id::expand(arg.krate, arg.path).into()
|
||||
}
|
||||
317
vendor/cxxbridge-macro/src/load.rs
vendored
Normal file
317
vendor/cxxbridge-macro/src/load.rs
vendored
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
use crate::clang::{Clang, Node};
|
||||
use crate::syntax::attrs::OtherAttrs;
|
||||
use crate::syntax::cfg::CfgExpr;
|
||||
use crate::syntax::namespace::Namespace;
|
||||
use crate::syntax::report::Errors;
|
||||
use crate::syntax::{Api, Discriminant, Doc, Enum, EnumRepr, ForeignName, Pair, Variant};
|
||||
use flate2::write::GzDecoder;
|
||||
use memmap::Mmap;
|
||||
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use std::env;
|
||||
use std::fmt::{self, Display};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use syn::{parse_quote, Path};
|
||||
|
||||
const CXX_CLANG_AST: &str = "CXX_CLANG_AST";
|
||||
|
||||
pub fn load(cx: &mut Errors, apis: &mut [Api]) {
|
||||
let ref mut variants_from_header = Vec::new();
|
||||
for api in apis {
|
||||
if let Api::Enum(enm) = api {
|
||||
if enm.variants_from_header {
|
||||
if enm.variants.is_empty() {
|
||||
variants_from_header.push(enm);
|
||||
} else {
|
||||
let span = span_for_enum_error(enm);
|
||||
cx.error(
|
||||
span,
|
||||
"enum with #![variants_from_header] must be written with no explicit variants",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let span = match variants_from_header.get(0) {
|
||||
None => return,
|
||||
Some(enm) => enm.variants_from_header_attr.clone().unwrap(),
|
||||
};
|
||||
|
||||
let ast_dump_path = match env::var_os(CXX_CLANG_AST) {
|
||||
Some(ast_dump_path) => PathBuf::from(ast_dump_path),
|
||||
None => {
|
||||
let msg = format!(
|
||||
"environment variable ${} has not been provided",
|
||||
CXX_CLANG_AST,
|
||||
);
|
||||
return cx.error(span, msg);
|
||||
}
|
||||
};
|
||||
|
||||
let memmap = File::open(&ast_dump_path).and_then(|file| unsafe { Mmap::map(&file) });
|
||||
let mut gunzipped;
|
||||
let ast_dump_bytes = match match memmap {
|
||||
Ok(ref memmap) => {
|
||||
let is_gzipped = memmap.get(..2) == Some(b"\x1f\x8b");
|
||||
if is_gzipped {
|
||||
gunzipped = Vec::new();
|
||||
let decode_result = GzDecoder::new(&mut gunzipped).write_all(memmap);
|
||||
decode_result.map(|_| gunzipped.as_slice())
|
||||
} else {
|
||||
Ok(memmap as &[u8])
|
||||
}
|
||||
}
|
||||
Err(error) => Err(error),
|
||||
} {
|
||||
Ok(bytes) => bytes,
|
||||
Err(error) => {
|
||||
let msg = format!("failed to read {}: {}", ast_dump_path.display(), error);
|
||||
return cx.error(span, msg);
|
||||
}
|
||||
};
|
||||
|
||||
let ref root: Node = match serde_json::from_slice(ast_dump_bytes) {
|
||||
Ok(root) => root,
|
||||
Err(error) => {
|
||||
let msg = format!("failed to read {}: {}", ast_dump_path.display(), error);
|
||||
return cx.error(span, msg);
|
||||
}
|
||||
};
|
||||
|
||||
let ref mut namespace = Vec::new();
|
||||
traverse(cx, root, namespace, variants_from_header, None);
|
||||
|
||||
for enm in variants_from_header {
|
||||
if enm.variants.is_empty() {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let name = CxxName(&enm.name);
|
||||
let msg = format!("failed to find any C++ definition of enum {}", name);
|
||||
cx.error(span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn traverse<'a>(
|
||||
cx: &mut Errors,
|
||||
node: &'a Node,
|
||||
namespace: &mut Vec<&'a str>,
|
||||
variants_from_header: &mut [&mut Enum],
|
||||
mut idx: Option<usize>,
|
||||
) {
|
||||
match &node.kind {
|
||||
Clang::NamespaceDecl(decl) => {
|
||||
let name = match &decl.name {
|
||||
Some(name) => name,
|
||||
// Can ignore enums inside an anonymous namespace.
|
||||
None => return,
|
||||
};
|
||||
namespace.push(name);
|
||||
idx = None;
|
||||
}
|
||||
Clang::EnumDecl(decl) => {
|
||||
let name = match &decl.name {
|
||||
Some(name) => name,
|
||||
None => return,
|
||||
};
|
||||
idx = None;
|
||||
for (i, enm) in variants_from_header.iter_mut().enumerate() {
|
||||
if enm.name.cxx == **name && enm.name.namespace.iter().eq(&*namespace) {
|
||||
if !enm.variants.is_empty() {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let qual_name = CxxName(&enm.name);
|
||||
let msg = format!("found multiple C++ definitions of enum {}", qual_name);
|
||||
cx.error(span, msg);
|
||||
return;
|
||||
}
|
||||
let fixed_underlying_type = match &decl.fixed_underlying_type {
|
||||
Some(fixed_underlying_type) => fixed_underlying_type,
|
||||
None => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let name = &enm.name.cxx;
|
||||
let qual_name = CxxName(&enm.name);
|
||||
let msg = format!(
|
||||
"implicit implementation-defined repr for enum {} is not supported yet; consider changing its C++ definition to `enum {}: int {{...}}",
|
||||
qual_name, name,
|
||||
);
|
||||
cx.error(span, msg);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let repr = translate_qual_type(
|
||||
cx,
|
||||
enm,
|
||||
fixed_underlying_type
|
||||
.desugared_qual_type
|
||||
.as_ref()
|
||||
.unwrap_or(&fixed_underlying_type.qual_type),
|
||||
);
|
||||
enm.repr = EnumRepr::Foreign { rust_type: repr };
|
||||
idx = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if idx.is_none() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Clang::EnumConstantDecl(decl) => {
|
||||
if let Some(idx) = idx {
|
||||
let enm = &mut *variants_from_header[idx];
|
||||
let span = enm
|
||||
.variants_from_header_attr
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.path
|
||||
.get_ident()
|
||||
.unwrap()
|
||||
.span();
|
||||
let cxx_name = match ForeignName::parse(&decl.name, span) {
|
||||
Ok(foreign_name) => foreign_name,
|
||||
Err(_) => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let msg = format!("unsupported C++ variant name: {}", decl.name);
|
||||
return cx.error(span, msg);
|
||||
}
|
||||
};
|
||||
let rust_name: Ident = match syn::parse_str(&decl.name) {
|
||||
Ok(ident) => ident,
|
||||
Err(_) => format_ident!("__Variant{}", enm.variants.len()),
|
||||
};
|
||||
let discriminant = match discriminant_value(&node.inner) {
|
||||
ParsedDiscriminant::Constant(discriminant) => discriminant,
|
||||
ParsedDiscriminant::Successor => match enm.variants.last() {
|
||||
None => Discriminant::zero(),
|
||||
Some(last) => match last.discriminant.checked_succ() {
|
||||
Some(discriminant) => discriminant,
|
||||
None => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let msg = format!(
|
||||
"overflow processing discriminant value for variant: {}",
|
||||
decl.name,
|
||||
);
|
||||
return cx.error(span, msg);
|
||||
}
|
||||
},
|
||||
},
|
||||
ParsedDiscriminant::Fail => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let msg = format!(
|
||||
"failed to obtain discriminant value for variant: {}",
|
||||
decl.name,
|
||||
);
|
||||
cx.error(span, msg);
|
||||
Discriminant::zero()
|
||||
}
|
||||
};
|
||||
enm.variants.push(Variant {
|
||||
cfg: CfgExpr::Unconditional,
|
||||
doc: Doc::new(),
|
||||
attrs: OtherAttrs::none(),
|
||||
name: Pair {
|
||||
namespace: Namespace::ROOT,
|
||||
cxx: cxx_name,
|
||||
rust: rust_name,
|
||||
},
|
||||
discriminant,
|
||||
expr: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
for inner in &node.inner {
|
||||
traverse(cx, inner, namespace, variants_from_header, idx);
|
||||
}
|
||||
if let Clang::NamespaceDecl(_) = &node.kind {
|
||||
let _ = namespace.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_qual_type(cx: &mut Errors, enm: &Enum, qual_type: &str) -> Path {
|
||||
let rust_std_name = match qual_type {
|
||||
"char" => "c_char",
|
||||
"int" => "c_int",
|
||||
"long" => "c_long",
|
||||
"long long" => "c_longlong",
|
||||
"signed char" => "c_schar",
|
||||
"short" => "c_short",
|
||||
"unsigned char" => "c_uchar",
|
||||
"unsigned int" => "c_uint",
|
||||
"unsigned long" => "c_ulong",
|
||||
"unsigned long long" => "c_ulonglong",
|
||||
"unsigned short" => "c_ushort",
|
||||
unsupported => {
|
||||
let span = &enm.variants_from_header_attr;
|
||||
let qual_name = CxxName(&enm.name);
|
||||
let msg = format!(
|
||||
"unsupported underlying type for {}: {}",
|
||||
qual_name, unsupported,
|
||||
);
|
||||
cx.error(span, msg);
|
||||
"c_int"
|
||||
}
|
||||
};
|
||||
let span = enm
|
||||
.variants_from_header_attr
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.path
|
||||
.get_ident()
|
||||
.unwrap()
|
||||
.span();
|
||||
let ident = Ident::new(rust_std_name, span);
|
||||
let path = quote_spanned!(span=> ::cxx::core::ffi::#ident);
|
||||
parse_quote!(#path)
|
||||
}
|
||||
|
||||
enum ParsedDiscriminant {
|
||||
Constant(Discriminant),
|
||||
Successor,
|
||||
Fail,
|
||||
}
|
||||
|
||||
fn discriminant_value(mut clang: &[Node]) -> ParsedDiscriminant {
|
||||
if clang.is_empty() {
|
||||
// No discriminant expression provided; use successor of previous
|
||||
// descriminant.
|
||||
return ParsedDiscriminant::Successor;
|
||||
}
|
||||
|
||||
loop {
|
||||
if clang.len() != 1 {
|
||||
return ParsedDiscriminant::Fail;
|
||||
}
|
||||
|
||||
let node = &clang[0];
|
||||
match &node.kind {
|
||||
Clang::ImplicitCastExpr => clang = &node.inner,
|
||||
Clang::ConstantExpr(expr) => match Discriminant::from_str(&expr.value) {
|
||||
Ok(discriminant) => return ParsedDiscriminant::Constant(discriminant),
|
||||
Err(_) => return ParsedDiscriminant::Fail,
|
||||
},
|
||||
_ => return ParsedDiscriminant::Fail,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
struct CxxName<'a>(&'a Pair);
|
||||
|
||||
impl<'a> Display for CxxName<'a> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
for namespace in &self.0.namespace {
|
||||
write!(formatter, "{}::", namespace)?;
|
||||
}
|
||||
write!(formatter, "{}", self.0.cxx)
|
||||
}
|
||||
}
|
||||
103
vendor/cxxbridge-macro/src/syntax/atom.rs
vendored
Normal file
103
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/attrs.rs
vendored
Normal file
302
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/cfg.rs
vendored
Normal file
77
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/check.rs
vendored
Normal file
733
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/derive.rs
vendored
Normal file
81
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/discriminant.rs
vendored
Normal file
336
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/doc.rs
vendored
Normal file
46
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/error.rs
vendored
Normal file
98
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/file.rs
vendored
Normal file
127
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/ident.rs
vendored
Normal file
57
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/impls.rs
vendored
Normal file
450
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/improper.rs
vendored
Normal file
39
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/instantiate.rs
vendored
Normal file
80
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/mangle.rs
vendored
Normal file
120
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/map.rs
vendored
Normal file
180
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/mod.rs
vendored
Normal file
306
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/names.rs
vendored
Normal file
64
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/namespace.rs
vendored
Normal file
85
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/parse.rs
vendored
Normal file
1492
vendor/cxxbridge-macro/src/syntax/parse.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
36
vendor/cxxbridge-macro/src/syntax/pod.rs
vendored
Normal file
36
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/qualified.rs
vendored
Normal file
59
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/report.rs
vendored
Normal file
33
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/resolve.rs
vendored
Normal file
46
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/set.rs
vendored
Normal file
136
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/symbol.rs
vendored
Normal file
110
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/tokens.rs
vendored
Normal file
308
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/toposort.rs
vendored
Normal file
51
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/trivial.rs
vendored
Normal file
312
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/types.rs
vendored
Normal file
285
vendor/cxxbridge-macro/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/cxxbridge-macro/src/syntax/visit.rs
vendored
Normal file
34
vendor/cxxbridge-macro/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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
vendor/cxxbridge-macro/src/tokens.rs
vendored
Normal file
75
vendor/cxxbridge-macro/src/tokens.rs
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use crate::syntax::Receiver;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote_spanned, ToTokens};
|
||||
use syn::Token;
|
||||
|
||||
pub struct ReceiverType<'a>(&'a Receiver);
|
||||
pub struct ReceiverTypeSelf<'a>(&'a Receiver);
|
||||
|
||||
impl Receiver {
|
||||
// &TheType
|
||||
pub fn ty(&self) -> ReceiverType {
|
||||
ReceiverType(self)
|
||||
}
|
||||
|
||||
// &Self
|
||||
pub fn ty_self(&self) -> ReceiverTypeSelf {
|
||||
ReceiverTypeSelf(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ReceiverType<'_> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Receiver {
|
||||
pinned: _,
|
||||
ampersand,
|
||||
lifetime,
|
||||
mutable: _,
|
||||
var: _,
|
||||
colon_token: _,
|
||||
ty,
|
||||
shorthand: _,
|
||||
pin_tokens,
|
||||
mutability,
|
||||
} = &self.0;
|
||||
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);
|
||||
ty.to_tokens(tokens);
|
||||
if let Some((_pin, _langle, rangle)) = pin_tokens {
|
||||
rangle.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for ReceiverTypeSelf<'_> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Receiver {
|
||||
pinned: _,
|
||||
ampersand,
|
||||
lifetime,
|
||||
mutable: _,
|
||||
var: _,
|
||||
colon_token: _,
|
||||
ty,
|
||||
shorthand: _,
|
||||
pin_tokens,
|
||||
mutability,
|
||||
} = &self.0;
|
||||
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);
|
||||
Token).to_tokens(tokens);
|
||||
if let Some((_pin, _langle, rangle)) = pin_tokens {
|
||||
rangle.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
vendor/cxxbridge-macro/src/type_id.rs
vendored
Normal file
44
vendor/cxxbridge-macro/src/type_id.rs
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
use crate::syntax::qualified::QualifiedName;
|
||||
use proc_macro2::{TokenStream, TokenTree};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::ext::IdentExt;
|
||||
|
||||
pub enum Crate {
|
||||
Cxx,
|
||||
DollarCrate(TokenTree),
|
||||
}
|
||||
|
||||
impl ToTokens for Crate {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
Crate::Cxx => tokens.extend(quote!(::cxx)),
|
||||
Crate::DollarCrate(krate) => krate.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "folly::File" => `(f, o, l, l, y, (), F, i, l, e)`
|
||||
pub fn expand(krate: Crate, arg: QualifiedName) -> TokenStream {
|
||||
let mut ids = Vec::new();
|
||||
|
||||
for word in arg.segments {
|
||||
if !ids.is_empty() {
|
||||
ids.push(quote!(()));
|
||||
}
|
||||
for ch in word.unraw().to_string().chars() {
|
||||
ids.push(match ch {
|
||||
'A'..='Z' | 'a'..='z' => {
|
||||
let t = format_ident!("{}", ch);
|
||||
quote!(#krate::#t)
|
||||
}
|
||||
'0'..='9' | '_' => {
|
||||
let t = format_ident!("_{}", ch);
|
||||
quote!(#krate::#t)
|
||||
}
|
||||
_ => quote!([(); #ch as _]),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
quote! { (#(#ids,)*) }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue