Cramming PhysX in there
More PhysX work More PhysX work
This commit is contained in:
414
modules/PhysX/physx/physx-sys/pxbind/Cargo.lock
generated
Normal file
414
modules/PhysX/physx/physx-sys/pxbind/Cargo.lock
generated
Normal file
@@ -0,0 +1,414 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clang-ast"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5218f4ca4789f5665f2a29a08b3fd36a9862364ef29892a1255b7efcf91edc78"
|
||||
dependencies = [
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"similar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxbind"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clang-ast",
|
||||
"env_logger",
|
||||
"heck",
|
||||
"insta",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
19
modules/PhysX/physx/physx-sys/pxbind/Cargo.toml
Normal file
19
modules/PhysX/physx/physx-sys/pxbind/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "pxbind"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
clang-ast = "0.1"
|
||||
env_logger = "0.10"
|
||||
heck = "0.4"
|
||||
log = "0.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = "1.26"
|
||||
tempfile = "3.6"
|
||||
1027
modules/PhysX/physx/physx-sys/pxbind/src/consumer.rs
Normal file
1027
modules/PhysX/physx/physx-sys/pxbind/src/consumer.rs
Normal file
File diff suppressed because it is too large
Load Diff
245
modules/PhysX/physx/physx-sys/pxbind/src/consumer/enums.rs
Normal file
245
modules/PhysX/physx/physx-sys/pxbind/src/consumer/enums.rs
Normal file
@@ -0,0 +1,245 @@
|
||||
use super::{Builtin, Comment, EnumDecl, Item, Node, Typedef};
|
||||
use anyhow::Context as _;
|
||||
|
||||
pub struct EnumVariant<'ast> {
|
||||
/// The name of the variant
|
||||
pub name: &'ast str,
|
||||
/// The constant value of the variant
|
||||
pub value: i64,
|
||||
/// Text comment on the enum constant
|
||||
pub comment: Option<Comment<'ast>>,
|
||||
}
|
||||
|
||||
pub struct EnumBinding<'ast> {
|
||||
/// The repr() applied to the the Rust enum to get it the correct size
|
||||
pub repr: Builtin,
|
||||
/// The "friendly" name of the enum, eg `PxErrorCode`
|
||||
pub name: &'ast str,
|
||||
/// The qualified type of the enum, minus the physx:: namespace since all
|
||||
/// the c/cpp code we compile is done within that namespace, eg. PxErrorCode::Enum
|
||||
pub cxx_qt: &'ast str,
|
||||
/// Text comment on the enum (or more usually, the wrapping struct)
|
||||
pub comment: Option<Comment<'ast>>,
|
||||
/// The list of constants
|
||||
pub variants: Vec<EnumVariant<'ast>>,
|
||||
}
|
||||
|
||||
pub struct FlagsBinding<'ast> {
|
||||
/// The name of the typedef used in the public API
|
||||
pub name: &'ast str,
|
||||
/// The index in the AstConsumer of the enum binding
|
||||
pub enums_index: usize,
|
||||
/// The storage type used by the flags
|
||||
pub storage_type: super::Builtin,
|
||||
}
|
||||
|
||||
impl<'ast> super::AstConsumer<'ast> {
|
||||
pub(super) fn consume_enum(
|
||||
&mut self,
|
||||
parent: &'ast Node,
|
||||
enum_node: &'ast Node,
|
||||
enum_decl: &'ast EnumDecl,
|
||||
) -> anyhow::Result<()> {
|
||||
let comment = match Self::get_comment(enum_node) {
|
||||
Some(com) => Some(com),
|
||||
None => {
|
||||
// If the comment isn't directly on the enum itself, check if
|
||||
// the parent is a struct since most physx enums follow the classic
|
||||
// struct EnumName { enum Enum {}; }; pattern
|
||||
if matches!(parent.kind, Item::CXXRecordDecl(_)) {
|
||||
Self::get_comment(parent)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let name = if let Item::CXXRecordDecl(rec) = &parent.kind {
|
||||
if let Some(rname) = rec.name.as_deref() {
|
||||
// Check if the record is actually not just a wrapper (ie, has fields or methods)
|
||||
// as that means we'll need to the name the enum with the inner name
|
||||
// as that is _probably_ still unique
|
||||
if parent
|
||||
.inner
|
||||
.iter()
|
||||
.any(|inn| matches!(&inn.kind, Item::FieldDecl { .. }))
|
||||
{
|
||||
if let Some(ename) = enum_decl.name.as_deref() {
|
||||
ename
|
||||
} else {
|
||||
log::debug!("Wrapper struct {rname} that will also be a POD contained an anonymous enum");
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
rname
|
||||
}
|
||||
} else {
|
||||
log::debug!(
|
||||
"skipping enum {:?} with anonymous wrapper struct",
|
||||
enum_decl.name
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
} else if let Some(ename) = enum_decl.name.as_deref() {
|
||||
ename
|
||||
} else {
|
||||
log::debug!("skipping anonymous enum");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let mut repr = Builtin::Int;
|
||||
let mut variants = Vec::new();
|
||||
|
||||
// Unfortunately the qualified type isn't present on the enum itself,
|
||||
// but rather each and every variant. They _should_ all be the same
|
||||
let mut cxx_qt = None;
|
||||
|
||||
fn get_value(node: &Node, current: i64, repr: &mut Builtin) -> anyhow::Result<i64> {
|
||||
for inn in &node.inner {
|
||||
match &inn.kind {
|
||||
Item::ImplicitCastExpr { .. } => {
|
||||
return get_value(inn, current, repr);
|
||||
}
|
||||
Item::ConstantExpr { value, kind } => {
|
||||
// There are a couple of cases where clang will emit
|
||||
// unsigned int for some variants and int for others,
|
||||
// so we need to just ignore changes once it's not the default
|
||||
if matches!(repr, Builtin::Int) {
|
||||
if let Some(builtin) = super::AstConsumer::parse_builtin(kind) {
|
||||
*repr = builtin;
|
||||
}
|
||||
}
|
||||
|
||||
return value.parse().context("failed to parse enum constant");
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(current)
|
||||
}
|
||||
|
||||
let mut current = 0;
|
||||
|
||||
for (varn, vard) in enum_node.inner.iter().filter_map(|inn| {
|
||||
if let Item::EnumConstantDecl(cdecl) = &inn.kind {
|
||||
Some((inn, cdecl))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
if Self::is_deprecated(varn) {
|
||||
log::debug!("ignoring deprecated variant {name}::{}", vard.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = &vard.name;
|
||||
|
||||
if let Some(cxx_qt) = cxx_qt {
|
||||
anyhow::ensure!(
|
||||
cxx_qt == vard.kind.qual_type,
|
||||
"enum has mismatching qualified types current: '{cxx_qt}', new: '{}'",
|
||||
vard.kind.qual_type
|
||||
);
|
||||
} else {
|
||||
cxx_qt = Some(vard.kind.qual_type.as_str());
|
||||
}
|
||||
|
||||
let comment = Self::get_comment(varn);
|
||||
let value = get_value(varn, current, &mut repr)?;
|
||||
|
||||
current = value + 1;
|
||||
|
||||
variants.push(EnumVariant {
|
||||
name,
|
||||
comment,
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
// All cpp code is used within the physx namespace, so strip that prefix
|
||||
let cxx_qt =
|
||||
cxx_qt.with_context(|| format!("enum '{name}' never declared a qualified typename"))?;
|
||||
let cxx_qt = super::no_physx(cxx_qt);
|
||||
|
||||
self.enums.push(EnumBinding {
|
||||
repr,
|
||||
name,
|
||||
cxx_qt,
|
||||
comment,
|
||||
variants,
|
||||
});
|
||||
self.enum_map.insert(cxx_qt, (repr, name));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn consume_flags(
|
||||
&mut self,
|
||||
_node: &'ast Node,
|
||||
td: &'ast Typedef,
|
||||
) -> anyhow::Result<()> {
|
||||
// PhysX uses a PxFlags<> template typedef to create a bitfield type for
|
||||
// a specific enum, we use this typedef to also generate an appropriate
|
||||
// bitflags that can be transparently passed between the FFI boundary
|
||||
let Some(flags) = super::no_physx(&td.kind.qual_type).strip_prefix("PxFlags<") else {
|
||||
return Ok(());
|
||||
};
|
||||
// Get rid of `>`
|
||||
let flags = &flags[..flags.len() - 1];
|
||||
|
||||
let mut iter = flags.split(',');
|
||||
|
||||
// PxFlags<PxDistanceJointFlag::Enum, physx::PxU16>
|
||||
// First template parameter is the enum type being wrapped
|
||||
let enum_type = iter
|
||||
.next()
|
||||
.with_context(|| format!("PxFlags typedef '{}' did not specify an enum type", td.name))?
|
||||
.trim();
|
||||
|
||||
// Second is the storage type, which _should_ always be an unsigned integer
|
||||
// type, so we assert on this to ensure shenanigans aren't happening
|
||||
// Though the PxFlags template allows for defaulting to u32 for storage,
|
||||
// this is not used AFAICT in PhysX, so we require that the storage
|
||||
// type be specified as well, for now
|
||||
let storage_type = iter
|
||||
.next()
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"PxFlags typedef '{}' did not specify a storage type",
|
||||
td.name
|
||||
)
|
||||
})?
|
||||
.trim();
|
||||
|
||||
let storage_type = Self::parse_builtin(storage_type).with_context(|| {
|
||||
format!(
|
||||
"PxFlags typedef '{}' has storage type '{storage_type}' which is not a builtin",
|
||||
td.name
|
||||
)
|
||||
})?;
|
||||
|
||||
// Find the enum binding, we use this later when generating the bitflags,
|
||||
// we search in reverse order since the enum being wrapped almost always
|
||||
// comes directly before the flags typedef
|
||||
let enums_index = self
|
||||
.enums
|
||||
.iter()
|
||||
.rposition(|eb| eb.cxx_qt == enum_type)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"PxFlags typedef '{}' references unknown enum type '{enum_type}'",
|
||||
td.name
|
||||
)
|
||||
})?;
|
||||
|
||||
self.flags.push(FlagsBinding {
|
||||
name: &td.name,
|
||||
enums_index,
|
||||
storage_type,
|
||||
});
|
||||
self.flags_map.insert(&td.name, storage_type);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
242
modules/PhysX/physx/physx-sys/pxbind/src/consumer/functions.rs
Normal file
242
modules/PhysX/physx/physx-sys/pxbind/src/consumer/functions.rs
Normal file
@@ -0,0 +1,242 @@
|
||||
use super::{Comment, Item, Method, QualType, TemplateArg};
|
||||
use crate::Node;
|
||||
use anyhow::Context as _;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub kind: super::Type,
|
||||
pub range: Option<clang_ast::SourceRange>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Param<'ast> {
|
||||
pub name: Cow<'ast, str>,
|
||||
pub kind: QualType<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> Param<'ast> {
|
||||
#[inline]
|
||||
pub fn self_pod(rec_type: QualType<'ast>, is_const: bool) -> Self {
|
||||
Self {
|
||||
name: Cow::Borrowed("self_"),
|
||||
kind: QualType::Pointer {
|
||||
is_const: false,
|
||||
is_pointee_const: is_const,
|
||||
pointee: Box::new(rec_type),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum PhysxInvoke<'ast> {
|
||||
/// Normal function call. Not many of these in PhysX, it's pretty OO
|
||||
Func { func_name: &'ast str, is_c: bool },
|
||||
/// Method call
|
||||
Method {
|
||||
func_name: &'ast str,
|
||||
class_name: &'ast str,
|
||||
is_static: bool,
|
||||
},
|
||||
/// Constructor call
|
||||
Ctor(&'ast str),
|
||||
/// New
|
||||
New(&'ast str),
|
||||
}
|
||||
|
||||
pub enum FuncBindingExt<'ast> {
|
||||
IsDelete(&'ast str),
|
||||
None(PhysxInvoke<'ast>),
|
||||
HasSelf(PhysxInvoke<'ast>),
|
||||
}
|
||||
|
||||
pub struct FuncBinding<'ast> {
|
||||
pub name: String,
|
||||
pub comment: Option<Comment<'ast>>,
|
||||
pub ext: FuncBindingExt<'ast>,
|
||||
pub params: Vec<Param<'ast>>,
|
||||
pub ret: Option<QualType<'ast>>,
|
||||
}
|
||||
|
||||
impl<'ast> FuncBinding<'ast> {
|
||||
pub fn owning_class(&self) -> Option<&'ast str> {
|
||||
match &self.ext {
|
||||
FuncBindingExt::None(pi) | FuncBindingExt::HasSelf(pi) => match pi {
|
||||
PhysxInvoke::Ctor(name)
|
||||
| PhysxInvoke::New(name)
|
||||
| PhysxInvoke::Method {
|
||||
class_name: name, ..
|
||||
} => Some(name),
|
||||
PhysxInvoke::Func { .. } => None,
|
||||
},
|
||||
FuncBindingExt::IsDelete(class_name) => Some(class_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> super::AstConsumer<'ast> {
|
||||
/// Retrieves a unique name for the function to ensure that overloads have
|
||||
/// different names. It also appends `phys_` before the name to ensure that
|
||||
/// the C++ code compiles by avoiding errors due to functions that only
|
||||
/// differ by return type being ambiguous
|
||||
fn get_func_name(&mut self, name: &'ast str) -> String {
|
||||
if let Some(count) = self.func_map.get_mut(name) {
|
||||
*count += 1;
|
||||
format!("phys_{name}_{count}")
|
||||
} else {
|
||||
self.func_map.insert(name, 0);
|
||||
format!("phys_{name}")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume_function(
|
||||
&mut self,
|
||||
node: &'ast Node,
|
||||
func: &'ast Function,
|
||||
template_types: &[(&str, &TemplateArg<'ast>)],
|
||||
is_c: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
if func.name.starts_with("operator") {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Check the source location for the function
|
||||
//
|
||||
// - PxMath - trivial functions that we can just do in Rust if needed
|
||||
// without crossing the FFI boundary
|
||||
// - PxString - internal-only string funtions we don't care about
|
||||
// - PxUtilities - useless internal-only functions
|
||||
// - PxAtomic - internal-only functions
|
||||
// - PxHash - internal-only functions
|
||||
let ignored = [
|
||||
"PxMath.h",
|
||||
"PxString.h",
|
||||
"PxUtilities.h",
|
||||
"PxAtomic.h",
|
||||
"PxHash.h",
|
||||
];
|
||||
if func
|
||||
.range
|
||||
.as_ref()
|
||||
.and_then(|r| r.begin.expansion_loc.as_ref())
|
||||
.map_or(false, |el| {
|
||||
el.file
|
||||
.rfind('/')
|
||||
.map_or(false, |sep| ignored.contains(&&el.file[sep + 1..]))
|
||||
})
|
||||
{
|
||||
log::debug!("skipping PxMath.h function {}", func.name);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let comment = Self::get_comment(node);
|
||||
|
||||
let mut fb = FuncBinding {
|
||||
name: self.get_func_name(&func.name),
|
||||
comment,
|
||||
ext: FuncBindingExt::None(PhysxInvoke::Func {
|
||||
func_name: &func.name,
|
||||
is_c,
|
||||
}),
|
||||
ret: None,
|
||||
params: Vec::new(),
|
||||
};
|
||||
|
||||
self.consume_return(&func.name, &func.kind.qual_type, template_types, &mut fb)?;
|
||||
self.consume_params(&func.name, node, template_types, &mut fb)?;
|
||||
|
||||
self.funcs.push(fb);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn consume_method(
|
||||
&mut self,
|
||||
node: &'ast Node,
|
||||
meth: &'ast Method,
|
||||
template_types: &[(&str, &TemplateArg<'ast>)],
|
||||
mut func: FuncBinding<'ast>,
|
||||
) -> anyhow::Result<()> {
|
||||
if meth.kind.qual_type.contains('<') {
|
||||
log::debug!(
|
||||
"ignoring method '{}' which has 1 or more templated parameters",
|
||||
meth.name
|
||||
);
|
||||
}
|
||||
|
||||
self.consume_return(&meth.name, &meth.kind.qual_type, template_types, &mut func)?;
|
||||
self.consume_params(&meth.name, node, template_types, &mut func)?;
|
||||
|
||||
self.funcs.push(func);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn consume_params(
|
||||
&self,
|
||||
name: &'ast str,
|
||||
node: &'ast Node,
|
||||
template_types: &[(&str, &TemplateArg<'ast>)],
|
||||
func: &mut FuncBinding<'ast>,
|
||||
) -> anyhow::Result<()> {
|
||||
for (i, param) in node
|
||||
.inner
|
||||
.iter()
|
||||
.filter_map(|inn| {
|
||||
if let Item::ParmVarDecl(param) = &inn.kind {
|
||||
Some(param)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
{
|
||||
let pname = param
|
||||
.name
|
||||
.as_deref()
|
||||
.map_or_else(|| format!("anon_param{i}").into(), Cow::Borrowed);
|
||||
let kind = self
|
||||
.parse_type(¶m.kind, template_types)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"failed to parse parameter '{pname} ({})' for function '{name}'",
|
||||
param.kind.qual_type,
|
||||
)
|
||||
})?;
|
||||
|
||||
func.params.push(Param { name: pname, kind });
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unfortunately `CXXMethodDecl`'s don't have a node for the return type,
|
||||
/// so we need to manually parse it from the function signature...
|
||||
#[inline]
|
||||
fn consume_return(
|
||||
&self,
|
||||
name: &str,
|
||||
sig: &'ast str,
|
||||
template_types: &[(&str, &TemplateArg<'ast>)],
|
||||
func: &mut FuncBinding<'ast>,
|
||||
) -> anyhow::Result<()> {
|
||||
// Ignore functions that already have a return type, notably constructors
|
||||
if func.ret.is_none() {
|
||||
let open_ind = sig
|
||||
.find('(')
|
||||
.with_context(|| format!("function signature for '{name}' doesn't have a '('"))?;
|
||||
|
||||
let ret = sig[..open_ind].trim();
|
||||
if ret != "void" {
|
||||
func.ret = Some(
|
||||
self.parse_type(ret, template_types)
|
||||
.with_context(|| format!("failed to parse return type for '{name}'"))?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
740
modules/PhysX/physx/physx-sys/pxbind/src/consumer/record.rs
Normal file
740
modules/PhysX/physx/physx-sys/pxbind/src/consumer/record.rs
Normal file
@@ -0,0 +1,740 @@
|
||||
use std::fmt;
|
||||
|
||||
use super::{functions, Builtin, ClassDef, Id, Item, QualType, Type, Typedef};
|
||||
use crate::Node;
|
||||
use anyhow::Context as _;
|
||||
use functions::*;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Copy, Clone, Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Access {
|
||||
Public,
|
||||
Protected,
|
||||
Private,
|
||||
}
|
||||
|
||||
fn storage_class<'de, D>(deserializer: D) -> Result<bool, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let s: &str = serde::de::Deserialize::deserialize(deserializer)?;
|
||||
Ok(s == "static")
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Method {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub kind: Type,
|
||||
#[serde(default, rename = "storageClass", deserialize_with = "storage_class")]
|
||||
pub is_static: bool,
|
||||
#[serde(default, rename = "virtual")]
|
||||
pub is_virtual: bool,
|
||||
}
|
||||
|
||||
impl Method {
|
||||
#[inline]
|
||||
fn is_const(&self) -> bool {
|
||||
self.is_static || self.kind.qual_type.ends_with(") const")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Constructor {
|
||||
#[serde(flatten)]
|
||||
pub(super) inner: Method,
|
||||
}
|
||||
|
||||
impl Constructor {
|
||||
/// Determines whether a constructor is a [copy constructor](https://en.cppreference.com/w/cpp/language/copy_constructor)
|
||||
#[inline]
|
||||
fn is_copy_or_move_constructor(&self, node: &Node) -> bool {
|
||||
let mut iter = node.inner.iter().filter_map(|inn| {
|
||||
if let Item::ParmVarDecl(param) = &inn.kind {
|
||||
Some(¶m.kind.qual_type)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let Some(first) = iter.next() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if first.ends_with(" &&") {
|
||||
return true;
|
||||
}
|
||||
|
||||
let maybe_copy = first
|
||||
.strip_suffix(" &")
|
||||
.map_or(false, |is_ref| is_ref.ends_with(&self.inner.name));
|
||||
|
||||
maybe_copy && iter.next().is_none()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Dtor {
|
||||
#[serde(default)]
|
||||
irrelevant: bool,
|
||||
#[serde(default)]
|
||||
simple: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DefinitionData {
|
||||
// #[serde(default, rename = "isPOD")]
|
||||
// is_pod: bool,
|
||||
dtor: Dtor,
|
||||
#[serde(default)]
|
||||
is_abstract: bool,
|
||||
#[serde(default)]
|
||||
is_polymorphic: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Base {
|
||||
//access: String,
|
||||
#[serde(rename = "type")]
|
||||
kind: Type,
|
||||
//written_access: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Tag {
|
||||
Struct,
|
||||
Class,
|
||||
Union,
|
||||
}
|
||||
|
||||
impl fmt::Display for Tag {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Struct => f.write_str("struct"),
|
||||
Self::Class => f.write_str("class"),
|
||||
Self::Union => f.write_str("union"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Record {
|
||||
pub id: Option<Id>,
|
||||
pub name: Option<String>,
|
||||
pub tag_used: Option<Tag>,
|
||||
pub definition_data: Option<DefinitionData>,
|
||||
#[serde(default)]
|
||||
pub bases: Vec<Base>,
|
||||
}
|
||||
|
||||
impl Record {
|
||||
#[inline]
|
||||
fn is_abstract(&self) -> bool {
|
||||
self.definition_data
|
||||
.as_ref()
|
||||
.map_or(false, |dd| dd.is_abstract)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_polymorphic(&self) -> bool {
|
||||
self.definition_data
|
||||
.as_ref()
|
||||
.map_or(false, |dd| dd.is_polymorphic)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_irrelevant_destructor(&self) -> bool {
|
||||
self.definition_data
|
||||
.as_ref()
|
||||
.map_or(false, |dd| dd.dtor.irrelevant)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_simple_destructor(&self) -> bool {
|
||||
self.definition_data
|
||||
.as_ref()
|
||||
.map_or(false, |dd| dd.dtor.simple)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RecBindingDef<'ast> {
|
||||
pub name: &'ast str,
|
||||
pub has_vtable: bool,
|
||||
pub ast: &'ast Record,
|
||||
pub fields: Vec<FieldBinding<'ast>>,
|
||||
pub calc_layout: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RecBindingForward<'ast> {
|
||||
pub name: &'ast str,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RecBinding<'ast> {
|
||||
Forward(RecBindingForward<'ast>),
|
||||
Def(RecBindingDef<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> RecBinding<'ast> {
|
||||
pub fn name(&self) -> &'ast str {
|
||||
match self {
|
||||
Self::Def(def) => def.name,
|
||||
Self::Forward(fwd) => fwd.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> PartialEq<str> for RecBinding<'ast> {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
match self {
|
||||
Self::Def(def) => def.name == other,
|
||||
Self::Forward(fwd) => fwd.name == other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FieldBinding<'ast> {
|
||||
pub name: &'ast str,
|
||||
pub kind: QualType<'ast>,
|
||||
pub is_public: bool,
|
||||
pub is_reference: bool,
|
||||
}
|
||||
|
||||
impl<'ast> super::AstConsumer<'ast> {
|
||||
fn has_release_method(&self, node: &'ast Node, rec: &'ast Record) -> anyhow::Result<bool> {
|
||||
if node.inner.iter().any(|inn| {
|
||||
if let Item::CXXMethodDecl(method) = &inn.kind {
|
||||
method.name == "release"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
for base in self.iter_bases(rec) {
|
||||
let (cdef, _) = base?;
|
||||
if self.has_release_method(cdef.node, cdef.rec)? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn is_template_we_care_about(
|
||||
node: &'ast Node,
|
||||
td: &'ast Typedef,
|
||||
) -> Option<&'ast str> {
|
||||
let tds = [
|
||||
"PxBitAndByte",
|
||||
"PxRaycastCallback",
|
||||
"PxOverlapCallback",
|
||||
"PxSweepCallback",
|
||||
"PxRaycastBuffer",
|
||||
"PxOverlapBuffer",
|
||||
"PxSweepBuffer",
|
||||
"PxBitMap",
|
||||
];
|
||||
|
||||
if !tds.contains(&td.name.as_str()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
node.inner.iter().find_map(|inn| {
|
||||
if let Item::TemplateSpecializationType { template_name } = &inn.kind {
|
||||
Some(template_name.as_str())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn consume_template_typedef(
|
||||
&mut self,
|
||||
_node: &'ast Node,
|
||||
td: &'ast Typedef,
|
||||
template_name: &'ast str,
|
||||
root: &'ast Node,
|
||||
) -> anyhow::Result<()> {
|
||||
if self.classes.contains_key(td.name.as_str()) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut fields = Vec::new();
|
||||
match td.name.as_str() {
|
||||
"PxBitAndByte" => {
|
||||
fields.push(FieldBinding {
|
||||
name: "mData",
|
||||
kind: QualType::Builtin(Builtin::UChar),
|
||||
is_public: false,
|
||||
is_reference: false,
|
||||
});
|
||||
}
|
||||
"PxRaycastCallback" | "PxOverlapCallback" | "PxSweepCallback" | "PxRaycastBuffer"
|
||||
| "PxOverlapBuffer" | "PxSweepBuffer" => {
|
||||
let hit_type = match td.name.as_str() {
|
||||
"PxRaycastCallback" | "PxRaycastBuffer" => "PxRaycastHit",
|
||||
"PxOverlapCallback" | "PxOverlapBuffer" => "PxOverlapHit",
|
||||
"PxSweepCallback" | "PxSweepBuffer" => "PxSweepHit",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
fields.push(FieldBinding {
|
||||
name: "block",
|
||||
kind: QualType::Record { name: hit_type },
|
||||
is_public: true,
|
||||
is_reference: false,
|
||||
});
|
||||
fields.push(FieldBinding {
|
||||
name: "hasBlock",
|
||||
kind: QualType::Builtin(Builtin::Bool),
|
||||
is_public: true,
|
||||
is_reference: false,
|
||||
});
|
||||
fields.push(FieldBinding {
|
||||
name: "touches",
|
||||
kind: QualType::Pointer {
|
||||
is_const: false,
|
||||
is_pointee_const: false,
|
||||
pointee: Box::new(QualType::Record { name: hit_type }),
|
||||
},
|
||||
is_public: true,
|
||||
is_reference: false,
|
||||
});
|
||||
fields.push(FieldBinding {
|
||||
name: "maxNbTouches",
|
||||
kind: QualType::Builtin(Builtin::UInt),
|
||||
is_public: true,
|
||||
is_reference: false,
|
||||
});
|
||||
fields.push(FieldBinding {
|
||||
name: "nbTouches",
|
||||
kind: QualType::Builtin(Builtin::UInt),
|
||||
is_public: true,
|
||||
is_reference: false,
|
||||
});
|
||||
}
|
||||
"PxBitMap" => {
|
||||
fields.push(FieldBinding {
|
||||
name: "mMap",
|
||||
kind: QualType::Pointer {
|
||||
is_const: false,
|
||||
is_pointee_const: false,
|
||||
pointee: Box::new(QualType::Builtin(Builtin::UInt)),
|
||||
},
|
||||
is_public: false,
|
||||
is_reference: false,
|
||||
});
|
||||
fields.push(FieldBinding {
|
||||
name: "mWordCount",
|
||||
kind: QualType::Builtin(Builtin::UInt),
|
||||
is_public: false,
|
||||
is_reference: false,
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
self.consume_template_instance(&td.kind.qual_type, Some(&td.name))?;
|
||||
}
|
||||
}
|
||||
|
||||
let name = &td.name;
|
||||
let (node, ast) = super::search(root, &|node: &Node| match &node.kind {
|
||||
Item::ClassTemplateSpecializationDecl(rec) | Item::CXXRecordDecl(rec) => {
|
||||
(rec.name.as_deref() == Some(template_name)).then_some(rec)
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.with_context(|| format!("failed to locate template specialization for {name}"))?;
|
||||
|
||||
self.classes.insert(
|
||||
name,
|
||||
Some(super::ClassDef {
|
||||
index: self.recs.len(),
|
||||
node,
|
||||
rec: ast,
|
||||
}),
|
||||
);
|
||||
|
||||
self.recs.push(RecBinding::Def(RecBindingDef {
|
||||
name,
|
||||
has_vtable: ast.is_polymorphic(),
|
||||
fields,
|
||||
ast,
|
||||
calc_layout: true,
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iter_bases(
|
||||
&self,
|
||||
rec: &'ast Record,
|
||||
) -> impl Iterator<Item = anyhow::Result<(&ClassDef<'ast>, &RecBindingDef<'ast>)>> {
|
||||
rec.bases.iter().filter_map(|base| {
|
||||
let Some(base_name) = base.kind.qual_type.strip_prefix("physx::") else {
|
||||
log::debug!("skipping non-physx base class '{}'", base.kind.qual_type);
|
||||
return None;
|
||||
};
|
||||
|
||||
let get = || {
|
||||
let base_rec = self.classes.get(base_name).with_context(|| {
|
||||
format!(
|
||||
"failed to find base '{}' for '{}'",
|
||||
base.kind.qual_type,
|
||||
rec.name.as_deref().unwrap(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let base_rec = base_rec.as_ref().with_context(|| {
|
||||
format!(
|
||||
"Definition for base class {} has not been consumed",
|
||||
base.kind.qual_type
|
||||
)
|
||||
})?;
|
||||
|
||||
if let RecBinding::Def(base_binding) = &self.recs[base_rec.index] {
|
||||
anyhow::ensure!(
|
||||
base_binding.name == base_name,
|
||||
"Retrieved incorrect binding for base class"
|
||||
);
|
||||
Ok((base_rec, base_binding))
|
||||
} else {
|
||||
anyhow::bail!("Found a forward declaration instead of the base definition");
|
||||
}
|
||||
};
|
||||
|
||||
Some(get())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn consume_record(
|
||||
&mut self,
|
||||
node: &'ast Node,
|
||||
rec: &'ast Record,
|
||||
) -> anyhow::Result<()> {
|
||||
// Do a quick check of the inner nodes, if we have an enumdecl, but no fields
|
||||
// or methods, this is just a wrapper around an enum and we can just emit the enum
|
||||
// and exit
|
||||
let mut had_enums = false;
|
||||
let mut had_more = false;
|
||||
|
||||
for inn in &node.inner {
|
||||
match &inn.kind {
|
||||
Item::FieldDecl { .. } => had_more = true,
|
||||
kind if kind.as_method().is_some() => had_more = true,
|
||||
Item::EnumDecl(decl) => {
|
||||
self.consume_enum(node, inn, decl)?;
|
||||
had_enums = true;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
if had_enums && !had_more {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let Some(rname) = rec.name.as_deref() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
anyhow::ensure!(
|
||||
rec.definition_data.is_some(),
|
||||
"can't consume a record without a definition"
|
||||
);
|
||||
let has_vtable = rec.is_polymorphic();
|
||||
|
||||
let mut is_public = !matches!(rec.tag_used, Some(Tag::Class));
|
||||
|
||||
let mut fields = Vec::new();
|
||||
for base_binding in self.iter_bases(rec) {
|
||||
let (_, base_binding) = base_binding?;
|
||||
fields.extend(base_binding.fields.iter().cloned());
|
||||
}
|
||||
|
||||
self.get_fields(node, rec, &[], &mut fields)?;
|
||||
|
||||
// Keep a record of each method that we are binding, to account for
|
||||
// overloading, particularly constructors, we need to append a counter
|
||||
// to keep the binding functions unique
|
||||
let mut meth_map = std::collections::BTreeMap::<String, u8>::new();
|
||||
|
||||
let mut get_name = |req: String| -> String {
|
||||
if let Some(count) = meth_map.get_mut(&req) {
|
||||
*count += 1;
|
||||
format!("{req}_{count}")
|
||||
} else {
|
||||
meth_map.insert(req.clone(), 0);
|
||||
req
|
||||
}
|
||||
};
|
||||
|
||||
for inn in &node.inner {
|
||||
// Ignore any method that isn't public, it's not part of the API we care about
|
||||
if let Some(method) = inn.kind.as_method() {
|
||||
if !is_public {
|
||||
continue;
|
||||
} else if method.kind.qual_type.contains('<') {
|
||||
log::debug!(
|
||||
"skipping `{rname}::{}` as it contains a templated parameter",
|
||||
method.name
|
||||
);
|
||||
continue;
|
||||
} else if Self::is_deprecated(inn) {
|
||||
log::debug!("skipping deprecated method {rname}::{}", method.name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let comment = Self::get_comment(inn);
|
||||
|
||||
let (mut func, method, has_self) = match &inn.kind {
|
||||
Item::AccessSpecDecl { access } => {
|
||||
is_public = matches!(access, Access::Public);
|
||||
continue;
|
||||
}
|
||||
Item::CXXConstructorDecl(method) => {
|
||||
// If the class is abstract we can't construct it directly so don't need to bind constructors
|
||||
// We don't care about copy or move constructors because they don't make sense in a C API
|
||||
if rec.is_abstract() || method.is_copy_or_move_constructor(inn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let func_binding = if rec.is_polymorphic() || !rec.has_simple_destructor() {
|
||||
FuncBinding {
|
||||
name: get_name(format!("{rname}_new_alloc")),
|
||||
ret: Some(QualType::Pointer {
|
||||
is_const: false,
|
||||
is_pointee_const: false,
|
||||
pointee: Box::new(QualType::Record { name: rname }),
|
||||
}),
|
||||
comment,
|
||||
ext: FuncBindingExt::None(PhysxInvoke::New(rname)),
|
||||
params: Vec::new(),
|
||||
}
|
||||
} else {
|
||||
FuncBinding {
|
||||
name: get_name(format!("{rname}_new")),
|
||||
ret: Some(QualType::Record { name: rname }),
|
||||
comment,
|
||||
ext: FuncBindingExt::None(PhysxInvoke::Ctor(rname)),
|
||||
params: Vec::new(),
|
||||
}
|
||||
};
|
||||
|
||||
(func_binding, &method.inner, false)
|
||||
}
|
||||
Item::CXXMethodDecl(method) => {
|
||||
// We don't care about operator overloads
|
||||
if method.name.starts_with("operator") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let func_binding = FuncBinding {
|
||||
name: get_name(format!(
|
||||
"{rname}_{}{}",
|
||||
method.name,
|
||||
if method.is_const() { "" } else { "" }
|
||||
)),
|
||||
ret: None,
|
||||
comment,
|
||||
ext: if method.is_static {
|
||||
FuncBindingExt::None(PhysxInvoke::Method {
|
||||
func_name: &method.name,
|
||||
class_name: rname,
|
||||
is_static: method.is_static,
|
||||
})
|
||||
} else {
|
||||
FuncBindingExt::HasSelf(PhysxInvoke::Method {
|
||||
func_name: &method.name,
|
||||
class_name: rname,
|
||||
is_static: method.is_static,
|
||||
})
|
||||
},
|
||||
params: Vec::new(),
|
||||
};
|
||||
|
||||
(func_binding, method, !method.is_static)
|
||||
}
|
||||
Item::CXXDestructorDecl(method) => {
|
||||
// Determine whether this class has a destructor which has no semantic effect.
|
||||
//
|
||||
// PhysX uses reference counting for many things, in which
|
||||
// case it should be deleted with a `release` method instead
|
||||
// of explicitly deleting it, but we need to account for that
|
||||
// `release` method possibly being on a base class, so we
|
||||
// need to walk up the base class chain until we hit the root
|
||||
// or a base that has a `release` method
|
||||
// https://nvidia-omniverse.github.io/PhysX/physx/5.1.2/docs/API.html#reference-counting
|
||||
if rec.has_irrelevant_destructor() || self.has_release_method(node, rec)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
(
|
||||
FuncBinding {
|
||||
name: format!("{rname}_delete"),
|
||||
comment,
|
||||
ext: FuncBindingExt::IsDelete(rname),
|
||||
params: Vec::new(),
|
||||
ret: None,
|
||||
},
|
||||
method,
|
||||
true,
|
||||
)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
if has_self {
|
||||
func.params.push(Param::self_pod(
|
||||
QualType::Record { name: rname },
|
||||
method.is_const(),
|
||||
));
|
||||
}
|
||||
|
||||
self.consume_method(inn, method, &[], func)?;
|
||||
}
|
||||
|
||||
// Check the fields to see if any records need to be forward declared
|
||||
// Note this doesn't apply to function parameters since functions are
|
||||
// emitted after all Pod types
|
||||
for field in &fields {
|
||||
if let QualType::Pointer { pointee, .. } | QualType::Reference { pointee, .. } =
|
||||
&field.kind
|
||||
{
|
||||
if let QualType::Record { name } = &**pointee {
|
||||
// Special case for PxTempAllocatorChunk which is an internal
|
||||
// linked list
|
||||
if *name != rname && !self.classes.contains_key(name) {
|
||||
self.recs
|
||||
.push(RecBinding::Forward(RecBindingForward { name }));
|
||||
self.classes.insert(name, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no fields, we need to add a dummy field since C++ doesn't have
|
||||
// zero-sized types. This is fine in practice since these types are only
|
||||
// ever passed by pointer
|
||||
let is_empty = fields.is_empty() && !has_vtable;
|
||||
if is_empty {
|
||||
fields.push(FieldBinding {
|
||||
name: "pxbind_dummy",
|
||||
kind: QualType::Builtin(super::Builtin::Char),
|
||||
is_public: false,
|
||||
is_reference: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Decide whether we should use "structgen" to calculate the exact layout of
|
||||
// this C++ struct.
|
||||
//
|
||||
// Ideally we would do this for all types, but we must be able to name them,
|
||||
// which is not feasible for anonymous types, or types which the generator
|
||||
// doesn't support yet (their cppTypeName will be empty).
|
||||
//
|
||||
// Note that empty types are only refered to by pointers and references in
|
||||
// PhysX, so we can generate dummy contents for them.
|
||||
let calc_layout = (!matches!(rec.tag_used, Some(crate::consumer::Tag::Union))
|
||||
&& !fields.is_empty())
|
||||
|| rname == "PxBroadcastingErrorCallback";
|
||||
|
||||
let record = RecBindingDef {
|
||||
name: rname,
|
||||
has_vtable,
|
||||
fields,
|
||||
ast: rec,
|
||||
calc_layout,
|
||||
};
|
||||
|
||||
self.classes.insert(
|
||||
rname,
|
||||
Some(super::ClassDef {
|
||||
index: self.recs.len(),
|
||||
node,
|
||||
rec,
|
||||
}),
|
||||
);
|
||||
self.recs.push(RecBinding::Def(record));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_fields(
|
||||
&self,
|
||||
node: &'ast Node,
|
||||
rec: &'ast Record,
|
||||
template_types: &[(&str, &super::TemplateArg<'ast>)],
|
||||
fields: &mut Vec<FieldBinding<'ast>>,
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(rname) = rec.name.as_deref() else {
|
||||
return Ok(());
|
||||
};
|
||||
let mut is_public = !matches!(rec.tag_used, Some(Tag::Class));
|
||||
|
||||
for inn in &node.inner {
|
||||
// We _could_ get comments for fields here, but due to the rust
|
||||
// declarations being emitted by structgen, it becomes a bit noisy
|
||||
|
||||
match &inn.kind {
|
||||
Item::AccessSpecDecl { access } => {
|
||||
is_public = matches!(access, Access::Public);
|
||||
}
|
||||
Item::FieldDecl { name, kind } => {
|
||||
// Skip anonymous fields, they aren't really accessible
|
||||
if let Some(name) = name.as_deref() {
|
||||
// PhysX uses PxPadding<BYTES> in some struct, but this
|
||||
// is uninteresting so we can just skip it, they'll be
|
||||
// accounted for in our own padding calculations regardless
|
||||
if kind.qual_type.starts_with("PxPadding<") {
|
||||
log::debug!("skipping padding field");
|
||||
continue;
|
||||
}
|
||||
|
||||
if kind.qual_type.contains('<') {
|
||||
log::debug!("skipping templated field {rname}::{name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// We've made modifications to the C++ code to deprecate
|
||||
// fields that are using deprecated types
|
||||
if Self::is_deprecated(inn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let kind = self
|
||||
.parse_type(kind, template_types)
|
||||
.with_context(|| format!("failed to parse type for {rname}::{name}"))?;
|
||||
|
||||
// if matches!(&kind, QualType::FunctionPointer) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
let is_reference = matches!(kind, QualType::Reference { .. });
|
||||
|
||||
fields.push(FieldBinding {
|
||||
name,
|
||||
kind,
|
||||
is_public,
|
||||
is_reference,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
135
modules/PhysX/physx/physx-sys/pxbind/src/consumer/templates.rs
Normal file
135
modules/PhysX/physx/physx-sys/pxbind/src/consumer/templates.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::Node;
|
||||
|
||||
use super::{AstConsumer, Builtin, QualType, Record};
|
||||
use anyhow::Context as _;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum TemplateArg<'ast> {
|
||||
Type(QualType<'ast>),
|
||||
Value(u32),
|
||||
}
|
||||
|
||||
struct TemplateParam<'ast> {
|
||||
name: &'ast str,
|
||||
builtin: Option<Builtin>,
|
||||
}
|
||||
|
||||
enum TemplateItemKind<'ast> {
|
||||
Concrete(QualType<'ast>),
|
||||
Parameterized(&'ast str),
|
||||
}
|
||||
|
||||
struct TemplateItem<'ast> {
|
||||
name: &'ast str,
|
||||
kind: TemplateItemKind<'ast>,
|
||||
}
|
||||
|
||||
struct TemplateMethod<'ast> {
|
||||
name: String,
|
||||
params: Vec<TemplateItem<'ast>>,
|
||||
}
|
||||
|
||||
struct TemplateStamp<'ast> {
|
||||
name: Cow<'ast, str>,
|
||||
args: Vec<TemplateArg<'ast>>,
|
||||
}
|
||||
|
||||
pub struct Template<'ast> {
|
||||
params: Vec<TemplateParam<'ast>>,
|
||||
instanced: Vec<TemplateStamp<'ast>>,
|
||||
/// This is the
|
||||
top_record: &'ast Record,
|
||||
def_record: &'ast Node,
|
||||
}
|
||||
|
||||
impl<'ast> Template<'ast> {
|
||||
fn parse_template_args(
|
||||
&self,
|
||||
ast: &AstConsumer<'ast>,
|
||||
qt: &'ast str,
|
||||
) -> anyhow::Result<Vec<TemplateArg<'ast>>> {
|
||||
let begin = qt.find('<').context("not a template")?;
|
||||
let end = qt.rfind('>').context("not a template")?;
|
||||
|
||||
let mut targs = Vec::new();
|
||||
for (arg, param) in qt[begin + 1..end].split(',').zip(self.params.iter()) {
|
||||
// We don't really do error checking here, if the templates are messed
|
||||
// up PhysX won't compile
|
||||
if param.builtin.is_some() {
|
||||
targs.push(TemplateArg::Value(arg.parse()?));
|
||||
} else {
|
||||
targs.push(TemplateArg::Type(ast.parse_type(arg, &[])?));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(targs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_stamped(&self, args: &[TemplateArg<'ast>]) -> Option<Cow<'ast, str>> {
|
||||
self.instanced
|
||||
.iter()
|
||||
.find_map(|i| (i.args == args).then(|| i.name.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> AstConsumer<'ast> {
|
||||
pub(super) fn consume_template_instance(
|
||||
&mut self,
|
||||
qual_type: &'ast str,
|
||||
name: Option<&'ast str>,
|
||||
) -> anyhow::Result<Cow<'ast, str>> {
|
||||
let qual_type = if let Some(stripped) = qual_type.strip_prefix("const ") {
|
||||
stripped
|
||||
} else {
|
||||
qual_type
|
||||
};
|
||||
|
||||
let begin = qual_type.find('<').context("this isn't a template")?;
|
||||
|
||||
let template_name = &qual_type[..begin];
|
||||
let tdecl = self
|
||||
.templates
|
||||
.get(template_name)
|
||||
.with_context(|| format!("template decl '{template_name}' has not been consumed"))?;
|
||||
|
||||
let targs = tdecl.parse_template_args(self, qual_type)?;
|
||||
|
||||
// If we've already stamped out this template just return the name it was given
|
||||
if let Some(stamped) = tdecl.get_stamped(&targs) {
|
||||
return Ok(stamped);
|
||||
}
|
||||
|
||||
let instance_name = name.map_or_else(
|
||||
|| Cow::Owned(format!("{template_name}_T{}", tdecl.instanced.len())),
|
||||
Cow::Borrowed,
|
||||
);
|
||||
|
||||
let mut mappings: Vec<_> = targs
|
||||
.iter()
|
||||
.zip(tdecl.params.iter())
|
||||
.map(|(ta, tp)| (tp.name, ta))
|
||||
.collect();
|
||||
|
||||
let mut fields = Vec::new();
|
||||
self.get_fields(tdecl.def_record, tdecl.top_record, &mappings, &mut fields)?;
|
||||
|
||||
Ok(instance_name)
|
||||
}
|
||||
|
||||
pub(super) fn consume_template_decl(
|
||||
&mut self,
|
||||
node: &'ast Node,
|
||||
name: &'ast str,
|
||||
) -> anyhow::Result<()> {
|
||||
anyhow::ensure!(
|
||||
!self.templates.contains_key(name),
|
||||
"template '{name}' has already been consumed"
|
||||
);
|
||||
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
88
modules/PhysX/physx/physx-sys/pxbind/src/dump.rs
Normal file
88
modules/PhysX/physx/physx-sys/pxbind/src/dump.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use crate::Node;
|
||||
use anyhow::Context as _;
|
||||
|
||||
pub fn get_repo_root() -> anyhow::Result<String> {
|
||||
let mut git = std::process::Command::new("git");
|
||||
git.args(["rev-parse", "--show-toplevel"]);
|
||||
git.stdout(std::process::Stdio::piped());
|
||||
let captured = git
|
||||
.output()
|
||||
.context("failed to run git to find repo root")?;
|
||||
|
||||
let mut rr = String::from_utf8(captured.stdout).context("git output was non-utf8")?;
|
||||
// Removing trailing newline
|
||||
rr.pop();
|
||||
Ok(rr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_include_dir() -> anyhow::Result<String> {
|
||||
// Acquire the repo root so we don't need to care about where we are executing
|
||||
// this from (eg root, tests, wherever)
|
||||
let repo_root = get_repo_root()?;
|
||||
|
||||
Ok(format!("{repo_root}/physx/physx-sys/physx/physx/include"))
|
||||
}
|
||||
|
||||
pub fn get_ast(header: impl AsRef<std::path::Path>) -> anyhow::Result<Vec<u8>> {
|
||||
let mut cmd = std::process::Command::new("clang++");
|
||||
|
||||
let include_dir = get_include_dir()?;
|
||||
|
||||
cmd.args([
|
||||
"-Xclang",
|
||||
// Requests the AST dump
|
||||
"-ast-dump=json",
|
||||
// We aren't actually compiling, just gathering type info
|
||||
"-fsyntax-only",
|
||||
// clang will complain about all physx headers when we are in C++
|
||||
// mode because it treats .h as "c headers", this is useless
|
||||
"-xc++-header",
|
||||
// Define PX_DEPRECATED so that the attribute is emitted into the AST
|
||||
"-DPX_DEPRECATED=__attribute__((deprecated()))",
|
||||
// Ignore all warnings, we don't care about C++ shenanigans
|
||||
"-w",
|
||||
// We don't want this
|
||||
"-DDISABLE_CUDA_PHYSX",
|
||||
"-fcolor-diagnostics",
|
||||
// Add the root include directory so that clang knows how to find
|
||||
// all of the includes
|
||||
"-I",
|
||||
&include_dir,
|
||||
// Sigh, physx asserts that this is defined :p
|
||||
"-DNDEBUG",
|
||||
]);
|
||||
cmd.arg(header.as_ref());
|
||||
|
||||
// note that this is _terribly_ slow but hopefully fixed in 1.69?
|
||||
// https://github.com/rust-lang/rust/issues/108223
|
||||
cmd.stdout(std::process::Stdio::piped());
|
||||
cmd.stderr(std::process::Stdio::piped());
|
||||
|
||||
let captured = cmd
|
||||
.output()
|
||||
.context("failed to run clang++ to gather AST")?;
|
||||
|
||||
anyhow::ensure!(
|
||||
captured.status.success(),
|
||||
"clang++ failed to gather AST {:?}\n{}",
|
||||
captured.status,
|
||||
String::from_utf8(captured.stderr).unwrap_or_default(),
|
||||
);
|
||||
|
||||
Ok(captured.stdout)
|
||||
}
|
||||
|
||||
/// Dump the AST of a header and all of its includes and parses it into a [`Node`]
|
||||
pub fn get_parsed_ast(header: impl AsRef<std::path::Path>) -> anyhow::Result<(Node, Vec<u8>)> {
|
||||
log::info!("Gathering AST via clang...");
|
||||
let t = std::time::Instant::now();
|
||||
let ast = get_ast(header)?;
|
||||
log::info!("Gathered AST in {}ms", t.elapsed().as_millis());
|
||||
|
||||
log::info!("Parsing AST...");
|
||||
let t = std::time::Instant::now();
|
||||
let root_node: Node = serde_json::from_slice(&ast).context("failed to parse AST")?;
|
||||
log::info!("Parsed AST in {}ms", t.elapsed().as_millis());
|
||||
Ok((root_node, ast))
|
||||
}
|
||||
324
modules/PhysX/physx/physx-sys/pxbind/src/generator.rs
Normal file
324
modules/PhysX/physx/physx-sys/pxbind/src/generator.rs
Normal file
@@ -0,0 +1,324 @@
|
||||
#[macro_export]
|
||||
macro_rules! writes {
|
||||
($s:expr, $f:expr $(,)?) => {{
|
||||
use std::fmt::Write;
|
||||
write!($s, $f).unwrap();
|
||||
}};
|
||||
($s:expr, $f:expr, $($arg:tt)*) => {{
|
||||
use std::fmt::Write;
|
||||
write!($s, $f, $($arg)*).unwrap();
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! writesln {
|
||||
($s:expr) => {{
|
||||
use std::fmt::Write;
|
||||
writeln!($s).unwrap();
|
||||
}};
|
||||
($s:expr, $f:expr $(,)?) => {{
|
||||
use std::fmt::Write;
|
||||
writeln!($s, $f).unwrap();
|
||||
}};
|
||||
($s:expr, $f:expr, $($arg:tt)*) => {{
|
||||
use std::fmt::Write;
|
||||
writeln!($s, $f, $($arg)*).unwrap();
|
||||
}};
|
||||
}
|
||||
|
||||
mod comment;
|
||||
mod enums;
|
||||
mod functions;
|
||||
mod record;
|
||||
|
||||
use crate::consumer::{AstConsumer, Builtin, EnumBinding, FuncBinding, RecBinding};
|
||||
use std::{fmt, io::Write};
|
||||
|
||||
/// The variable name of `PodStructGen` in the structgen program
|
||||
const SG: &str = "sg";
|
||||
/// The name of the macro used to calculate a field's offset in the structgen program
|
||||
const UOF: &str = "unsafe_offsetof";
|
||||
|
||||
/// It's impossible (I believe) with Rust's format strings to have the width
|
||||
/// of the alignment be dynamic, so we just uhhh...be lame
|
||||
struct Indent(u32);
|
||||
|
||||
impl fmt::Display for Indent {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for _ in 0..self.0 {
|
||||
f.write_str(" ")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Generator {
|
||||
pub record_filter: Box<dyn Fn(&RecBinding<'_>) -> bool>,
|
||||
pub enum_filter: Box<dyn Fn(&EnumBinding<'_>) -> bool>,
|
||||
pub func_filter: Box<dyn Fn(&FuncBinding<'_>) -> bool>,
|
||||
}
|
||||
|
||||
impl Default for Generator {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
record_filter: Box::new(|_rb| true),
|
||||
enum_filter: Box::new(|_eb| true),
|
||||
func_filter: Box::new(|_fb| true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Generator {
|
||||
pub fn generate_all(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
structgen: &mut impl Write,
|
||||
cpp: &mut impl Write,
|
||||
rust: &mut impl Write,
|
||||
) -> anyhow::Result<()> {
|
||||
self.generate_structgen(ast, structgen)?;
|
||||
self.generate_cpp(ast, cpp)?;
|
||||
self.generate_rust(ast, rust)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates the structgen `main` function, which is used to generate
|
||||
/// the the POD types for C and Rust and guarantee their fields are
|
||||
/// appropriately sized and aligned so they can be interchanged
|
||||
pub fn generate_structgen(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
out: &mut impl Write,
|
||||
) -> anyhow::Result<()> {
|
||||
// Preamble
|
||||
{
|
||||
// Get access to all of the PhysX types we're retrieving the layout for
|
||||
writeln!(out, "// Automatically generated by pxbind")?;
|
||||
writeln!(out, r#"#include "PxPhysicsAPI.h""#)?;
|
||||
writeln!(out, "\nusing namespace physx;")?;
|
||||
|
||||
// Macro used to get the offset of each public field that the PODs
|
||||
// expose
|
||||
writeln!(
|
||||
out,
|
||||
"\n#define {UOF}(st, m) ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))"
|
||||
)?;
|
||||
// The header that contains the implementation of PodStructGen
|
||||
writeln!(out, r#"#include "structgen.hpp""#)?;
|
||||
writeln!(out, "\nint main() {{")?;
|
||||
}
|
||||
|
||||
let indent = Indent(1);
|
||||
writeln!(out, "{indent}PodStructGen {SG};")?;
|
||||
|
||||
let mut acc = String::new();
|
||||
for rec in ast.recs.iter().filter(|rb| (self.record_filter)(rb)) {
|
||||
acc.clear();
|
||||
|
||||
match rec {
|
||||
RecBinding::Def(def) => def.emit_structgen(&mut acc, 1),
|
||||
RecBinding::Forward(forward) => forward.emit_structgen(&mut acc, 1),
|
||||
}
|
||||
writeln!(out, "{acc}")?;
|
||||
}
|
||||
|
||||
writeln!(out, "{indent}{SG}.finish();\n}}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_cpp(&self, ast: &AstConsumer<'_>, out: &mut impl Write) -> anyhow::Result<()> {
|
||||
self.generate_size_asserts(ast, out)?;
|
||||
self.generate_cpp_functions(ast, out, 0)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates the static assert code used to verify that every structgen
|
||||
/// POD type is the same size as the C++ type it is wrapping
|
||||
pub fn generate_size_asserts(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
out: &mut impl Write,
|
||||
) -> anyhow::Result<()> {
|
||||
writeln!(
|
||||
out,
|
||||
"using namespace physx;\n#include \"structgen_out.hpp\"\n"
|
||||
)?;
|
||||
|
||||
for rec in ast.recs.iter().filter_map(|rb| {
|
||||
if let RecBinding::Def(def) = rb {
|
||||
if (self.record_filter)(rb) {
|
||||
return Some(def);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}) {
|
||||
let name = rec.name;
|
||||
writeln!(out, "static_assert(sizeof(physx::{name}) == sizeof(physx_{name}), \"POD wrapper for `physx::{name}` has incorrect size\");")?;
|
||||
}
|
||||
|
||||
writeln!(out)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates the C functions used to convert between the C bridge types
|
||||
/// and calls into the C++ code
|
||||
pub fn generate_cpp_functions(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
out: &mut impl Write,
|
||||
level: u32,
|
||||
) -> anyhow::Result<()> {
|
||||
let indent = Indent(level);
|
||||
|
||||
writeln!(out, "{indent}extern \"C\" {{")?;
|
||||
let mut acc = String::new();
|
||||
for func in ast.funcs.iter().filter(|fb| (self.func_filter)(fb)) {
|
||||
acc.clear();
|
||||
func.emit_cpp(&mut acc, level + 1)?;
|
||||
writeln!(out, "{acc}")?;
|
||||
}
|
||||
writeln!(out, "{indent}}}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_rust(&self, ast: &AstConsumer<'_>, w: &mut impl Write) -> anyhow::Result<()> {
|
||||
let level = 0;
|
||||
|
||||
self.generate_rust_enums(ast, w, level)?;
|
||||
self.generate_rust_records(ast, w)?;
|
||||
self.generate_rust_functions(ast, w, level)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_rust_enums(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
writer: &mut impl Write,
|
||||
level: u32,
|
||||
) -> anyhow::Result<u32> {
|
||||
let mut fiter = ast.flags.iter().peekable();
|
||||
let mut acc = String::new();
|
||||
|
||||
const INT_ENUMS: &[(&str, Builtin, &str)] = &[
|
||||
("PxConcreteType", Builtin::UShort, "Undefined"),
|
||||
("PxD6Drive", Builtin::USize, "Count"),
|
||||
];
|
||||
|
||||
for (enum_binding, flags_binding) in ast.enums.iter().enumerate().filter_map(|(i, eb)| {
|
||||
let fb = if fiter.peek().map_or(false, |f| f.enums_index == i) {
|
||||
fiter.next()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if (self.enum_filter)(eb) {
|
||||
Some((eb, fb))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
if !acc.is_empty() {
|
||||
acc.clear();
|
||||
writesln!(acc);
|
||||
}
|
||||
|
||||
enum_binding.emit_rust(&mut acc, level);
|
||||
|
||||
if let Some((builtin, default)) = INT_ENUMS.iter().find_map(|(name, bi, def)| {
|
||||
if *name == enum_binding.name {
|
||||
Some((*bi, *def))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
writesln!(acc);
|
||||
enum_binding.emit_rust_conversion(&mut acc, level, builtin, default);
|
||||
}
|
||||
|
||||
if let Some(flags) = flags_binding {
|
||||
writesln!(acc);
|
||||
flags.emit_rust(enum_binding, &mut acc, level);
|
||||
}
|
||||
|
||||
write!(writer, "{acc}")?;
|
||||
}
|
||||
|
||||
Ok((ast.enums.len() + ast.flags.len()) as u32)
|
||||
}
|
||||
|
||||
pub fn generate_rust_records(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
writer: &mut impl Write,
|
||||
) -> anyhow::Result<u32> {
|
||||
let mut num = 0;
|
||||
let mut acc = String::new();
|
||||
|
||||
for rec in ast.recs.iter().filter(|rb| (self.record_filter)(rb)) {
|
||||
acc.clear();
|
||||
writesln!(acc);
|
||||
|
||||
match rec {
|
||||
RecBinding::Def(def) => {
|
||||
if def.emit_rust(&mut acc, 0) {
|
||||
num += 1;
|
||||
write!(writer, "{acc}")?;
|
||||
}
|
||||
}
|
||||
RecBinding::Forward(forward) => {
|
||||
if matches!(ast.classes.get(forward.name), Some(None)) {
|
||||
forward.emit_rust(&mut acc, 0);
|
||||
write!(writer, "{acc}")?;
|
||||
num += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(num)
|
||||
}
|
||||
|
||||
pub fn generate_rust_functions(
|
||||
&self,
|
||||
ast: &AstConsumer<'_>,
|
||||
w: &mut impl Write,
|
||||
level: u32,
|
||||
) -> anyhow::Result<u32> {
|
||||
let indent = Indent(level);
|
||||
|
||||
writeln!(w, "{indent}extern \"C\" {{")?;
|
||||
let mut acc = String::new();
|
||||
for func in ast.funcs.iter().filter(|fb| (self.func_filter)(fb)) {
|
||||
acc.clear();
|
||||
func.emit_rust(&mut acc, level + 1);
|
||||
writeln!(w, "{acc}")?;
|
||||
}
|
||||
writeln!(w, "{indent}}}")?;
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
struct RustIdent<'ast>(&'ast str);
|
||||
|
||||
impl<'ast> fmt::Display for RustIdent<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
static KEYWORDS: &[&str] = &["box", "type", "ref"];
|
||||
|
||||
f.write_str(self.0)?;
|
||||
|
||||
if KEYWORDS.contains(&self.0) {
|
||||
f.write_str("_")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
use super::Indent;
|
||||
|
||||
impl<'ast> crate::consumer::Comment<'ast> {
|
||||
pub(super) fn emit_rust(&self, writer: &mut String, level: u32) {
|
||||
let indent = Indent(level);
|
||||
|
||||
let emit_lines = |w: &mut String, lines: &[&str]| {
|
||||
for line in lines {
|
||||
if line.is_empty() {
|
||||
writesln!(w, "{indent}///");
|
||||
// PhysX _tends_ to use `#type::field/variant` style intralinks
|
||||
// so attempt to convert them to proper rustdoc style intralinks
|
||||
} else if let Some(ind) = line.find('#') {
|
||||
writes!(w, "{indent}/// {}", &line[..ind]);
|
||||
writes!(w, "[`");
|
||||
match line[ind + 1..]
|
||||
.find(|c: char| !c.is_alphanumeric() && c != ':' && c != '_')
|
||||
{
|
||||
Some(end) => {
|
||||
writes!(w, "{}`]", &line[ind + 1..ind + end + 1]);
|
||||
writesln!(w, "{}", &line[ind + end + 1..]);
|
||||
}
|
||||
None => {
|
||||
writesln!(w, "{}`]", &line[ind + 1..]);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
writesln!(w, "{indent}/// {line}");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
emit_lines(writer, self.summary.as_slice());
|
||||
|
||||
if !self.additional.is_empty() {
|
||||
writesln!(writer, "{indent}///");
|
||||
emit_lines(writer, self.additional.as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
144
modules/PhysX/physx/physx-sys/pxbind/src/generator/enums.rs
Normal file
144
modules/PhysX/physx/physx-sys/pxbind/src/generator/enums.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use crate::consumer::{Builtin, EnumBinding};
|
||||
|
||||
use super::Indent;
|
||||
|
||||
/// Fixes enum variant names from the ugly C++ style of `eWHY_ARE_YOU_SHOUTING`
|
||||
/// to `WhyAreYouShouting`
|
||||
fn fix_variant_name(s: &str) -> String {
|
||||
let no_e = s
|
||||
.strip_prefix('e')
|
||||
.filter(|s| s.chars().next().unwrap().is_ascii_alphabetic())
|
||||
.unwrap_or(s);
|
||||
|
||||
use heck::ToUpperCamelCase;
|
||||
no_e.to_upper_camel_case()
|
||||
}
|
||||
|
||||
impl<'ast> EnumBinding<'ast> {
|
||||
pub fn emit_rust(&self, w: &mut String, level: u32) {
|
||||
if let Some(com) = &self.comment {
|
||||
com.emit_rust(w, level);
|
||||
}
|
||||
|
||||
let indent = Indent(level);
|
||||
let indent1 = Indent(level + 1);
|
||||
writesln!(w, "{indent}#[derive(Debug, Clone, Copy, PartialEq, Eq)]");
|
||||
writesln!(w, "{indent}#[repr({})]", self.repr.rust_type());
|
||||
writesln!(w, "{indent}pub enum {} {{", self.name);
|
||||
|
||||
for var in &self.variants {
|
||||
if let Some(com) = &var.comment {
|
||||
com.emit_rust(w, level + 1);
|
||||
}
|
||||
|
||||
writesln!(
|
||||
w,
|
||||
"{indent1}{} = {},",
|
||||
fix_variant_name(var.name),
|
||||
var.value
|
||||
);
|
||||
}
|
||||
|
||||
writesln!(w, "{indent}}}");
|
||||
}
|
||||
|
||||
pub fn emit_rust_conversion(&self, w: &mut String, level: u32, from: Builtin, default: &str) {
|
||||
let indent = Indent(level);
|
||||
let indent1 = Indent(level + 1);
|
||||
let indent2 = Indent(level + 2);
|
||||
|
||||
let int_type = from.rust_type();
|
||||
|
||||
writesln!(w, "{indent}impl From<{int_type}> for {} {{", self.name);
|
||||
writesln!(w, "{indent1}fn from(val: {int_type}) -> Self {{");
|
||||
writesln!(w, "{indent2}#[allow(clippy::match_same_arms)]");
|
||||
writesln!(w, "{indent2}match val {{");
|
||||
|
||||
let indentm = Indent(level + 3);
|
||||
|
||||
for var in &self.variants {
|
||||
writesln!(
|
||||
w,
|
||||
"{indentm}{} => Self::{},",
|
||||
var.value,
|
||||
fix_variant_name(var.name)
|
||||
);
|
||||
}
|
||||
|
||||
writesln!(w, "{indentm}_ => Self::{default},");
|
||||
writesln!(w, "{indent2}}}");
|
||||
writesln!(w, "{indent1}}}");
|
||||
writesln!(w, "{indent}}}");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> crate::consumer::FlagsBinding<'ast> {
|
||||
pub fn emit_rust(&self, enum_binding: &EnumBinding<'ast>, w: &mut String, level: u32) {
|
||||
let indent = Indent(level);
|
||||
let indent1 = Indent(level + 1);
|
||||
let indent2 = Indent(level + 2);
|
||||
writesln!(w, "{indent}bitflags::bitflags! {{");
|
||||
writesln!(w, "{indent1}/// Flags for [`{}`]", enum_binding.name);
|
||||
writesln!(w, "{indent1}#[derive(Default)]");
|
||||
writesln!(w, "{indent1}#[repr(transparent)]");
|
||||
writesln!(
|
||||
w,
|
||||
"{indent1}pub struct {}: {} {{",
|
||||
self.name,
|
||||
self.storage_type.rust_type()
|
||||
);
|
||||
|
||||
for var in &enum_binding.variants {
|
||||
// If used as flags, ignore emitting any zero value, see
|
||||
// https://docs.rs/bitflags/1.3.2/bitflags/#zero-flags
|
||||
if var.value == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if let Some(com) = &var.comment {
|
||||
// com.emit_rust(writer, level + 2)?;
|
||||
// }
|
||||
|
||||
writes!(w, "{indent2}const {} = ", fix_variant_name(var.name));
|
||||
|
||||
// Since bitflags are made up of power of 2 values that can
|
||||
// be combined, and the PhysX API sometimes defines named
|
||||
// combinations of flags, reconstruct the bitflags to be
|
||||
// easier to read
|
||||
let val = var.value as u64;
|
||||
if val & (val - 1) == 0 {
|
||||
writes!(w, "1 << {}", val.ilog2());
|
||||
} else {
|
||||
let mut is_combo = false;
|
||||
// If we're not a power of 2, we're a combination of flags,
|
||||
// find which ones and emit them in a friendly way
|
||||
for (i, which) in enum_binding
|
||||
.variants
|
||||
.iter()
|
||||
.filter_map(|var| {
|
||||
let prev = var.value as u64;
|
||||
(prev & (prev - 1) == 0 && (prev & val) != 0).then_some(var.name)
|
||||
})
|
||||
.enumerate()
|
||||
{
|
||||
is_combo = true;
|
||||
if i > 0 {
|
||||
writes!(w, " | ");
|
||||
}
|
||||
|
||||
writes!(w, "Self::{}.bits", fix_variant_name(which));
|
||||
}
|
||||
|
||||
// There are a couple of cases where they're not combos, so just
|
||||
// emit the raw value
|
||||
if !is_combo {
|
||||
writes!(w, "0x{val:08x}");
|
||||
}
|
||||
}
|
||||
|
||||
writesln!(w, ";");
|
||||
}
|
||||
|
||||
writesln!(w, "{indent1}}}\n{indent}}}");
|
||||
}
|
||||
}
|
||||
291
modules/PhysX/physx/physx-sys/pxbind/src/generator/functions.rs
Normal file
291
modules/PhysX/physx/physx-sys/pxbind/src/generator/functions.rs
Normal file
@@ -0,0 +1,291 @@
|
||||
use super::Indent;
|
||||
use crate::consumer::{functions::*, QualType};
|
||||
|
||||
const RET: &str = "return_val";
|
||||
const RET_POD: &str = "return_val_pod";
|
||||
|
||||
impl<'ast> Param<'ast> {
|
||||
fn write_c_to_cpp(&self, out: &mut String, level: u32) {
|
||||
let name = &self.name;
|
||||
|
||||
let indent = Indent(level);
|
||||
|
||||
match &self.kind {
|
||||
QualType::Builtin(bi) => {
|
||||
// This means we got a pod type by value, so we need to copy
|
||||
// from the C pod to the C++ type
|
||||
writesln!(out, "{indent}{} {name};", bi.cpp_type());
|
||||
writesln!(out, "{indent}memcpy(&{name}, &{name}_pod, sizeof({name}));");
|
||||
}
|
||||
QualType::Pointer { .. } => {
|
||||
let ty = self.kind.cpp_type();
|
||||
writesln!(
|
||||
out,
|
||||
"{indent}{ty} {name} = reinterpret_cast<{ty}>({name}_pod);",
|
||||
);
|
||||
}
|
||||
QualType::Reference { pointee, .. } => {
|
||||
if let QualType::Builtin(bi) = pointee.as_ref() {
|
||||
if !bi.is_pod() {
|
||||
writesln!(
|
||||
out,
|
||||
"{indent}{} {name} = *{name}_pod;",
|
||||
self.kind.cpp_type()
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let ty = self.kind.cpp_type();
|
||||
writesln!(
|
||||
out,
|
||||
"{indent}{ty} {name} = reinterpret_cast<{ty}>(*{name}_pod);",
|
||||
);
|
||||
}
|
||||
QualType::Enum { .. } => {
|
||||
writesln!(
|
||||
out,
|
||||
"{indent}auto {name} = static_cast<{}>({name}_pod);",
|
||||
self.kind.cpp_type(),
|
||||
);
|
||||
}
|
||||
QualType::Flags { .. } => {
|
||||
writesln!(
|
||||
out,
|
||||
"{indent}auto {name} = {}({name}_pod);",
|
||||
self.kind.cpp_type()
|
||||
);
|
||||
}
|
||||
QualType::Record { .. } => {
|
||||
writesln!(out, "{indent}{} {name};", self.kind.cpp_type());
|
||||
writesln!(out, "{indent}memcpy(&{name}, &{name}_pod, sizeof({name}));");
|
||||
}
|
||||
_ => panic!(
|
||||
"parameter '{}' kind '{:?}' is not supported ",
|
||||
self.name, self.kind
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> FuncBinding<'ast> {
|
||||
pub(super) fn emit_cpp(&self, acc: &mut String, level: u32) -> anyhow::Result<()> {
|
||||
// Emit the function signature, this uses the C pod types that we've
|
||||
// generated to wrap the underlying physx C++ types
|
||||
{
|
||||
let indent = Indent(level);
|
||||
|
||||
writes!(acc, "{indent}");
|
||||
|
||||
if let Some(ret) = &self.ret {
|
||||
writes!(acc, "{}", ret.c_type());
|
||||
} else {
|
||||
acc.push_str("void");
|
||||
}
|
||||
|
||||
writes!(acc, " {}(", self.name);
|
||||
|
||||
for (i, param) in self.params.iter().enumerate() {
|
||||
let sep = if i > 0 { ", " } else { "" };
|
||||
|
||||
writes!(
|
||||
acc,
|
||||
"{sep}{} {}{}",
|
||||
param.kind.c_type(),
|
||||
param.name,
|
||||
if param.kind.is_pod() { "_pod" } else { "" }
|
||||
);
|
||||
}
|
||||
|
||||
writesln!(acc, ") {{");
|
||||
}
|
||||
|
||||
let indent = Indent(level + 1);
|
||||
|
||||
// Emit the code that converts each argument to an appropriately typed/named
|
||||
// c++ variable
|
||||
if !self.params.is_empty() {
|
||||
for param in self.params.iter().filter(|p| p.kind.is_pod()) {
|
||||
param.write_c_to_cpp(acc, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
let (invoke, arg_skip) = match &self.ext {
|
||||
FuncBindingExt::IsDelete(_) => {
|
||||
writesln!(acc, "{indent}delete self_;\n{}}}", Indent(level));
|
||||
return Ok(());
|
||||
}
|
||||
FuncBindingExt::None(inv) => (inv, 0),
|
||||
FuncBindingExt::HasSelf(inv) => (inv, 1),
|
||||
};
|
||||
|
||||
// Emit the code that actually calls into physx
|
||||
let args = self
|
||||
.params
|
||||
.iter()
|
||||
.skip(arg_skip)
|
||||
.map(|param| param.name.as_ref());
|
||||
|
||||
invoke.emit(args, self.ret.as_ref(), acc, level + 1);
|
||||
|
||||
if let Some(ret) = &self.ret {
|
||||
if !ret.is_pod() {
|
||||
writesln!(acc, "{indent}return {RET};");
|
||||
} else {
|
||||
// If we're a pod type we need to generate the code to convert
|
||||
// from the C++ type to the C wrapper
|
||||
match ret {
|
||||
QualType::Builtin(bi) => {
|
||||
writesln!(acc, "{indent}{} {RET_POD};", bi.c_type());
|
||||
writesln!(
|
||||
acc,
|
||||
"{indent}memcpy(&{RET_POD}, &{RET}, sizeof({RET_POD}));"
|
||||
);
|
||||
}
|
||||
QualType::Record { name } => {
|
||||
writesln!(acc, "{indent}physx_{name} {RET_POD};");
|
||||
writesln!(
|
||||
acc,
|
||||
"{indent}memcpy(&{RET_POD}, &{RET}, sizeof({RET_POD}));"
|
||||
);
|
||||
}
|
||||
QualType::Enum { repr, .. } | QualType::Flags { repr, .. } => {
|
||||
writesln!(acc, "{indent}{} {RET_POD};", repr.c_type());
|
||||
writesln!(
|
||||
acc,
|
||||
"{indent}memcpy(&{RET_POD}, &{RET}, sizeof({RET_POD}));"
|
||||
);
|
||||
}
|
||||
QualType::Pointer { .. } => {
|
||||
writesln!(
|
||||
acc,
|
||||
"{indent}auto {RET_POD} = reinterpret_cast<{}>({RET});",
|
||||
ret.c_type()
|
||||
);
|
||||
}
|
||||
QualType::Reference { .. } => {
|
||||
writesln!(
|
||||
acc,
|
||||
"{indent}auto {RET_POD} = reinterpret_cast<{}>(&{RET});",
|
||||
ret.c_type()
|
||||
);
|
||||
}
|
||||
#[allow(clippy::unimplemented)]
|
||||
_ => {
|
||||
unimplemented!("return type is not supported {:?}", ret);
|
||||
}
|
||||
}
|
||||
|
||||
writesln!(acc, "{indent}return {RET_POD};");
|
||||
}
|
||||
}
|
||||
|
||||
writesln!(acc, "{}}}", Indent(level));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn emit_rust(&self, writer: &mut String, level: u32) {
|
||||
if let Some(com) = &self.comment {
|
||||
com.emit_rust(writer, level);
|
||||
}
|
||||
|
||||
let indent = Indent(level);
|
||||
|
||||
let mut acc = String::new();
|
||||
writes!(acc, "{indent}pub fn {}(", self.name);
|
||||
|
||||
for (i, param) in self.params.iter().enumerate() {
|
||||
// While Rust allows trailing commas in function signatures, it's
|
||||
// kind of ugly
|
||||
let sep = if i > 0 { ", " } else { "" };
|
||||
|
||||
writes!(
|
||||
acc,
|
||||
"{sep}{}: {}",
|
||||
super::RustIdent(¶m.name),
|
||||
param.kind.rust_type()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(ret) = &self.ret {
|
||||
writes!(acc, ") -> {};", ret.rust_type());
|
||||
} else {
|
||||
writes!(acc, ");");
|
||||
}
|
||||
|
||||
writesln!(writer, "{acc}");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> PhysxInvoke<'ast> {
|
||||
fn emit(
|
||||
&self,
|
||||
args: impl Iterator<Item = &'ast str>,
|
||||
return_type: Option<&QualType<'ast>>,
|
||||
out: &mut String,
|
||||
level: u32,
|
||||
) {
|
||||
let mut args = args.peekable();
|
||||
let has_args = args.peek().is_some();
|
||||
|
||||
let indent = Indent(level);
|
||||
|
||||
// Would be nice with https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.intersperse
|
||||
// but it's not stable yet
|
||||
let emit_args = |out: &mut String| {
|
||||
for (i, arg) in args.enumerate() {
|
||||
let sep = if i > 0 { ", " } else { "" };
|
||||
|
||||
writes!(out, "{sep}{arg}");
|
||||
}
|
||||
};
|
||||
|
||||
match self {
|
||||
Self::Func { func_name, .. } => {
|
||||
writes!(out, "{indent}");
|
||||
if let Some(ret) = return_type {
|
||||
writes!(out, "{} {RET} = ", ret.cpp_type());
|
||||
}
|
||||
|
||||
writes!(out, "{func_name}(");
|
||||
emit_args(out);
|
||||
writes!(out, ");\n");
|
||||
}
|
||||
Self::Method {
|
||||
func_name,
|
||||
class_name,
|
||||
is_static,
|
||||
} => {
|
||||
writes!(out, "{indent}");
|
||||
if let Some(ret) = return_type {
|
||||
writes!(out, "{} {RET} = ", ret.cpp_type());
|
||||
}
|
||||
|
||||
if *is_static {
|
||||
writes!(out, "{class_name}::{func_name}(");
|
||||
} else {
|
||||
writes!(out, "self_->{func_name}(");
|
||||
}
|
||||
|
||||
emit_args(out);
|
||||
writes!(out, ");\n");
|
||||
}
|
||||
Self::Ctor(class) => {
|
||||
writes!(out, "{indent}{class} {RET}");
|
||||
// Deal with Most Vexing Parse, thanks C++
|
||||
if has_args {
|
||||
writes!(out, "(");
|
||||
emit_args(out);
|
||||
writes!(out, ");\n");
|
||||
} else {
|
||||
writes!(out, ";\n");
|
||||
}
|
||||
}
|
||||
Self::New(class) => {
|
||||
writes!(out, "{indent}auto {RET} = new physx::{}(", class);
|
||||
emit_args(out);
|
||||
writes!(out, ");\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
modules/PhysX/physx/physx-sys/pxbind/src/generator/record.rs
Normal file
189
modules/PhysX/physx/physx-sys/pxbind/src/generator/record.rs
Normal file
@@ -0,0 +1,189 @@
|
||||
use super::{Indent, SG, UOF};
|
||||
use crate::consumer::QualType;
|
||||
|
||||
impl<'ast> crate::consumer::RecBindingDef<'ast> {
|
||||
pub(super) fn emit_structgen(&self, writer: &mut String, level: u32) {
|
||||
if self.calc_layout {
|
||||
self.emit_structgen_calc(writer, level);
|
||||
} else {
|
||||
self.emit_structgen_passthrough(writer, level);
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_structgen_calc(&self, w: &mut String, level: u32) {
|
||||
let indent = Indent(level);
|
||||
let indent1 = Indent(level + 1);
|
||||
let indent2 = Indent(level + 2);
|
||||
|
||||
let name = self.name;
|
||||
|
||||
writesln!(
|
||||
w,
|
||||
"{indent}struct physx_{name}: public physx::{name} {{"
|
||||
);
|
||||
writesln!(w, "{indent1}static void dump_layout(PodStructGen& {SG}) {{");
|
||||
writesln!(
|
||||
w,
|
||||
r#"{indent2}{SG}.begin_struct("physx_{name}", "{name}");"#
|
||||
);
|
||||
|
||||
for field in &self.fields {
|
||||
if !field.is_public || field.is_reference {
|
||||
continue;
|
||||
}
|
||||
|
||||
let fname = field.name;
|
||||
let cpp_type = field.kind.cpp_type();
|
||||
let rust_type = field.kind.rust_type();
|
||||
|
||||
writes!(w, "{indent2}{SG}.add_field(\"");
|
||||
|
||||
// We need to handle arrays specially since they break the pattern of literally every other
|
||||
// C type since the element and array lengths are split by the identifier. Sigh.
|
||||
if let QualType::Array { element, len } = &field.kind {
|
||||
// There are a couple of cases of 2-dimensional arrays :p
|
||||
if let QualType::Array {
|
||||
element: inner,
|
||||
len: len1,
|
||||
} = &**element
|
||||
{
|
||||
writes!(w, "{} {fname}[{len1}]", inner.c_type());
|
||||
} else {
|
||||
writes!(w, "{} {fname}", element.c_type());
|
||||
}
|
||||
|
||||
writes!(w, "[{len}]");
|
||||
} else {
|
||||
let c_type = field.kind.c_type();
|
||||
writes!(w, "{c_type} {fname}");
|
||||
}
|
||||
|
||||
writesln!(
|
||||
w,
|
||||
r#"", "{}", "{rust_type}", sizeof({cpp_type}), {UOF}(physx_{name}, {fname}));"#,
|
||||
super::RustIdent(fname),
|
||||
);
|
||||
}
|
||||
|
||||
writesln!(w, "{indent2}{SG}.end_struct(sizeof(physx::{name}));");
|
||||
writesln!(w, "{indent1}}}\n{indent}}};");
|
||||
writesln!(w, "{indent}physx_{name}::dump_layout({SG});");
|
||||
}
|
||||
|
||||
fn emit_structgen_passthrough(&self, w: &mut String, level: u32) {
|
||||
let indent = Indent(level);
|
||||
let cindent = Indent(1);
|
||||
|
||||
writes!(
|
||||
w,
|
||||
"{indent}{SG}.pass_thru(\"{} physx_{}",
|
||||
if !matches!(self.ast.tag_used, Some(crate::consumer::Tag::Union)) {
|
||||
"struct"
|
||||
} else {
|
||||
"union"
|
||||
},
|
||||
self.name
|
||||
);
|
||||
|
||||
if self.ast.definition_data.is_none() {
|
||||
writesln!(w, ";\\n\");");
|
||||
return;
|
||||
}
|
||||
|
||||
writes!(w, " {{\\n");
|
||||
|
||||
if self.has_vtable {
|
||||
writes!(w, "{cindent}void* vtable_;\\n");
|
||||
}
|
||||
|
||||
for field in &self.fields {
|
||||
if let QualType::Array { element, len } = &field.kind {
|
||||
writes!(w, "{cindent}{} {}[{len}];\\n", element.c_type(), field.name);
|
||||
} else {
|
||||
writes!(w, "{cindent}{} {};\\n", field.kind.c_type(), field.name);
|
||||
}
|
||||
}
|
||||
|
||||
writes!(w, "}};\\n\");");
|
||||
}
|
||||
|
||||
pub fn emit_rust(&self, w: &mut String, level: u32) -> bool {
|
||||
if self.calc_layout {
|
||||
return false;
|
||||
}
|
||||
|
||||
let indent = Indent(level);
|
||||
let indent1 = Indent(level + 1);
|
||||
|
||||
let is_union = matches!(self.ast.tag_used, Some(crate::consumer::Tag::Union));
|
||||
|
||||
writesln!(w, "{indent}#[derive(Clone, Copy)]");
|
||||
|
||||
if !is_union {
|
||||
writesln!(
|
||||
w,
|
||||
"{indent}#[cfg_attr(feature = \"debug-structs\", derive(Debug))]"
|
||||
);
|
||||
}
|
||||
writesln!(w, "{indent}#[repr(C)]");
|
||||
writesln!(
|
||||
w,
|
||||
"{indent}pub {} {} {{",
|
||||
if is_union { "union" } else { "struct" },
|
||||
self.name
|
||||
);
|
||||
|
||||
if self.has_vtable {
|
||||
writesln!(w, "{indent1}vtable_: *const std::ffi::c_void,");
|
||||
}
|
||||
|
||||
for field in &self.fields {
|
||||
if field.is_public {
|
||||
writes!(w, "{indent1}pub ");
|
||||
}
|
||||
|
||||
writesln!(w, "{}: {},", field.name, field.kind.rust_type());
|
||||
}
|
||||
|
||||
writesln!(w, "{indent}}}");
|
||||
|
||||
// Unions can't have derived Debug impls so we make our own
|
||||
if is_union {
|
||||
let indent2 = Indent(level + 2);
|
||||
writesln!(w, "{indent}#[cfg(feature = \"debug-structs\")]");
|
||||
writesln!(w, "{indent}impl std::fmt::Debug for {} {{", self.name);
|
||||
writesln!(
|
||||
w,
|
||||
"{indent1}fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{"
|
||||
);
|
||||
writesln!(w, "{indent2}f.write_str(\"{}\")", self.name);
|
||||
writesln!(w, "{indent1}}}");
|
||||
writesln!(w, "{indent}}}");
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> crate::consumer::RecBindingForward<'ast> {
|
||||
pub fn emit_structgen(&self, w: &mut String, level: u32) {
|
||||
let indent = Indent(level);
|
||||
|
||||
writes!(
|
||||
w,
|
||||
"{indent}{SG}.pass_thru(\"struct physx_{};\\n\");",
|
||||
self.name
|
||||
);
|
||||
}
|
||||
|
||||
pub fn emit_rust(&self, w: &mut String, level: u32) {
|
||||
let indent = Indent(level);
|
||||
let indent1 = Indent(level + 1);
|
||||
|
||||
writesln!(w, "{indent}#[derive(Copy, Clone)]");
|
||||
writesln!(w, "{indent}#[repr(C)]");
|
||||
writesln!(w, "{indent}pub struct {} {{", self.name);
|
||||
writesln!(w, "{indent1}_unused: [u8; 0],");
|
||||
writesln!(w, "}}");
|
||||
}
|
||||
}
|
||||
7
modules/PhysX/physx/physx-sys/pxbind/src/lib.rs
Normal file
7
modules/PhysX/physx/physx-sys/pxbind/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
pub mod consumer;
|
||||
mod dump;
|
||||
pub mod generator;
|
||||
|
||||
pub use dump::*;
|
||||
|
||||
pub type Node = clang_ast::Node<consumer::Item>;
|
||||
35
modules/PhysX/physx/physx-sys/pxbind/src/main.rs
Normal file
35
modules/PhysX/physx/physx-sys/pxbind/src/main.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use anyhow::Context as _;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
// It takes clang++ around 30 seconds to dump the JSON, so just keep a file
|
||||
// around to reduce iteration times
|
||||
let root = if let Ok(json) = std::fs::read("ast-dump.json") {
|
||||
serde_json::from_slice(&json).context("failed to parse ast-dump.json")?
|
||||
} else {
|
||||
// This is the root API include that includes all the other public APIs
|
||||
let api_h = format!("{}/PxPhysicsAPI.h", pxbind::get_include_dir()?);
|
||||
let (root, raw) = pxbind::get_parsed_ast(api_h)?;
|
||||
|
||||
std::fs::write("ast-dump.json", raw).context("failed to write ast-dump.json")?;
|
||||
|
||||
root
|
||||
};
|
||||
|
||||
let mut ast = pxbind::consumer::AstConsumer::default();
|
||||
ast.consume(&root)?;
|
||||
|
||||
let rr: std::path::PathBuf = pxbind::get_repo_root()?.into();
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
let mut structgen = File::create(rr.join("physx-sys/src/structgen/structgen.cpp"))?;
|
||||
let mut cpp = File::create(rr.join("physx-sys/src/physx_generated.hpp"))?;
|
||||
let mut rust = File::create(rr.join("physx-sys/src/physx_generated.rs"))?;
|
||||
|
||||
let generator = pxbind::generator::Generator::default();
|
||||
generator.generate_all(&ast, &mut structgen, &mut cpp, &mut rust)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc_fingerprint":1020393412623493685,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Kuju\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.78.0 (9b00956e5 2024-04-29)\nbinary: rustc\ncommit-hash: 9b00956e56009bab2aa15d7bff10916599e3d6d6\ncommit-date: 2024-04-29\nhost: x86_64-pc-windows-msvc\nrelease: 1.78.0\nLLVM version: 18.1.2\n","stderr":""}},"successes":{}}
|
||||
3
modules/PhysX/physx/physx-sys/pxbind/target/CACHEDIR.TAG
Normal file
3
modules/PhysX/physx/physx-sys/pxbind/target/CACHEDIR.TAG
Normal file
@@ -0,0 +1,3 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
15fff3338fe16caf
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"perf-literal\", \"std\"]","declared_features":"","target":12812136000324506373,"profile":12206360443249279867,"path":514390540837453068,"deps":[[15818844694086178958,"memchr",false,3696284910854410102]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\aho-corasick-7325719205e84efb\\dep-lib-aho_corasick"}}],"rustflags":[],"metadata":13904389431191498124,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
b56f9f57d9a63965
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"default\", \"std\"]","declared_features":"","target":18338613112069040866,"profile":12206360443249279867,"path":3398623636968603478,"deps":[[16045357212464686133,"build_script_build",false,4921420730370980292]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\anyhow-33087781d5b7a33f\\dep-lib-anyhow"}}],"rustflags":[],"metadata":17154292783084528516,"config":2202906307356721367,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
a95306e68384a30a
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"default\", \"std\"]","declared_features":"","target":2297296889237502566,"profile":13232757476167777671,"path":13951969448738311833,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\anyhow-ab7c18cf3a7b5f66\\dep-build-script-build-script-build"}}],"rustflags":[],"metadata":17154292783084528516,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
c479015814664c44
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[16045357212464686133,"build_script_build",false,766602063617872809]],"local":[{"RerunIfChanged":{"output":"debug\\build\\anyhow-eda7ba776fa5260e\\output","paths":["build/probe.rs"]}},{"RerunIfEnvChanged":{"var":"RUSTC_BOOTSTRAP","val":null}}],"rustflags":[],"metadata":0,"config":0,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
6a9a16bce0214086
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[]","declared_features":"","target":11726655330667564086,"profile":12206360443249279867,"path":18095504893307942540,"deps":[[1098045598771442027,"rustc_hash",false,10046108987582848972],[2511671586729554969,"serde",false,3009812188610348422]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\clang-ast-d481a288a7b0d16c\\dep-lib-clang_ast"}}],"rustflags":[],"metadata":15365661418732589432,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
78868d473ebc8b59
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"auto-color\", \"color\", \"default\", \"humantime\", \"regex\"]","declared_features":"","target":17553807293545275602,"profile":12206360443249279867,"path":6357041016660639553,"deps":[[2500285171997094844,"termcolor",false,1632694092393299734],[5523453112889398513,"is_terminal",false,8855430130372177659],[10187828652899488954,"log",false,8060913817175892080],[13547796294171082677,"humantime",false,4574831503798447096],[14982752537185592049,"regex",false,15571578597231113558]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\env_logger-56e99d5d442b8f7b\\dep-lib-env_logger"}}],"rustflags":[],"metadata":16604235976610830136,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
05163ee200614164
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"default\"]","declared_features":"","target":11271119367433188140,"profile":12206360443249279867,"path":12172711469631106695,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\heck-02b7e56dd051b17e\\dep-lib-heck"}}],"rustflags":[],"metadata":4968006677088137060,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
f82b2ca303117d3f
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[]","declared_features":"","target":10444203147181933371,"profile":12206360443249279867,"path":4372706294445872892,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\humantime-4629a5ab77780d49\\dep-lib-humantime"}}],"rustflags":[],"metadata":16972751450777833143,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
fbee1f16c9cee47a
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[]","declared_features":"","target":8847024640214747843,"profile":12206360443249279867,"path":4377015741861967496,"deps":[[11426986729031771186,"windows_sys",false,2836039361729776079]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\is-terminal-0a7ad9ee6b95796f\\dep-lib-is-terminal"}}],"rustflags":[],"metadata":10282796769989993602,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
0085d722ffcf5927
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[]","declared_features":"","target":17114873591667335244,"profile":12206360443249279867,"path":5271807057032177272,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\itoa-efe7cef573b48b40\\dep-lib-itoa"}}],"rustflags":[],"metadata":851671291587502216,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
70a0ce7d681ede6f
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"std\"]","declared_features":"","target":10943587141627988751,"profile":12206360443249279867,"path":9668473457380251647,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\log-f3a5f9f964d58f6f\\dep-lib-log"}}],"rustflags":[],"metadata":179143468214550567,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
760f1dec8ad74b33
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"alloc\", \"std\"]","declared_features":"","target":13876443730220172507,"profile":12206360443249279867,"path":16869016088127395208,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\memchr-994f69aff981d39f\\dep-lib-memchr"}}],"rustflags":[],"metadata":7513296495906230968,"config":2202906307356721367,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
c44dc8e20f9cabc3
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[18024560886749334364,"build_script_build",false,4758730596670865345]],"local":[{"RerunIfChanged":{"output":"debug\\build\\proc-macro2-54f73788dbe949be\\output","paths":["build/probe.rs"]}},{"RerunIfEnvChanged":{"var":"RUSTC_BOOTSTRAP","val":null}}],"rustflags":[],"metadata":0,"config":0,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
c17f59cc43680a42
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"proc-macro\"]","declared_features":"","target":427768481117760528,"profile":13232757476167777671,"path":13607430533783183389,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\proc-macro2-b8d17f71a68360db\\dep-build-script-build-script-build"}}],"rustflags":[],"metadata":7635439851376710101,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
43a575eadbdc4b11
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"proc-macro\"]","declared_features":"","target":2187471303096632034,"profile":13232757476167777671,"path":3452992316074397663,"deps":[[10045147784146067611,"unicode_ident",false,16873762277770283682],[18024560886749334364,"build_script_build",false,14099534650456690116]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\proc-macro2-c511da7308677aa7\\dep-lib-proc_macro2"}}],"rustflags":[],"metadata":7635439851376710101,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
0f47b60f7b9655e8
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[]","declared_features":"","target":14407593714901199159,"profile":11597332650809196192,"path":17523903030608720598,"deps":[[235571525104734574,"env_logger",false,6452457866812819064],[1287732937133714181,"clang_ast",false,9673769248703814250],[2511671586729554969,"serde",false,3009812188610348422],[7898347539352098708,"serde_json",false,4381860357230674670],[10187828652899488954,"log",false,8060913817175892080],[11709930968028960932,"heck",false,7224161933702600197],[16045357212464686133,"anyhow",false,7294044523911409589]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\pxbind-7b5c5eabd80e626f\\dep-lib-pxbind"}}],"rustflags":[],"metadata":7797948686568424061,"config":2202906307356721367,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
187a02b52e2bcaf5
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[]","declared_features":"","target":625391877448926851,"profile":11597332650809196192,"path":1684066648322511884,"deps":[[235571525104734574,"env_logger",false,6452457866812819064],[1287732937133714181,"clang_ast",false,9673769248703814250],[2511671586729554969,"serde",false,3009812188610348422],[7898347539352098708,"serde_json",false,4381860357230674670],[10187828652899488954,"log",false,8060913817175892080],[11709930968028960932,"heck",false,7224161933702600197],[16045357212464686133,"anyhow",false,7294044523911409589],[18151506772420311404,"pxbind",false,16741452645108434703]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\pxbind-8860ffe5ff381603\\dep-bin-pxbind"}}],"rustflags":[],"metadata":7797948686568424061,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
f439405effbe777f
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"proc-macro\"]","declared_features":"","target":10824007166531090010,"profile":13232757476167777671,"path":8278568829579911698,"deps":[[18024560886749334364,"proc_macro2",false,1246332558987601219]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\quote-6572dbe8242ebcbd\\dep-lib-quote"}}],"rustflags":[],"metadata":2717943770976187624,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
563509803b5c19d8
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"perf\", \"perf-backtrack\", \"perf-cache\", \"perf-dfa\", \"perf-inline\", \"perf-literal\", \"perf-onepass\", \"std\"]","declared_features":"","target":16142358731464406428,"profile":12206360443249279867,"path":14124468467888855413,"deps":[[7325384046744447800,"aho_corasick",false,12640726259290341141],[12099698704509148049,"regex_syntax",false,3045103758781574214],[14373384308191128698,"regex_automata",false,11585689692279149770],[15818844694086178958,"memchr",false,3696284910854410102]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\regex-ae8b68fa9aa6fefa\\dep-lib-regex"}}],"rustflags":[],"metadata":3256615787768725874,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
ca14343a64a3c8a0
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"alloc\", \"dfa-onepass\", \"hybrid\", \"meta\", \"nfa-backtrack\", \"nfa-pikevm\", \"nfa-thompson\", \"perf-inline\", \"perf-literal\", \"perf-literal-multisubstring\", \"perf-literal-substring\", \"std\", \"syntax\"]","declared_features":"","target":448595855551789158,"profile":12206360443249279867,"path":11649580546086723798,"deps":[[7325384046744447800,"aho_corasick",false,12640726259290341141],[12099698704509148049,"regex_syntax",false,3045103758781574214],[15818844694086178958,"memchr",false,3696284910854410102]],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\regex-automata-448c8a222c61f315\\dep-lib-regex_automata"}}],"rustflags":[],"metadata":8878122455581797878,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
46ec6126bc61422a
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":208723055495880444,"features":"[\"std\"]","declared_features":"","target":4790163008085533209,"profile":12206360443249279867,"path":11373887691066036009,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug\\.fingerprint\\regex-syntax-6cf651013ee141d8\\dep-lib-regex_syntax"}}],"rustflags":[],"metadata":17586400164587752172,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user