Merge "Add rust LSP utilities"
diff --git a/Cargo.Bazel.lock b/Cargo.Bazel.lock
index 38f8003..e70a4ca 100644
--- a/Cargo.Bazel.lock
+++ b/Cargo.Bazel.lock
@@ -1,5 +1,5 @@
{
- "checksum": "9496d946b25ee32f2e88d66571320aad6d52655f5f4e1f646ddb64b89eca1136",
+ "checksum": "7305dfa1e83bfd0222912e22f8294905db9c35e036a34182aaaf7bafa13c28ac",
"crates": {
"addr2line 0.20.0": {
"name": "addr2line",
@@ -233,6 +233,43 @@
},
"license": "MIT"
},
+ "anstyle 1.0.1": {
+ "name": "anstyle",
+ "version": "1.0.1",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/anstyle/1.0.1/download",
+ "sha256": "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "anstyle",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "anstyle",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "crate_features": {
+ "common": [
+ "default",
+ "std"
+ ],
+ "selects": {}
+ },
+ "edition": "2021",
+ "version": "1.0.1"
+ },
+ "license": "MIT OR Apache-2.0"
+ },
"anyhow 1.0.71": {
"name": "anyhow",
"version": "1.0.71",
@@ -348,13 +385,13 @@
},
"license": "MIT"
},
- "assert_cmd 1.0.8": {
+ "assert_cmd 2.0.12": {
"name": "assert_cmd",
- "version": "1.0.8",
+ "version": "2.0.12",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/assert_cmd/1.0.8/download",
- "sha256": "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe"
+ "url": "https://crates.io/api/v1/crates/assert_cmd/2.0.12/download",
+ "sha256": "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
}
},
"targets": [
@@ -376,7 +413,11 @@
"deps": {
"common": [
{
- "id": "bstr 0.2.17",
+ "id": "anstyle 1.0.1",
+ "target": "anstyle"
+ },
+ {
+ "id": "bstr 1.6.0",
"target": "bstr"
},
{
@@ -384,7 +425,7 @@
"target": "doc_comment"
},
{
- "id": "predicates 2.1.5",
+ "id": "predicates 3.0.3",
"target": "predicates"
},
{
@@ -402,8 +443,8 @@
],
"selects": {}
},
- "edition": "2018",
- "version": "1.0.8"
+ "edition": "2021",
+ "version": "2.0.12"
},
"license": "MIT OR Apache-2.0"
},
@@ -490,9 +531,9 @@
},
"license": "Apache-2.0 OR MIT"
},
- "autocxx 0.22.3": {
+ "autocxx 0.26.0": {
"name": "autocxx",
- "version": "0.22.3",
+ "version": "0.26.0",
"repository": null,
"targets": [
{
@@ -503,6 +544,15 @@
"**/*.rs"
]
}
+ },
+ {
+ "BuildScript": {
+ "crate_name": "build_script_build",
+ "crate_root": "build.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
}
],
"library_target_name": "autocxx",
@@ -513,11 +563,15 @@
"deps": {
"common": [
{
+ "id": "autocxx 0.26.0",
+ "target": "build_script_build"
+ },
+ {
"id": "cxx 1.0.97",
"target": "cxx"
},
{
- "id": "moveit 0.5.1",
+ "id": "moveit 0.6.0",
"target": "moveit"
}
],
@@ -533,24 +587,29 @@
],
"selects": {}
},
- "version": "0.22.3"
+ "version": "0.26.0"
+ },
+ "build_script_attrs": {
+ "data_glob": [
+ "**"
+ ]
},
"license": "MIT OR Apache-2.0"
},
- "autocxx-bindgen 0.59.17": {
+ "autocxx-bindgen 0.65.1": {
"name": "autocxx-bindgen",
- "version": "0.59.17",
+ "version": "0.65.1",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/autocxx-bindgen/0.59.17/download",
- "sha256": "f9a9a26dd38d385d23b1bf61bd231b77f690c4368aef4c77cee1b7a6da2e2042"
+ "url": "https://crates.io/api/v1/crates/autocxx-bindgen/0.65.1/download",
+ "sha256": "6c9fb7b8dd83a582e12157367773d8d1195f2dea54d4250aaf3426abae3237aa"
}
},
"targets": [
{
"Library": {
"crate_name": "autocxx_bindgen",
- "crate_root": "src/lib.rs",
+ "crate_root": "lib.rs",
"srcs": [
"**/*.rs"
]
@@ -573,9 +632,6 @@
],
"crate_features": {
"common": [
- "clap",
- "default",
- "env_logger",
"log",
"logging",
"runtime",
@@ -587,7 +643,7 @@
"deps": {
"common": [
{
- "id": "autocxx-bindgen 0.59.17",
+ "id": "autocxx-bindgen 0.65.1",
"target": "build_script_build"
},
{
@@ -603,14 +659,6 @@
"target": "clang_sys"
},
{
- "id": "clap 2.34.0",
- "target": "clap"
- },
- {
- "id": "env_logger 0.9.3",
- "target": "env_logger"
- },
- {
"id": "itertools 0.10.5",
"target": "itertools"
},
@@ -631,6 +679,10 @@
"target": "peeking_take_while"
},
{
+ "id": "prettyplease 0.2.12",
+ "target": "prettyplease"
+ },
+ {
"id": "proc-macro2 1.0.63",
"target": "proc_macro2"
},
@@ -651,6 +703,10 @@
"target": "shlex"
},
{
+ "id": "syn 2.0.28",
+ "target": "syn"
+ },
+ {
"id": "which 4.4.0",
"target": "which"
}
@@ -658,7 +714,7 @@
"selects": {}
},
"edition": "2018",
- "version": "0.59.17"
+ "version": "0.65.1"
},
"build_script_attrs": {
"data_glob": [
@@ -667,9 +723,9 @@
},
"license": "BSD-3-Clause"
},
- "autocxx-engine 0.22.3": {
+ "autocxx-engine 0.26.0": {
"name": "autocxx-engine",
- "version": "0.22.3",
+ "version": "0.26.0",
"repository": null,
"targets": [
{
@@ -693,6 +749,7 @@
"cc",
"default",
"reproduction_case",
+ "runtime",
"serde_json"
],
"selects": {}
@@ -700,7 +757,7 @@
"deps": {
"common": [
{
- "id": "autocxx-bindgen 0.59.17",
+ "id": "autocxx-bindgen 0.65.1",
"target": "autocxx_bindgen"
},
{
@@ -724,7 +781,7 @@
"target": "log"
},
{
- "id": "miette 4.7.1",
+ "id": "miette 5.10.0",
"target": "miette"
},
{
@@ -732,6 +789,10 @@
"target": "once_cell"
},
{
+ "id": "prettyplease 0.2.12",
+ "target": "prettyplease"
+ },
+ {
"id": "proc-macro2 1.0.63",
"target": "proc_macro2"
},
@@ -748,7 +809,7 @@
"target": "serde_json"
},
{
- "id": "syn 1.0.109",
+ "id": "syn 2.0.28",
"target": "syn"
},
{
@@ -778,19 +839,19 @@
"target": "indoc"
},
{
- "id": "strum_macros 0.24.3",
- "target": "strum_macros"
+ "id": "rustversion 1.0.13",
+ "target": "rustversion"
}
],
"selects": {}
},
- "version": "0.22.3"
+ "version": "0.26.0"
},
"license": "MIT OR Apache-2.0"
},
- "autocxx-gen 0.22.3": {
+ "autocxx-gen 0.26.0": {
"name": "autocxx-gen",
- "version": "0.22.3",
+ "version": "0.26.0",
"repository": null,
"targets": [],
"library_target_name": null,
@@ -813,7 +874,7 @@
"target": "indexmap"
},
{
- "id": "miette 4.7.1",
+ "id": "miette 5.10.0",
"target": "miette"
},
{
@@ -830,7 +891,7 @@
"deps_dev": {
"common": [
{
- "id": "assert_cmd 1.0.8",
+ "id": "assert_cmd 2.0.12",
"target": "assert_cmd"
},
{
@@ -849,13 +910,13 @@
"selects": {}
},
"edition": "2021",
- "version": "0.22.3"
+ "version": "0.26.0"
},
"license": "MIT OR Apache-2.0"
},
- "autocxx-integration-tests 0.22.3": {
+ "autocxx-integration-tests 0.26.0": {
"name": "autocxx-integration-tests",
- "version": "0.22.3",
+ "version": "0.26.0",
"repository": null,
"targets": [
{
@@ -900,6 +961,10 @@
"target": "log"
},
{
+ "id": "moveit 0.6.0",
+ "target": "moveit"
+ },
+ {
"id": "once_cell 1.18.0",
"target": "once_cell"
},
@@ -916,6 +981,10 @@
"target": "rust_info"
},
{
+ "id": "static_assertions 1.1.0",
+ "target": "static_assertions"
+ },
+ {
"id": "syn 1.0.109",
"target": "syn"
},
@@ -938,19 +1007,23 @@
"target": "indoc"
},
{
+ "id": "rustversion 1.0.13",
+ "target": "rustversion"
+ },
+ {
"id": "test-log 0.2.12",
"target": "test_log"
}
],
"selects": {}
},
- "version": "0.22.3"
+ "version": "0.26.0"
},
"license": "MIT OR Apache-2.0"
},
- "autocxx-macro 0.22.3": {
+ "autocxx-macro 0.26.0": {
"name": "autocxx-macro",
- "version": "0.22.3",
+ "version": "0.26.0",
"repository": null,
"targets": [
{
@@ -983,20 +1056,20 @@
"target": "quote"
},
{
- "id": "syn 1.0.109",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
"selects": {}
},
"edition": "2021",
- "version": "0.22.3"
+ "version": "0.26.0"
},
"license": "MIT OR Apache-2.0"
},
- "autocxx-parser 0.22.3": {
+ "autocxx-parser 0.26.0": {
"name": "autocxx-parser",
- "version": "0.22.3",
+ "version": "0.26.0",
"repository": null,
"targets": [
{
@@ -1055,7 +1128,7 @@
"target": "serde_json"
},
{
- "id": "syn 1.0.109",
+ "id": "syn 2.0.28",
"target": "syn"
},
{
@@ -1066,7 +1139,7 @@
"selects": {}
},
"edition": "2021",
- "version": "0.22.3"
+ "version": "0.26.0"
},
"license": "MIT OR Apache-2.0"
},
@@ -1163,6 +1236,45 @@
},
"license": "MIT OR Apache-2.0"
},
+ "backtrace-ext 0.2.1": {
+ "name": "backtrace-ext",
+ "version": "0.2.1",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/backtrace-ext/0.2.1/download",
+ "sha256": "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "backtrace_ext",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "backtrace_ext",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "deps": {
+ "common": [
+ {
+ "id": "backtrace 0.3.68",
+ "target": "backtrace"
+ }
+ ],
+ "selects": {}
+ },
+ "edition": "2018",
+ "version": "0.2.1"
+ },
+ "license": "MIT OR Apache-2.0"
+ },
"basic-toml 0.1.3": {
"name": "basic-toml",
"version": "0.1.3",
@@ -1364,13 +1476,49 @@
},
"license": "MIT/Apache-2.0"
},
- "bstr 0.2.17": {
- "name": "bstr",
- "version": "0.2.17",
+ "bitflags 2.3.3": {
+ "name": "bitflags",
+ "version": "2.3.3",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/bstr/0.2.17/download",
- "sha256": "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+ "url": "https://crates.io/api/v1/crates/bitflags/2.3.3/download",
+ "sha256": "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "bitflags",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "bitflags",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "crate_features": {
+ "common": [
+ "std"
+ ],
+ "selects": {}
+ },
+ "edition": "2021",
+ "version": "2.3.3"
+ },
+ "license": "MIT OR Apache-2.0"
+ },
+ "bstr 1.6.0": {
+ "name": "bstr",
+ "version": "1.6.0",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/bstr/1.6.0/download",
+ "sha256": "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
}
},
"targets": [
@@ -1391,9 +1539,8 @@
],
"crate_features": {
"common": [
+ "alloc",
"default",
- "lazy_static",
- "regex-automata",
"std",
"unicode"
],
@@ -1402,22 +1549,18 @@
"deps": {
"common": [
{
- "id": "lazy_static 1.4.0",
- "target": "lazy_static"
- },
- {
"id": "memchr 2.5.0",
"target": "memchr"
},
{
- "id": "regex-automata 0.1.10",
+ "id": "regex-automata 0.3.2",
"target": "regex_automata"
}
],
"selects": {}
},
- "edition": "2018",
- "version": "0.2.17"
+ "edition": "2021",
+ "version": "1.6.0"
},
"license": "MIT OR Apache-2.0"
},
@@ -2107,7 +2250,7 @@
"target": "quote"
},
{
- "id": "syn 2.0.22",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
@@ -2190,7 +2333,7 @@
"target": "quote"
},
{
- "id": "syn 2.0.22",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
@@ -3020,7 +3163,7 @@
"target": "quote"
},
{
- "id": "syn 2.0.22",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
@@ -3411,42 +3554,6 @@
},
"license": "MIT OR Apache-2.0"
},
- "heck 0.4.1": {
- "name": "heck",
- "version": "0.4.1",
- "repository": {
- "Http": {
- "url": "https://crates.io/api/v1/crates/heck/0.4.1/download",
- "sha256": "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
- }
- },
- "targets": [
- {
- "Library": {
- "crate_name": "heck",
- "crate_root": "src/lib.rs",
- "srcs": [
- "**/*.rs"
- ]
- }
- }
- ],
- "library_target_name": "heck",
- "common_attrs": {
- "compile_data_glob": [
- "**"
- ],
- "crate_features": {
- "common": [
- "default"
- ],
- "selects": {}
- },
- "edition": "2018",
- "version": "0.4.1"
- },
- "license": "MIT OR Apache-2.0"
- },
"hermit-abi 0.1.19": {
"name": "hermit-abi",
"version": "0.1.19",
@@ -3773,6 +3880,59 @@
},
"license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
},
+ "is-terminal 0.4.9": {
+ "name": "is-terminal",
+ "version": "0.4.9",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/is-terminal/0.4.9/download",
+ "sha256": "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "is_terminal",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "is_terminal",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "deps": {
+ "common": [],
+ "selects": {
+ "cfg(not(any(windows, target_os = \"hermit\", target_os = \"unknown\")))": [
+ {
+ "id": "rustix 0.38.7",
+ "target": "rustix"
+ }
+ ],
+ "cfg(target_os = \"hermit\")": [
+ {
+ "id": "hermit-abi 0.3.2",
+ "target": "hermit_abi"
+ }
+ ],
+ "cfg(windows)": [
+ {
+ "id": "windows-sys 0.48.0",
+ "target": "windows_sys"
+ }
+ ]
+ }
+ },
+ "edition": "2018",
+ "version": "0.4.9"
+ },
+ "license": "MIT"
+ },
"is_ci 1.1.1": {
"name": "is_ci",
"version": "1.1.1",
@@ -4269,6 +4429,45 @@
},
"license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
},
+ "linux-raw-sys 0.4.5": {
+ "name": "linux-raw-sys",
+ "version": "0.4.5",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/linux-raw-sys/0.4.5/download",
+ "sha256": "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "linux_raw_sys",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "linux_raw_sys",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "crate_features": {
+ "common": [
+ "errno",
+ "general",
+ "ioctl",
+ "no_std"
+ ],
+ "selects": {}
+ },
+ "edition": "2021",
+ "version": "0.4.5"
+ },
+ "license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
+ },
"log 0.4.19": {
"name": "log",
"version": "0.4.19",
@@ -4369,13 +4568,13 @@
},
"license": "Unlicense/MIT"
},
- "miette 4.7.1": {
+ "miette 5.10.0": {
"name": "miette",
- "version": "4.7.1",
+ "version": "5.10.0",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/miette/4.7.1/download",
- "sha256": "1c90329e44f9208b55f45711f9558cec15d7ef8295cc65ecd6d4188ae8edc58c"
+ "url": "https://crates.io/api/v1/crates/miette/5.10.0/download",
+ "sha256": "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e"
}
},
"targets": [
@@ -4396,11 +4595,12 @@
],
"crate_features": {
"common": [
- "atty",
"backtrace",
+ "backtrace-ext",
"default",
"fancy",
"fancy-no-backtrace",
+ "is-terminal",
"owo-colors",
"supports-color",
"supports-hyperlinks",
@@ -4413,14 +4613,18 @@
"deps": {
"common": [
{
- "id": "atty 0.2.14",
- "target": "atty"
- },
- {
"id": "backtrace 0.3.68",
"target": "backtrace"
},
{
+ "id": "backtrace-ext 0.2.1",
+ "target": "backtrace_ext"
+ },
+ {
+ "id": "is-terminal 0.4.9",
+ "target": "is_terminal"
+ },
+ {
"id": "once_cell 1.18.0",
"target": "once_cell"
},
@@ -4429,15 +4633,15 @@
"target": "owo_colors"
},
{
- "id": "supports-color 1.3.1",
+ "id": "supports-color 2.0.0",
"target": "supports_color"
},
{
- "id": "supports-hyperlinks 1.2.0",
+ "id": "supports-hyperlinks 2.1.0",
"target": "supports_hyperlinks"
},
{
- "id": "supports-unicode 1.0.2",
+ "id": "supports-unicode 2.0.0",
"target": "supports_unicode"
},
{
@@ -4463,23 +4667,23 @@
"proc_macro_deps": {
"common": [
{
- "id": "miette-derive 4.7.1",
+ "id": "miette-derive 5.10.0",
"target": "miette_derive"
}
],
"selects": {}
},
- "version": "4.7.1"
+ "version": "5.10.0"
},
"license": "Apache-2.0"
},
- "miette-derive 4.7.1": {
+ "miette-derive 5.10.0": {
"name": "miette-derive",
- "version": "4.7.1",
+ "version": "5.10.0",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/miette-derive/4.7.1/download",
- "sha256": "6b5bc45b761bcf1b5e6e6c4128cd93b84c218721a8d9b894aa0aff4ed180174c"
+ "url": "https://crates.io/api/v1/crates/miette-derive/5.10.0/download",
+ "sha256": "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
}
},
"targets": [
@@ -4509,14 +4713,14 @@
"target": "quote"
},
{
- "id": "syn 1.0.109",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
"selects": {}
},
"edition": "2018",
- "version": "4.7.1"
+ "version": "5.10.0"
},
"license": "Apache-2.0"
},
@@ -4595,13 +4799,13 @@
},
"license": "MIT OR Zlib OR Apache-2.0"
},
- "moveit 0.5.1": {
+ "moveit 0.6.0": {
"name": "moveit",
- "version": "0.5.1",
+ "version": "0.6.0",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/moveit/0.5.1/download",
- "sha256": "d7d756ffe4e38013507d35bf726a93fcdae2cae043ab5ce477f13857a335030d"
+ "url": "https://crates.io/api/v1/crates/moveit/0.6.0/download",
+ "sha256": "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba"
}
},
"targets": [
@@ -4638,7 +4842,7 @@
"selects": {}
},
"edition": "2018",
- "version": "0.5.1"
+ "version": "0.6.0"
},
"license": "Apache-2.0 OR MIT"
},
@@ -5041,13 +5245,13 @@
},
"license": "MIT OR Apache-2.0"
},
- "predicates 2.1.5": {
+ "predicates 3.0.3": {
"name": "predicates",
- "version": "2.1.5",
+ "version": "3.0.3",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/predicates/2.1.5/download",
- "sha256": "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
+ "url": "https://crates.io/api/v1/crates/predicates/3.0.3/download",
+ "sha256": "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9"
}
},
"targets": [
@@ -5075,6 +5279,10 @@
"deps": {
"common": [
{
+ "id": "anstyle 1.0.1",
+ "target": "anstyle"
+ },
+ {
"id": "difflib 0.4.0",
"target": "difflib"
},
@@ -5090,7 +5298,7 @@
"selects": {}
},
"edition": "2021",
- "version": "2.1.5"
+ "version": "3.0.3"
},
"license": "MIT OR Apache-2.0"
},
@@ -5167,6 +5375,74 @@
},
"license": "MIT OR Apache-2.0"
},
+ "prettyplease 0.2.12": {
+ "name": "prettyplease",
+ "version": "0.2.12",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/prettyplease/0.2.12/download",
+ "sha256": "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "prettyplease",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ },
+ {
+ "BuildScript": {
+ "crate_name": "build_script_build",
+ "crate_root": "build.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "prettyplease",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "crate_features": {
+ "common": [
+ "verbatim"
+ ],
+ "selects": {}
+ },
+ "deps": {
+ "common": [
+ {
+ "id": "prettyplease 0.2.12",
+ "target": "build_script_build"
+ },
+ {
+ "id": "proc-macro2 1.0.63",
+ "target": "proc_macro2"
+ },
+ {
+ "id": "syn 2.0.28",
+ "target": "syn"
+ }
+ ],
+ "selects": {}
+ },
+ "edition": "2021",
+ "version": "0.2.12"
+ },
+ "build_script_attrs": {
+ "data_glob": [
+ "**"
+ ],
+ "links": "prettyplease02"
+ },
+ "license": "MIT OR Apache-2.0"
+ },
"proc-macro-error 1.0.4": {
"name": "proc-macro-error",
"version": "1.0.4",
@@ -5569,36 +5845,6 @@
},
"license": "MIT OR Apache-2.0"
},
- "regex-automata 0.1.10": {
- "name": "regex-automata",
- "version": "0.1.10",
- "repository": {
- "Http": {
- "url": "https://crates.io/api/v1/crates/regex-automata/0.1.10/download",
- "sha256": "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
- }
- },
- "targets": [
- {
- "Library": {
- "crate_name": "regex_automata",
- "crate_root": "src/lib.rs",
- "srcs": [
- "**/*.rs"
- ]
- }
- }
- ],
- "library_target_name": "regex_automata",
- "common_attrs": {
- "compile_data_glob": [
- "**"
- ],
- "edition": "2015",
- "version": "0.1.10"
- },
- "license": "Unlicense/MIT"
- },
"regex-automata 0.3.2": {
"name": "regex-automata",
"version": "0.3.2",
@@ -5628,6 +5874,7 @@
"common": [
"alloc",
"dfa-onepass",
+ "dfa-search",
"hybrid",
"meta",
"nfa-backtrack",
@@ -5965,6 +6212,107 @@
},
"license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
},
+ "rustix 0.38.7": {
+ "name": "rustix",
+ "version": "0.38.7",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/rustix/0.38.7/download",
+ "sha256": "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "rustix",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ },
+ {
+ "BuildScript": {
+ "crate_name": "build_script_build",
+ "crate_root": "build.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "rustix",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "crate_features": {
+ "common": [
+ "default",
+ "std",
+ "termios",
+ "use-libc-auxv"
+ ],
+ "selects": {}
+ },
+ "deps": {
+ "common": [
+ {
+ "id": "bitflags 2.3.3",
+ "target": "bitflags"
+ },
+ {
+ "id": "rustix 0.38.7",
+ "target": "build_script_build"
+ }
+ ],
+ "selects": {
+ "cfg(all(any(target_os = \"android\", target_os = \"linux\"), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))": [
+ {
+ "id": "linux-raw-sys 0.4.5",
+ "target": "linux_raw_sys"
+ }
+ ],
+ "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))": [
+ {
+ "id": "linux-raw-sys 0.4.5",
+ "target": "linux_raw_sys"
+ }
+ ],
+ "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))": [
+ {
+ "id": "errno 0.3.1",
+ "target": "errno",
+ "alias": "libc_errno"
+ },
+ {
+ "id": "libc 0.2.147",
+ "target": "libc"
+ }
+ ],
+ "cfg(windows)": [
+ {
+ "id": "errno 0.3.1",
+ "target": "errno",
+ "alias": "libc_errno"
+ },
+ {
+ "id": "windows-sys 0.48.0",
+ "target": "windows_sys"
+ }
+ ]
+ }
+ },
+ "edition": "2021",
+ "version": "0.38.7"
+ },
+ "build_script_attrs": {
+ "data_glob": [
+ "**"
+ ]
+ },
+ "license": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
+ },
"rustversion 1.0.13": {
"name": "rustversion",
"version": "1.0.13",
@@ -6221,7 +6569,7 @@
"target": "quote"
},
{
- "id": "syn 2.0.22",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
@@ -6470,6 +6818,36 @@
},
"license": "MIT"
},
+ "static_assertions 1.1.0": {
+ "name": "static_assertions",
+ "version": "1.1.0",
+ "repository": {
+ "Http": {
+ "url": "https://crates.io/api/v1/crates/static_assertions/1.1.0/download",
+ "sha256": "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+ }
+ },
+ "targets": [
+ {
+ "Library": {
+ "crate_name": "static_assertions",
+ "crate_root": "src/lib.rs",
+ "srcs": [
+ "**/*.rs"
+ ]
+ }
+ }
+ ],
+ "library_target_name": "static_assertions",
+ "common_attrs": {
+ "compile_data_glob": [
+ "**"
+ ],
+ "edition": "2015",
+ "version": "1.1.0"
+ },
+ "license": "MIT OR Apache-2.0"
+ },
"strsim 0.10.0": {
"name": "strsim",
"version": "0.10.0",
@@ -6530,73 +6908,13 @@
},
"license": "MIT"
},
- "strum_macros 0.24.3": {
- "name": "strum_macros",
- "version": "0.24.3",
- "repository": {
- "Http": {
- "url": "https://crates.io/api/v1/crates/strum_macros/0.24.3/download",
- "sha256": "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
- }
- },
- "targets": [
- {
- "ProcMacro": {
- "crate_name": "strum_macros",
- "crate_root": "src/lib.rs",
- "srcs": [
- "**/*.rs"
- ]
- }
- }
- ],
- "library_target_name": "strum_macros",
- "common_attrs": {
- "compile_data_glob": [
- "**"
- ],
- "deps": {
- "common": [
- {
- "id": "heck 0.4.1",
- "target": "heck"
- },
- {
- "id": "proc-macro2 1.0.63",
- "target": "proc_macro2"
- },
- {
- "id": "quote 1.0.29",
- "target": "quote"
- },
- {
- "id": "syn 1.0.109",
- "target": "syn"
- }
- ],
- "selects": {}
- },
- "edition": "2018",
- "proc_macro_deps": {
- "common": [
- {
- "id": "rustversion 1.0.13",
- "target": "rustversion"
- }
- ],
- "selects": {}
- },
- "version": "0.24.3"
- },
- "license": "MIT"
- },
- "supports-color 1.3.1": {
+ "supports-color 2.0.0": {
"name": "supports-color",
- "version": "1.3.1",
+ "version": "2.0.0",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/supports-color/1.3.1/download",
- "sha256": "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f"
+ "url": "https://crates.io/api/v1/crates/supports-color/2.0.0/download",
+ "sha256": "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354"
}
},
"targets": [
@@ -6618,8 +6936,8 @@
"deps": {
"common": [
{
- "id": "atty 0.2.14",
- "target": "atty"
+ "id": "is-terminal 0.4.9",
+ "target": "is_terminal"
},
{
"id": "is_ci 1.1.1",
@@ -6629,17 +6947,17 @@
"selects": {}
},
"edition": "2018",
- "version": "1.3.1"
+ "version": "2.0.0"
},
"license": "Apache-2.0"
},
- "supports-hyperlinks 1.2.0": {
+ "supports-hyperlinks 2.1.0": {
"name": "supports-hyperlinks",
- "version": "1.2.0",
+ "version": "2.1.0",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/supports-hyperlinks/1.2.0/download",
- "sha256": "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406"
+ "url": "https://crates.io/api/v1/crates/supports-hyperlinks/2.1.0/download",
+ "sha256": "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
}
},
"targets": [
@@ -6661,24 +6979,24 @@
"deps": {
"common": [
{
- "id": "atty 0.2.14",
- "target": "atty"
+ "id": "is-terminal 0.4.9",
+ "target": "is_terminal"
}
],
"selects": {}
},
- "edition": "2018",
- "version": "1.2.0"
+ "edition": "2021",
+ "version": "2.1.0"
},
"license": "Apache-2.0"
},
- "supports-unicode 1.0.2": {
+ "supports-unicode 2.0.0": {
"name": "supports-unicode",
- "version": "1.0.2",
+ "version": "2.0.0",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/supports-unicode/1.0.2/download",
- "sha256": "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2"
+ "url": "https://crates.io/api/v1/crates/supports-unicode/2.0.0/download",
+ "sha256": "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7"
}
},
"targets": [
@@ -6700,14 +7018,14 @@
"deps": {
"common": [
{
- "id": "atty 0.2.14",
- "target": "atty"
+ "id": "is-terminal 0.4.9",
+ "target": "is_terminal"
}
],
"selects": {}
},
"edition": "2018",
- "version": "1.0.2"
+ "version": "2.0.0"
},
"license": "Apache-2.0"
},
@@ -6790,13 +7108,13 @@
},
"license": "MIT OR Apache-2.0"
},
- "syn 2.0.22": {
+ "syn 2.0.28": {
"name": "syn",
- "version": "2.0.22",
+ "version": "2.0.28",
"repository": {
"Http": {
- "url": "https://crates.io/api/v1/crates/syn/2.0.22/download",
- "sha256": "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
+ "url": "https://crates.io/api/v1/crates/syn/2.0.28/download",
+ "sha256": "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
}
},
"targets": [
@@ -6820,11 +7138,13 @@
"clone-impls",
"default",
"derive",
+ "extra-traits",
"full",
"parsing",
"printing",
"proc-macro",
- "quote"
+ "quote",
+ "visit-mut"
],
"selects": {}
},
@@ -6846,7 +7166,7 @@
"selects": {}
},
"edition": "2021",
- "version": "2.0.22"
+ "version": "2.0.28"
},
"license": "MIT OR Apache-2.0"
},
@@ -7334,7 +7654,7 @@
"target": "quote"
},
{
- "id": "syn 2.0.22",
+ "id": "syn 2.0.28",
"target": "syn"
}
],
@@ -8568,25 +8888,33 @@
},
"binary_crates": [],
"workspace_members": {
- "autocxx 0.22.3": "third_party/autocxx",
- "autocxx-engine 0.22.3": "third_party/autocxx/engine",
- "autocxx-gen 0.22.3": "third_party/autocxx/gen/cmd",
- "autocxx-integration-tests 0.22.3": "third_party/autocxx/integration-tests",
- "autocxx-macro 0.22.3": "third_party/autocxx/macro",
- "autocxx-parser 0.22.3": "third_party/autocxx/parser",
+ "autocxx 0.26.0": "third_party/autocxx",
+ "autocxx-engine 0.26.0": "third_party/autocxx/engine",
+ "autocxx-gen 0.26.0": "third_party/autocxx/gen/cmd",
+ "autocxx-integration-tests 0.26.0": "third_party/autocxx/integration-tests",
+ "autocxx-macro 0.26.0": "third_party/autocxx/macro",
+ "autocxx-parser 0.26.0": "third_party/autocxx/parser",
"compile_with_bazel 0.0.0": "",
"flatbuffers 22.10.26": "third_party/flatbuffers/rust/flatbuffers"
},
"conditions": {
"aarch64-pc-windows-gnullvm": [],
"cfg(all(any(target_os = \"android\", target_os = \"linux\"), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"), all(target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"powerpc64\", target_arch = \"riscv64\", target_arch = \"mips\", target_arch = \"mips64\"))))))))": [],
+ "cfg(all(any(target_os = \"android\", target_os = \"linux\"), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))": [],
"cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"), all(target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"powerpc64\", target_arch = \"riscv64\", target_arch = \"mips\", target_arch = \"mips64\")))))": [
"aarch64-unknown-linux-gnu",
"arm-unknown-linux-gnueabi",
"armv7-unknown-linux-gnueabihf",
"x86_64-unknown-linux-gnu"
],
+ "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))": [
+ "aarch64-unknown-linux-gnu",
+ "arm-unknown-linux-gnueabi",
+ "armv7-unknown-linux-gnueabihf",
+ "x86_64-unknown-linux-gnu"
+ ],
"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"), all(target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"powerpc64\", target_arch = \"riscv64\", target_arch = \"mips\", target_arch = \"mips64\"))))))))": [],
+ "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))": [],
"cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))": [],
"cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))": [],
"cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(windows_raw_dylib)))": [],
@@ -8613,6 +8941,12 @@
"armv7-unknown-linux-gnueabihf",
"x86_64-unknown-linux-gnu"
],
+ "cfg(not(any(windows, target_os = \"hermit\", target_os = \"unknown\")))": [
+ "aarch64-unknown-linux-gnu",
+ "arm-unknown-linux-gnueabi",
+ "armv7-unknown-linux-gnueabihf",
+ "x86_64-unknown-linux-gnu"
+ ],
"cfg(not(windows))": [
"aarch64-unknown-linux-gnu",
"arm-unknown-linux-gnueabi",
diff --git a/Cargo.lock b/Cargo.lock
index cd97ba0..5fcc5eb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -47,6 +47,12 @@
]
[[package]]
+name = "anstyle"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+
+[[package]]
name = "anyhow"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -67,10 +73,11 @@
[[package]]
name = "assert_cmd"
-version = "1.0.8"
+version = "2.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe"
+checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
dependencies = [
+ "anstyle",
"bstr",
"doc-comment",
"predicates",
@@ -98,7 +105,7 @@
[[package]]
name = "autocxx"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"aquamarine",
"autocxx-macro",
@@ -108,31 +115,31 @@
[[package]]
name = "autocxx-bindgen"
-version = "0.59.17"
+version = "0.65.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a9a26dd38d385d23b1bf61bd231b77f690c4368aef4c77cee1b7a6da2e2042"
+checksum = "6c9fb7b8dd83a582e12157367773d8d1195f2dea54d4250aaf3426abae3237aa"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"cexpr 0.6.0",
"clang-sys",
- "clap 2.34.0",
- "env_logger 0.9.3",
"itertools 0.10.5",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
+ "prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
+ "syn 2.0.28",
"which 4.4.0",
]
[[package]]
name = "autocxx-engine"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"aquamarine",
"autocxx-bindgen",
@@ -145,12 +152,13 @@
"log",
"miette",
"once_cell",
+ "prettyplease",
"proc-macro2",
"quote",
"regex",
+ "rustversion",
"serde_json",
- "strum_macros",
- "syn 1.0.109",
+ "syn 2.0.28",
"tempfile",
"thiserror",
"version_check",
@@ -158,7 +166,7 @@
[[package]]
name = "autocxx-gen"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"assert_cmd",
"autocxx",
@@ -177,7 +185,7 @@
[[package]]
name = "autocxx-integration-tests"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"autocxx",
"autocxx-engine",
@@ -188,10 +196,13 @@
"itertools 0.10.5",
"link-cplusplus",
"log",
+ "moveit",
"once_cell",
"proc-macro2",
"quote",
"rust_info",
+ "rustversion",
+ "static_assertions",
"syn 1.0.109",
"tempfile",
"test-log",
@@ -200,18 +211,18 @@
[[package]]
name = "autocxx-macro"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"autocxx-parser",
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.28",
]
[[package]]
name = "autocxx-parser"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"indexmap",
"itertools 0.10.5",
@@ -221,7 +232,7 @@
"quote",
"serde",
"serde_json",
- "syn 1.0.109",
+ "syn 2.0.28",
"thiserror",
]
@@ -241,6 +252,15 @@
]
[[package]]
+name = "backtrace-ext"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
+dependencies = [
+ "backtrace",
+]
+
+[[package]]
name = "basic-toml"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -255,7 +275,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"cexpr 0.4.0",
"clang-sys",
"clap 2.34.0",
@@ -279,14 +299,20 @@
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
-name = "bstr"
-version = "0.2.17"
+name = "bitflags"
+version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+
+[[package]]
+name = "bstr"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
dependencies = [
- "lazy_static",
"memchr",
- "regex-automata 0.1.10",
+ "regex-automata",
+ "serde",
]
[[package]]
@@ -344,7 +370,7 @@
dependencies = [
"ansi_term",
"atty",
- "bitflags",
+ "bitflags 1.3.2",
"strsim 0.8.0",
"textwrap 0.11.0",
"unicode-width",
@@ -358,7 +384,7 @@
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
- "bitflags",
+ "bitflags 1.3.2",
"clap_lex",
"indexmap",
"once_cell",
@@ -392,7 +418,7 @@
dependencies = [
"anyhow",
"bindgen",
- "bitflags",
+ "bitflags 1.3.2",
"cxx",
"cxxbridge-macro",
"futures",
@@ -426,7 +452,7 @@
"codespan-reporting",
"proc-macro2",
"quote",
- "syn 2.0.22",
+ "syn 2.0.28",
]
[[package]]
@@ -443,7 +469,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.22",
+ "syn 2.0.28",
]
[[package]]
@@ -524,7 +550,7 @@
name = "flatbuffers"
version = "22.10.26"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"rustc_version",
"serde",
]
@@ -585,7 +611,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.22",
+ "syn 2.0.28",
]
[[package]]
@@ -651,12 +677,6 @@
]
[[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.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -715,6 +735,17 @@
]
[[package]]
+name = "is-terminal"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+dependencies = [
+ "hermit-abi 0.3.2",
+ "rustix 0.38.7",
+ "windows-sys",
+]
+
+[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -798,6 +829,12 @@
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
+name = "linux-raw-sys"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+
+[[package]]
name = "log"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -811,12 +848,13 @@
[[package]]
name = "miette"
-version = "4.7.1"
+version = "5.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c90329e44f9208b55f45711f9558cec15d7ef8295cc65ecd6d4188ae8edc58c"
+checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e"
dependencies = [
- "atty",
"backtrace",
+ "backtrace-ext",
+ "is-terminal",
"miette-derive",
"once_cell",
"owo-colors",
@@ -831,13 +869,13 @@
[[package]]
name = "miette-derive"
-version = "4.7.1"
+version = "5.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b5bc45b761bcf1b5e6e6c4128cd93b84c218721a8d9b894aa0aff4ed180174c"
+checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.28",
]
[[package]]
@@ -857,9 +895,9 @@
[[package]]
name = "moveit"
-version = "0.5.1"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7d756ffe4e38013507d35bf726a93fcdae2cae043ab5ce477f13857a335030d"
+checksum = "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba"
dependencies = [
"cxx",
]
@@ -937,10 +975,11 @@
[[package]]
name = "predicates"
-version = "2.1.5"
+version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
+checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9"
dependencies = [
+ "anstyle",
"difflib",
"itertools 0.10.5",
"predicates-core",
@@ -963,6 +1002,16 @@
]
[[package]]
+name = "prettyplease"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.28",
+]
+
+[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1010,7 +1059,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
]
[[package]]
@@ -1021,18 +1070,12 @@
dependencies = [
"aho-corasick",
"memchr",
- "regex-automata 0.3.2",
+ "regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-
-[[package]]
-name = "regex-automata"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf"
@@ -1081,11 +1124,24 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
- "linux-raw-sys",
+ "linux-raw-sys 0.3.8",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399"
+dependencies = [
+ "bitflags 2.3.3",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.5",
"windows-sys",
]
@@ -1124,7 +1180,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.22",
+ "syn 2.0.28",
]
[[package]]
@@ -1166,6 +1222,12 @@
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1178,44 +1240,31 @@
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
-name = "strum_macros"
-version = "0.24.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "rustversion",
- "syn 1.0.109",
-]
-
-[[package]]
name = "supports-color"
-version = "1.3.1"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f"
+checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354"
dependencies = [
- "atty",
+ "is-terminal",
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
-version = "1.2.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406"
+checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
dependencies = [
- "atty",
+ "is-terminal",
]
[[package]]
name = "supports-unicode"
-version = "1.0.2"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2"
+checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7"
dependencies = [
- "atty",
+ "is-terminal",
]
[[package]]
@@ -1231,9 +1280,9 @@
[[package]]
name = "syn"
-version = "2.0.22"
+version = "2.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
+checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [
"proc-macro2",
"quote",
@@ -1250,7 +1299,7 @@
"cfg-if 1.0.0",
"fastrand",
"redox_syscall",
- "rustix",
+ "rustix 0.37.23",
"windows-sys",
]
@@ -1333,7 +1382,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.22",
+ "syn 2.0.28",
]
[[package]]
diff --git a/WORKSPACE b/WORKSPACE
index f65e4ee..f98a2da 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -724,29 +724,29 @@
)
http_archive(
- name = "ctre_phoenixpro_api_cpp_headers",
+ name = "ctre_phoenix6_api_cpp_headers",
build_file_content = """
cc_library(
name = 'api-cpp',
visibility = ['//visibility:public'],
- hdrs = glob(['ctre/phoenixpro/**/*.hpp', 'units/*.h']),
+ hdrs = glob(['ctre/phoenix6/**/*.hpp', 'units/*.h']),
includes = ["."],
deps = ["@//third_party/allwpilib/wpimath"],
)
""",
- sha256 = "340a9c8e726e2eb365b7a40a722df05fe7c7072c5c4a617fa0218eb6d074ad9f",
+ sha256 = "3c4da9f46c751d4981697da26d3c8680f40c87090782f5adf63412e34508f372",
urls = [
- "https://maven.ctr-electronics.com/release/com/ctre/phoenixpro/api-cpp/23.0.11/api-cpp-23.0.11-headers.zip",
+ "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/api-cpp/23.2.2/api-cpp-23.2.2-headers.zip",
],
)
http_archive(
- name = "ctre_phoenixpro_api_cpp_athena",
+ name = "ctre_phoenix6_api_cpp_athena",
build_file_content = """
filegroup(
name = 'shared_libraries',
srcs = [
- 'linux/athena/shared/libCTRE_PhoenixPro.so',
+ 'linux/athena/shared/libCTRE_Phoenix6.so',
],
visibility = ['//visibility:public'],
)
@@ -754,18 +754,18 @@
cc_library(
name = 'api-cpp',
visibility = ['//visibility:public'],
- srcs = ['linux/athena/shared/libCTRE_PhoenixPro.so'],
+ srcs = ['linux/athena/shared/libCTRE_Phoenix6.so'],
target_compatible_with = ['@//tools/platforms/hardware:roborio'],
)
""",
- sha256 = "11f392bebfe54f512be9ef59809e1a10c4497e0ce92970645f054e7e04fe7ef6",
+ sha256 = "8391cbd24582c951a8fdbcff533243be718fc54e091c068d5441bb0c18ff822c",
urls = [
- "https://maven.ctr-electronics.com/release/com/ctre/phoenixpro/api-cpp/23.0.11/api-cpp-23.0.11-linuxathena.zip",
+ "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/api-cpp/23.2.2/api-cpp-23.2.2-linuxathena.zip",
],
)
http_archive(
- name = "ctre_phoenixpro_tools_headers",
+ name = "ctre_phoenix6_tools_headers",
build_file_content = """
cc_library(
name = 'tools',
@@ -773,14 +773,14 @@
hdrs = glob(['ctre/**/*.h', 'ctre/**/*.hpp']),
)
""",
- sha256 = "7585e1bd9e581dd745e7f040ab521b966b40a04d05bc7fa82d6dafe2fb65764e",
+ sha256 = "33781c9db0a204e257928351c700295aec2bf6e2abb6a49ef237a95e98442a18",
urls = [
- "https://maven.ctr-electronics.com/release/com/ctre/phoenixpro/tools/23.0.11/tools-23.0.11-headers.zip",
+ "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/tools/23.2.2/tools-23.2.2-headers.zip",
],
)
http_archive(
- name = "ctre_phoenixpro_tools_athena",
+ name = "ctre_phoenix6_tools_athena",
build_file_content = """
filegroup(
name = 'shared_libraries',
@@ -797,9 +797,9 @@
target_compatible_with = ['@//tools/platforms/hardware:roborio'],
)
""",
- sha256 = "b1daadfe782c43ed32c2e1a3956998f9604a3fc9282ef866fd8dc1482f3b8cc9",
+ sha256 = "75ec607f81ab470bc7c01fda2b8ca7b71b7dc3378b370f806f8646db27600504",
urls = [
- "https://maven.ctr-electronics.com/release/com/ctre/phoenixpro/tools/23.0.11/tools-23.0.11-linuxathena.zip",
+ "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/tools/23.2.2/tools-23.2.2-linuxathena.zip",
],
)
diff --git a/aos/events/BUILD b/aos/events/BUILD
index 07c1f3a..d78df3a 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -3,7 +3,7 @@
load("//aos:flatbuffers.bzl", "cc_static_flatbuffer")
load("//aos:config.bzl", "aos_config")
load("//tools/build_rules:autocxx.bzl", "autocxx_library")
-load("@rules_rust//rust:defs.bzl", "rust_doc_test", "rust_test")
+load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc", "rust_doc_test", "rust_test")
package(default_visibility = ["//visibility:public"])
@@ -181,6 +181,11 @@
],
)
+rust_doc(
+ name = "event_loop_runtime_doc",
+ crate = ":event_loop_runtime",
+)
+
rust_doc_test(
name = "event_loop_runtime_doc_test",
crate = ":event_loop_runtime",
@@ -259,6 +264,60 @@
],
)
+rust_binary(
+ name = "ping_rs",
+ srcs = [
+ "ping.rs",
+ ],
+ data = [
+ ":pingpong_config",
+ ],
+ rustc_flags = ["-Crelocation-model=static"],
+ target_compatible_with = select({
+ "//conditions:default": ["//tools/platforms/rust:has_support"],
+ "//tools:has_msan": ["@platforms//:incompatible"],
+ }),
+ deps = [
+ ":event_loop_runtime",
+ ":ping_rust_fbs",
+ ":pong_rust_fbs",
+ ":shm_event_loop_rs",
+ "//aos:configuration_rs",
+ "//aos:configuration_rust_fbs",
+ "//aos:flatbuffers_rs",
+ "//aos:init_rs",
+ "@com_github_google_flatbuffers//rust",
+ "@crate_index//:futures",
+ ],
+)
+
+rust_binary(
+ name = "pong_rs",
+ srcs = [
+ "pong.rs",
+ ],
+ data = [
+ ":pingpong_config",
+ ],
+ rustc_flags = ["-Crelocation-model=static"],
+ target_compatible_with = select({
+ "//conditions:default": ["//tools/platforms/rust:has_support"],
+ "//tools:has_msan": ["@platforms//:incompatible"],
+ }),
+ deps = [
+ ":event_loop_runtime",
+ ":ping_rust_fbs",
+ ":pong_rust_fbs",
+ ":shm_event_loop_rs",
+ "//aos:configuration_rs",
+ "//aos:configuration_rust_fbs",
+ "//aos:flatbuffers_rs",
+ "//aos:init_rs",
+ "@com_github_google_flatbuffers//rust",
+ "@crate_index//:futures",
+ ],
+)
+
aos_config(
name = "aos_config",
src = "aos.json",
@@ -520,6 +579,15 @@
],
)
+cc_library(
+ name = "shm_event_loop_for_rust",
+ hdrs = ["shm_event_loop_for_rust.h"],
+ deps = [
+ ":event_loop",
+ ":simulated_event_loop",
+ ],
+)
+
autocxx_library(
name = "simulated_event_loop_rs",
srcs = ["simulated_event_loop.rs"],
@@ -560,6 +628,66 @@
],
)
+autocxx_library(
+ name = "shm_event_loop_rs",
+ srcs = ["shm_event_loop.rs"],
+ crate_name = "aos_events_shm_event_loop",
+ libs = [
+ ":shm_event_loop",
+ ":shm_event_loop_for_rust",
+ ],
+ rs_deps = [
+ "@com_github_google_flatbuffers//rust",
+ "@crate_index//:futures",
+ "//aos:configuration_rust_fbs",
+ "//aos:flatbuffers_rs",
+ ],
+ target_compatible_with = select({
+ "//conditions:default": ["//tools/platforms/rust:has_support"],
+ "//tools:has_msan": ["@platforms//:incompatible"],
+ }),
+ visibility = ["//visibility:public"],
+ deps = [
+ ":event_loop_runtime",
+ "//aos:configuration_rs",
+ ],
+)
+
+rust_doc(
+ name = "shm_event_loop_rs_doc",
+ crate = ":shm_event_loop_rs",
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+)
+
+rust_test(
+ name = "shm_event_loop_rs_test",
+ crate = ":shm_event_loop_rs",
+ data = [":pingpong_config"],
+ # TODO: Make Rust play happy with pic vs nopic. Details at:
+ # https://github.com/bazelbuild/rules_rust/issues/118
+ rustc_flags = ["-Crelocation-model=static"],
+ target_compatible_with = select({
+ "//conditions:default": ["//tools/platforms/rust:has_support"],
+ "//tools:has_msan": ["@platforms//:incompatible"],
+ }),
+ deps = [
+ ":ping_rust_fbs",
+ "//aos:init_rs",
+ "@crate_index//:futures",
+ "@rules_rust//tools/runfiles",
+ ],
+)
+
+rust_doc_test(
+ name = "shm_event_loop_rs_doc_test",
+ crate = ":shm_event_loop_rs",
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+ deps = [
+ ":ping_rust_fbs",
+ ":pong_rust_fbs",
+ ],
+)
+
cc_test(
name = "event_scheduler_test",
srcs = ["event_scheduler_test.cc"],
diff --git a/aos/events/event_loop_runtime.cc b/aos/events/event_loop_runtime.cc
index 727d806..e3d73c1 100644
--- a/aos/events/event_loop_runtime.cc
+++ b/aos/events/event_loop_runtime.cc
@@ -8,4 +8,22 @@
OnRunForRust::~OnRunForRust() { --runtime_->child_count_; }
bool OnRunForRust::is_running() const { return runtime_->is_running(); }
+std::unique_ptr<TimerForRust> TimerForRust::Make(EventLoopRuntime *runtime) {
+ auto handler = std::unique_ptr<TimerForRust>(new TimerForRust());
+ TimerForRust *inner = handler.get();
+ handler->timer_ = runtime->event_loop()->AddTimer([inner, runtime] {
+ inner->expired_ = true;
+ runtime->DoPoll();
+ });
+ return handler;
+}
+
+bool TimerForRust::Poll() {
+ if (expired_) {
+ // Reset it for next poll.
+ expired_ = false;
+ return true;
+ }
+ return false;
+}
} // namespace aos
diff --git a/aos/events/event_loop_runtime.h b/aos/events/event_loop_runtime.h
index 325560f..7cc551f 100644
--- a/aos/events/event_loop_runtime.h
+++ b/aos/events/event_loop_runtime.h
@@ -6,6 +6,7 @@
// particularly ergonomic for C++. See the Rust wrapper for detailed
// documentation.
+#include <chrono>
#include <memory>
#include <optional>
@@ -139,6 +140,41 @@
EventLoopRuntime *const runtime_;
};
+class TimerForRust {
+ public:
+ static std::unique_ptr<TimerForRust> Make(EventLoopRuntime *runtime);
+
+ TimerForRust(const TimerForRust &) = delete;
+ TimerForRust(TimerForRust &&) = delete;
+
+ TimerForRust &operator=(const TimerForRust &) = delete;
+ TimerForRust &operator=(TimerForRust &&) = delete;
+
+ ~TimerForRust() { timer_->Disable(); }
+
+ void Schedule(int64_t base, int64_t repeat_offset) {
+ timer_->Schedule(
+ monotonic_clock::time_point(std::chrono::nanoseconds(base)),
+ std::chrono::nanoseconds(repeat_offset));
+ }
+
+ void Disable() { timer_->Disable(); }
+
+ bool IsDisabled() const { return timer_->IsDisabled(); }
+
+ void set_name(rust::Str name) { timer_->set_name(RustStrToStringView(name)); }
+ rust::Str name() const { return StringViewToRustStr(timer_->name()); }
+
+ // If true, the timer is expired.
+ bool Poll();
+
+ private:
+ TimerForRust() = default;
+
+ TimerHandler *timer_;
+ bool expired_ = false;
+};
+
class EventLoopRuntime {
public:
EventLoopRuntime(EventLoop *event_loop) : event_loop_(event_loop) {}
@@ -199,8 +235,11 @@
OnRunForRust MakeOnRun() { return OnRunForRust(this); }
+ std::unique_ptr<TimerForRust> AddTimer() { return TimerForRust::Make(this); }
+
private:
friend class OnRunForRust;
+ friend class TimerForRust;
// Polls the top-level future once. This is what all the callbacks should do.
void DoPoll() {
diff --git a/aos/events/event_loop_runtime.rs b/aos/events/event_loop_runtime.rs
index 76c1e2e..35a4225 100644
--- a/aos/events/event_loop_runtime.rs
+++ b/aos/events/event_loop_runtime.rs
@@ -47,6 +47,7 @@
future::Future,
marker::PhantomData,
mem::ManuallyDrop,
+ ops::Add,
panic::{catch_unwind, AssertUnwindSafe},
pin::Pin,
slice,
@@ -84,6 +85,7 @@
generate!("aos::OnRunForRust")
generate!("aos::EventLoopRuntime")
generate!("aos::ExitHandle")
+generate!("aos::TimerForRust")
subclass!("aos::ApplicationFuture", RustApplicationFuture)
@@ -681,6 +683,115 @@
pub fn is_running(&self) -> bool {
self.0.is_running()
}
+
+ /// Returns an unarmed timer.
+ pub fn add_timer(&mut self) -> Timer {
+ Timer(self.0.as_mut().AddTimer())
+ }
+
+ /// Returns a timer that goes off every `duration`-long ticks.
+ pub fn add_interval(&mut self, duration: Duration) -> Timer {
+ let mut timer = self.add_timer();
+ timer.setup(self.monotonic_now(), Some(duration));
+ timer
+ }
+}
+
+/// An event loop primitive that allows sleeping asynchronously.
+///
+/// # Examples
+///
+/// ```no_run
+/// # use aos_events_event_loop_runtime::EventLoopRuntime;
+/// # use std::time::Duration;
+/// # fn compile_check(runtime: &mut EventLoopRuntime<'_>) {
+/// # let mut timer = runtime.add_timer();
+/// // Goes as soon as awaited.
+/// timer.setup(runtime.monotonic_now(), None);
+/// // Goes off once in 2 seconds.
+/// timer.setup(runtime.monotonic_now() + Duration::from_secs(2), None);
+/// // Goes off as soon as awaited and every 2 seconds afterwards.
+/// timer.setup(runtime.monotonic_now(), Some(Duration::from_secs(1)));
+/// async {
+/// for i in 0..10 {
+/// timer.tick().await;
+/// }
+/// // Timer won't off anymore. Next `tick` will never return.
+/// timer.disable();
+/// timer.tick().await;
+/// };
+/// # }
+/// ```
+pub struct Timer(UniquePtr<ffi::aos::TimerForRust>);
+
+/// A "tick" for a [`Timer`].
+///
+/// This is the raw future generated by the [`Timer::tick`] function.
+pub struct TimerTick<'a>(&'a mut Timer);
+
+impl Timer {
+ /// Arms the timer.
+ ///
+ /// The timer should sleep until `base`, `base + repeat`, `base + repeat * 2`, ...
+ /// If `repeat` is `None`, then the timer only expires once at `base`.
+ pub fn setup(&mut self, base: MonotonicInstant, repeat: Option<Duration>) {
+ self.0.pin_mut().Schedule(
+ base.0,
+ repeat
+ .unwrap_or(Duration::from_nanos(0))
+ .as_nanos()
+ .try_into()
+ .expect("Out of range: Internal clock uses 64 bits"),
+ );
+ }
+
+ /// Disarms the timer.
+ ///
+ /// Can be re-enabled by calling `setup` again.
+ pub fn disable(&mut self) {
+ self.0.pin_mut().Disable();
+ }
+
+ /// Returns `true` if the timer is enabled.
+ pub fn is_enabled(&self) -> bool {
+ !self.0.IsDisabled()
+ }
+
+ /// Sets the name of the timer.
+ ///
+ /// This can be useful to get a descriptive name in the timing reports.
+ pub fn set_name(&mut self, name: &str) {
+ self.0.pin_mut().set_name(name);
+ }
+
+ /// Gets the name of the timer.
+ pub fn name(&self) -> &str {
+ self.0.name()
+ }
+
+ /// Returns a tick which can be `.await`ed.
+ ///
+ /// This tick will resolve on the next timer expired.
+ pub fn tick(&mut self) -> TimerTick {
+ TimerTick(self)
+ }
+
+ /// Polls the timer, returning `[Poll::Ready]` only once the timer expired.
+ fn poll(&mut self) -> Poll<()> {
+ if self.0.pin_mut().Poll() {
+ Poll::Ready(())
+ } else {
+ Poll::Pending
+ }
+ }
+}
+
+impl Future for TimerTick<'_> {
+ type Output = ();
+
+ fn poll(mut self: Pin<&mut Self>, _: &mut std::task::Context) -> Poll<()> {
+ self.0.poll()
+ }
}
/// Provides async blocking access to messages on a channel. This will return every message on the
@@ -1342,6 +1453,14 @@
}
}
+impl Add<Duration> for MonotonicInstant {
+ type Output = MonotonicInstant;
+
+ fn add(self, rhs: Duration) -> Self::Output {
+ Self(self.0 + i64::try_from(rhs.as_nanos()).unwrap())
+ }
+}
+
impl fmt::Debug for MonotonicInstant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.duration_since_epoch().fmt(f)
diff --git a/aos/events/ping.rs b/aos/events/ping.rs
new file mode 100644
index 0000000..b9725b8
--- /dev/null
+++ b/aos/events/ping.rs
@@ -0,0 +1,87 @@
+use aos_configuration as config;
+use aos_events_event_loop_runtime::{EventLoopRuntime, Sender, Watcher};
+use aos_events_shm_event_loop::ShmEventLoop;
+use core::cell::Cell;
+use core::future::Future;
+use core::time::Duration;
+use futures::never::Never;
+use std::path::Path;
+
+use ping_rust_fbs::aos::examples as ping;
+use pong_rust_fbs::aos::examples as pong;
+
+fn main() {
+ aos_init::init();
+ let config = config::read_config_from(Path::new("pingpong_config.json")).unwrap();
+ let ping = PingTask::new();
+ ShmEventLoop::new(&config).run_with(|runtime| {
+ let task = ping.tasks(runtime);
+ runtime.spawn(task);
+ });
+}
+
+#[derive(Debug)]
+struct PingTask {
+ counter: Cell<i32>,
+}
+
+impl PingTask {
+ pub fn new() -> Self {
+ Self {
+ counter: Cell::new(0),
+ }
+ }
+
+ /// Returns a future with all the tasks for the ping process
+ pub fn tasks(&self, event_loop: &mut EventLoopRuntime) -> impl Future<Output = Never> + '_ {
+ let ping = self.ping(event_loop);
+ let handle_pong = self.handle_pong(event_loop);
+
+ async move {
+ futures::join!(ping, handle_pong);
+ unreachable!("Let's hope `never_type` gets stabilized soon :)");
+ }
+ }
+
+ fn ping(&self, event_loop: &mut EventLoopRuntime) -> impl Future<Output = Never> + '_ {
+ // The sender is used to send messages back to the pong channel.
+ let mut ping_sender: Sender<ping::Ping> = event_loop.make_sender("/test").unwrap();
+ let startup = event_loop.on_run();
+
+ let mut interval = event_loop.add_interval(Duration::from_secs(1));
+
+ async move {
+ // Wait for startup.
+ startup.await;
+ loop {
+ interval.tick().await;
+ self.counter.set(self.counter.get() + 1);
+ let mut builder = ping_sender.make_builder();
+ let mut ping = ping::PingBuilder::new(builder.fbb());
+ let iter = self.counter.get();
+ ping.add_value(iter);
+ let ping = ping.finish();
+ builder.send(ping).expect("Can't send ping");
+ }
+ }
+ }
+
+ fn handle_pong(&self, event_loop: &mut EventLoopRuntime) -> impl Future<Output = Never> + '_ {
+ // The watcher gives us incoming ping messages.
+ let mut pong_watcher: Watcher<pong::Pong> = event_loop.make_watcher("/test").unwrap();
+ let startup = event_loop.on_run();
+
+ async move {
+ // Wait for startup.
+ startup.await;
+ loop {
+ let pong = dbg!(pong_watcher.next().await);
+ assert_eq!(
+ pong.message().unwrap().value(),
+ self.counter.get(),
+ "Missed a reply"
+ );
+ }
+ }
+ }
+}
diff --git a/aos/events/pong.rs b/aos/events/pong.rs
new file mode 100644
index 0000000..b817ac2
--- /dev/null
+++ b/aos/events/pong.rs
@@ -0,0 +1,42 @@
+use aos_configuration as config;
+use aos_events_event_loop_runtime::{EventLoopRuntime, Sender, Watcher};
+use aos_events_shm_event_loop::ShmEventLoop;
+use core::future::Future;
+use futures::never::Never;
+use std::path::Path;
+
+use ping_rust_fbs::aos::examples as ping;
+use pong_rust_fbs::aos::examples as pong;
+
+fn main() {
+ aos_init::init();
+ let config = config::read_config_from(Path::new("pingpong_config.json")).unwrap();
+ ShmEventLoop::new(&config).run_with(|runtime| {
+ let task = pong(runtime);
+ runtime.spawn(task);
+ });
+}
+
+/// Responds to ping messages with an equivalent pong.
+fn pong(event_loop: &mut EventLoopRuntime) -> impl Future<Output = Never> {
+ // The watcher gives us incoming ping messages.
+ let mut ping_watcher: Watcher<ping::Ping> = event_loop.make_watcher("/test").unwrap();
+
+ // The sender is used to send messages back to the pong channel.
+ let mut pong_sender: Sender<pong::Pong> = event_loop.make_sender("/test").unwrap();
+ // Wait for startup.
+ let startup = event_loop.on_run();
+
+ async move {
+ startup.await;
+ loop {
+ let ping = dbg!(ping_watcher.next().await);
+
+ let mut builder = pong_sender.make_builder();
+ let mut pong = pong::PongBuilder::new(builder.fbb());
+ pong.add_value(ping.message().unwrap().value());
+ let pong = pong.finish();
+ builder.send(pong).expect("Can't send pong reponse");
+ }
+ }
+}
diff --git a/aos/events/shm_event_loop.cc b/aos/events/shm_event_loop.cc
index 8ed6e0e..8523cdf 100644
--- a/aos/events/shm_event_loop.cc
+++ b/aos/events/shm_event_loop.cc
@@ -73,6 +73,14 @@
return configuration::GetMyNode(configuration);
}
+void IgnoreWakeupSignal() {
+ struct sigaction action;
+ action.sa_handler = SIG_IGN;
+ PCHECK(sigemptyset(&action.sa_mask) == 0);
+ action.sa_flags = 0;
+ PCHECK(sigaction(ipc_lib::kWakeupSignal, &action, nullptr) == 0);
+}
+
} // namespace
ShmEventLoop::ShmEventLoop(const Configuration *configuration)
@@ -81,6 +89,11 @@
shm_base_(FLAGS_shm_base),
name_(FLAGS_application_name),
node_(MaybeMyNode(configuration)) {
+ // Ignore the wakeup signal by default. Otherwise, we have race conditions on
+ // shutdown where a wakeup signal will uncleanly terminate the process.
+ // See LocklessQueueWakeUpper::Wakeup() for some more information.
+ IgnoreWakeupSignal();
+
CHECK(IsInitialized()) << ": Need to initialize AOS first.";
ClearContext();
if (configuration->has_nodes()) {
diff --git a/aos/events/shm_event_loop.rs b/aos/events/shm_event_loop.rs
new file mode 100644
index 0000000..3e387ef
--- /dev/null
+++ b/aos/events/shm_event_loop.rs
@@ -0,0 +1,302 @@
+pub use aos_configuration::{Configuration, ConfigurationExt};
+pub use aos_events_event_loop_runtime::EventLoop;
+pub use aos_events_event_loop_runtime::{CppExitHandle, EventLoopRuntime, ExitHandle};
+
+use aos_configuration_fbs::aos::Configuration as RustConfiguration;
+use aos_flatbuffers::{transmute_table_to, Flatbuffer};
+use autocxx::WithinBox;
+use core::marker::PhantomData;
+use core::pin::Pin;
+use std::boxed::Box;
+use std::ops::{Deref, DerefMut};
+
+autocxx::include_cpp! (
+#include "aos/events/shm_event_loop.h"
+#include "aos/events/shm_event_loop_for_rust.h"
+
+safety!(unsafe)
+
+generate!("aos::ShmEventLoopForRust")
+
+extern_cpp_type!("aos::ExitHandle", crate::CppExitHandle)
+extern_cpp_type!("aos::Configuration", crate::Configuration)
+extern_cpp_type!("aos::EventLoop", crate::EventLoop)
+);
+
+/// A Rust-owned C++ `ShmEventLoop` object.
+pub struct ShmEventLoop<'config> {
+ inner: Pin<Box<ffi::aos::ShmEventLoopForRust>>,
+ _config: PhantomData<&'config Configuration>,
+}
+
+impl<'config> ShmEventLoop<'config> {
+ /// Creates a Rust-owned ShmEventLoop.
+ pub fn new(config: &'config impl Flatbuffer<RustConfiguration<'static>>) -> Self {
+ // SAFETY: The `_config` represents the lifetime of this pointer we're handing off to c++ to
+ // store.
+ let event_loop = unsafe {
+ ffi::aos::ShmEventLoopForRust::new(transmute_table_to::<Configuration>(
+ &config.message()._tab,
+ ))
+ }
+ .within_box();
+
+ Self {
+ inner: event_loop,
+ _config: PhantomData,
+ }
+ }
+
+ /// Provides a runtime to construct the application and runs the event loop.
+ ///
+ /// The runtime is the only way to interact with the event loop. It provides the functionality
+ /// to spawn a task, construct timers, watchers, fetchers, and so on.
+ ///
+ /// Making an [`EventLoopRuntime`] is tricky since the lifetime of the runtime is invariant
+ /// w.r.t the event loop. In other words, the runtime and the event loop must have the same
+ /// lifetime. By providing access to the runtime through an [`FnOnce`], we can guarantee
+ /// that the runtime and the event loop both have the same lifetime.
+ ///
+ /// # Examples
+ ///
+ /// A ping application might do something like the following
+ ///
+ /// ```no_run
+ /// # use aos_events_shm_event_loop::*;
+ /// use ping_rust_fbs::aos::examples as ping;
+ /// use pong_rust_fbs::aos::examples as pong;
+ /// use std::cell::Cell;
+ /// use std::path::Path;
+ /// use aos_configuration::read_config_from;
+ /// use aos_events_event_loop_runtime::{Sender, Watcher};
+ ///
+ /// let config = read_config_from(Path::new("path/to/aos_config.json")).unwrap();
+ /// let event_loop = ShmEventLoop::new(&config);
+ /// event_loop.run_with(|runtime| {
+ /// // One task will send a ping, the other will listen to pong messages.
+ /// let mut sender: Sender<ping::Ping> = runtime
+ /// .make_sender("/test")
+ /// .expect("Can't create `Ping` sender");
+ ///
+ /// let on_run = runtime.on_run();
+ /// // Sends a single ping message.
+ /// let send_task = async move {
+ /// on_run.await;
+ /// let mut builder = sender.make_builder();
+ /// let mut ping = ping::PingBuilder::new(builder.fbb());
+ /// ping.add_value(10);
+ /// let ping = ping.finish();
+ /// builder.send(ping).expect("Can't send ping");
+ /// };
+ ///
+ /// let mut watcher: Watcher<pong::Pong> = runtime
+ /// .make_watcher("/test")
+ /// .expect("Can't create `Ping` watcher");
+ ///
+ /// // Listens to pong messages and prints them.
+ /// let receive_task = async move {
+ /// loop {
+ /// let pong = dbg!(watcher.next().await);
+ /// }
+ /// };
+ ///
+ /// runtime.spawn(async move {
+ /// futures::join!(send_task, receive_task);
+ /// std::future::pending().await
+ /// });
+ /// }); // Event loop starts runnning...
+ /// unreachable!("This can't be reached since no ExitHandle was made");
+ /// ```
+ ///
+ /// `run_with` can also borrow data from the outer scope that can be used in the async task.
+ ///
+ /// ```no_run
+ /// # use aos_events_shm_event_loop::*;
+ /// # use std::cell::Cell;
+ /// # use std::path::Path;
+ /// # use aos_configuration::read_config_from;
+ /// let config = read_config_from(Path::new("path/to/aos_config.json")).unwrap();
+ /// let shared_data = Cell::new(971);
+ /// let shared_data = &shared_data;
+ /// let event_loop = ShmEventLoop::new(&config);
+ /// event_loop.run_with(|runtime| {
+ /// // Note how `Cell` is enough since the event loop is single threaded.
+ /// let t1 = async move {
+ /// shared_data.set(shared_data.get() + 1);
+ /// };
+ /// let t2 = async move {
+ /// shared_data.set(shared_data.get() + 1);
+ /// };
+ ///
+ /// runtime.spawn(async move {
+ /// futures::join!(t1, t2);
+ /// std::future::pending().await
+ /// });
+ /// });
+ /// unreachable!("This can't be reached since no ExitHandle was made");
+ /// ```
+ ///
+ /// However, the spawned future must outlive `run_with`.
+ ///
+ /// ```compile_fail
+ /// # use aos_events_shm_event_loop::*;
+ /// # use std::cell::Cell;
+ /// # use std::path::Path;
+ /// # use aos_configuration::read_config_from;
+ /// let config = read_config_from(Path::new("path/to/aos_config.json")).unwrap();
+ /// let event_loop = ShmEventLoop::new(&config);
+ /// event_loop.run_with(|runtime| {
+ /// // ERROR: `shared_data` doesn't live long enough.
+ /// let shared_data = Cell::new(971);
+ /// let t1 = async {
+ /// shared_data.set(shared_data.get() + 1);
+ /// };
+ /// let t2 = async {
+ /// shared_data.set(shared_data.get() + 1);
+ /// };
+ ///
+ /// runtime.spawn(async move {
+ /// futures::join!(t1, t2);
+ /// std::future::pending().await
+ /// });
+ /// });
+ /// ```
+ pub fn run_with<'env, F>(mut self, fun: F)
+ where
+ F: for<'event_loop> FnOnce(&mut Scoped<'event_loop, 'env, EventLoopRuntime<'event_loop>>),
+ {
+ // SAFETY: The runtime and the event loop (i.e. self) both get destroyed at the end of this
+ // scope: first the runtime followed by the event loop. The runtime gets exclusive access
+ // during initialization in `fun` while the event loop remains unused.
+ let runtime = unsafe { EventLoopRuntime::new(self.inner.as_mut().event_loop_mut()) };
+ let mut runtime = Scoped::new(runtime);
+ fun(&mut runtime);
+ self.run();
+ }
+
+ /// Makes an exit handle.
+ ///
+ /// Awaiting on the exit handle is the only way to actually exit the event loop
+ /// task, other than panicking.
+ pub fn make_exit_handle(&mut self) -> ExitHandle {
+ self.inner.as_mut().MakeExitHandle().into()
+ }
+
+ /// Runs the spawned task to completion.
+ fn run(&mut self) {
+ self.inner.as_mut().Run();
+ }
+}
+
+/// A wrapper over some data that lives for the duration of a scope.
+///
+/// This struct ensures the existence of some `'env` which outlives `'scope`. In
+/// the presence of higher-ranked trait bounds which require types that work for
+/// any `'scope`, this allows the compiler to propagate lifetime bounds which
+/// outlive any of the possible `'scope`. This is the simplest way to express
+/// this concept to the compiler right now.
+pub struct Scoped<'scope, 'env: 'scope, T: 'scope> {
+ data: T,
+ _env: PhantomData<fn(&'env ()) -> &'env ()>,
+ _scope: PhantomData<fn(&'scope ()) -> &'scope ()>,
+}
+
+impl<'scope, 'env: 'scope, T: 'scope> Scoped<'scope, 'env, T> {
+ /// Makes the [`Scoped`].
+ pub fn new(data: T) -> Self {
+ Self {
+ data,
+ _env: PhantomData,
+ _scope: PhantomData,
+ }
+ }
+}
+
+impl<'scope, 'env: 'scope, T: 'scope> Deref for Scoped<'scope, 'env, T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.data
+ }
+}
+
+impl<'scope, 'env: 'scope, T: 'scope> DerefMut for Scoped<'scope, 'env, T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.data
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use runfiles::Runfiles;
+
+ use aos_configuration::read_config_from;
+ use aos_events_event_loop_runtime::{Sender, Watcher};
+ use aos_init::test_init;
+ use ping_rust_fbs::aos::examples as ping;
+ use std::sync::atomic::{AtomicUsize, Ordering};
+ use std::sync::Barrier;
+
+ /// Tests basic functionality with 2 threads operating their own event loops.
+ #[test]
+ fn smoke_test() {
+ test_init();
+
+ let r = Runfiles::create().unwrap();
+ let config =
+ read_config_from(&r.rlocation("org_frc971/aos/events/pingpong_config.json")).unwrap();
+
+ const VALUE: i32 = 971;
+ let barrier = Barrier::new(2);
+ let count = AtomicUsize::new(0);
+
+ std::thread::scope(|s| {
+ let config = &config;
+ let barrier = &barrier;
+ let count = &count;
+ s.spawn(move || {
+ let mut event_loop = ShmEventLoop::new(config);
+ let exit_handle = event_loop.make_exit_handle();
+ event_loop.run_with(|runtime| {
+ let mut watcher: Watcher<ping::Ping> = runtime
+ .make_watcher("/test")
+ .expect("Can't create `Ping` watcher");
+ let on_run = runtime.on_run();
+ runtime.spawn(async move {
+ on_run.await;
+ barrier.wait();
+ let ping = watcher.next().await;
+ assert_eq!(ping.message().unwrap().value(), VALUE);
+ count.fetch_add(1, Ordering::Relaxed);
+ exit_handle.exit().await
+ });
+ });
+ });
+ s.spawn(move || {
+ let mut event_loop = ShmEventLoop::new(config);
+ let exit_handle = event_loop.make_exit_handle();
+ event_loop.run_with(|runtime| {
+ let mut sender: Sender<ping::Ping> = runtime
+ .make_sender("/test")
+ .expect("Can't create `Ping` sender");
+ let on_run = runtime.on_run();
+ runtime.spawn(async move {
+ on_run.await;
+ // Give the waiting thread a chance to start.
+ barrier.wait();
+ let mut sender = sender.make_builder();
+ let mut ping = ping::PingBuilder::new(sender.fbb());
+ ping.add_value(VALUE);
+ let ping = ping.finish();
+ sender.send(ping).expect("send should succeed");
+ count.fetch_add(1, Ordering::Relaxed);
+ exit_handle.exit().await
+ });
+ });
+ });
+ });
+
+ assert_eq!(count.into_inner(), 2, "Not all event loops ran.");
+ }
+}
diff --git a/aos/events/shm_event_loop_for_rust.h b/aos/events/shm_event_loop_for_rust.h
new file mode 100644
index 0000000..3a815e1
--- /dev/null
+++ b/aos/events/shm_event_loop_for_rust.h
@@ -0,0 +1,31 @@
+#ifndef AOS_EVENTS_SHM_EVENT_LOOP_FOR_RUST_H_
+#define AOS_EVENTS_SHM_EVENT_LOOP_FOR_RUST_H_
+
+#include <memory>
+
+#include "aos/events/event_loop.h"
+#include "aos/events/shm_event_loop.h"
+
+namespace aos {
+
+class ShmEventLoopForRust {
+ public:
+ ShmEventLoopForRust(const Configuration *configuration)
+ : event_loop_(configuration) {}
+
+ const EventLoop *event_loop() const { return &event_loop_; }
+ EventLoop *event_loop_mut() { return &event_loop_; }
+
+ std::unique_ptr<ExitHandle> MakeExitHandle() {
+ return event_loop_.MakeExitHandle();
+ }
+
+ void Run() { event_loop_.Run(); }
+
+ private:
+ ShmEventLoop event_loop_;
+};
+
+} // namespace aos
+
+#endif // AOS_EVENTS_SHM_EVENT_LOOP_FOR_RUST_H_
diff --git a/aos/init.rs b/aos/init.rs
index 8a5f262..9ac62f1 100644
--- a/aos/init.rs
+++ b/aos/init.rs
@@ -16,6 +16,12 @@
///
/// Panics if non-test initialization has already been performed.
pub fn test_init() {
+ init();
+ // TODO(Brian): Do we want any of the other stuff that `:gtest_main` has?
+ // TODO(Brian): Call `aos::SetShmBase` like `:gtest_main` does.
+}
+
+pub fn init() {
static ONCE: Once = Once::new();
ONCE.call_once(|| {
let argv0 = std::env::args().next().expect("must have argv[0]");
@@ -23,7 +29,4 @@
// SAFETY: argv0 is a NUL-terminated string.
unsafe { ffi::aos::InitFromRust(argv0.as_ptr()) };
});
-
- // TODO(Brian): Do we want any of the other stuff that `:gtest_main` has?
- // TODO(Brian): Call `aos::SetShmBase` like `:gtest_main` does.
}
diff --git a/aos/network/message_bridge_client_lib.cc b/aos/network/message_bridge_client_lib.cc
index 8df81c6..e42eaa0 100644
--- a/aos/network/message_bridge_client_lib.cc
+++ b/aos/network/message_bridge_client_lib.cc
@@ -378,11 +378,15 @@
client_status_(event_loop_),
config_sha256_(std::move(config_sha256)),
refresh_key_timer_(event_loop->AddTimer([this]() { RequestAuthKey(); })),
- sctp_config_request_(event_loop_->MakeSender<SctpConfigRequest>("/aos")) {
+ sctp_config_request_(
+ event_loop_->TryMakeSender<SctpConfigRequest>("/aos")) {
std::string_view node_name = event_loop->node()->name()->string_view();
// Set up the SCTP configuration watcher and timer.
if (requested_authentication == SctpAuthMethod::kAuth && HasSctpAuth()) {
+ CHECK(sctp_config_request_.valid())
+ << ": Must have SctpConfig channel configured to use SCTP "
+ "authentication.";
event_loop->MakeWatcher("/aos", [this](const SctpConfig &config) {
if (config.has_key()) {
for (auto &conn : connections_) {
@@ -449,6 +453,7 @@
}
void MessageBridgeClient::RequestAuthKey() {
+ CHECK(sctp_config_request_.valid());
auto sender = sctp_config_request_.MakeBuilder();
auto builder = sender.MakeBuilder<SctpConfigRequest>();
builder.add_request_key(true);
diff --git a/aos/network/message_bridge_server_lib.cc b/aos/network/message_bridge_server_lib.cc
index 9ac062e..35c8afe 100644
--- a/aos/network/message_bridge_server_lib.cc
+++ b/aos/network/message_bridge_server_lib.cc
@@ -418,12 +418,16 @@
config_sha256_(std::move(config_sha256)),
allocator_(0),
refresh_key_timer_(event_loop->AddTimer([this]() { RequestAuthKey(); })),
- sctp_config_request_(event_loop_->MakeSender<SctpConfigRequest>("/aos")) {
+ sctp_config_request_(
+ event_loop_->TryMakeSender<SctpConfigRequest>("/aos")) {
CHECK_EQ(config_sha256_.size(), 64u) << ": Wrong length sha256sum";
CHECK(event_loop_->node() != nullptr) << ": No nodes configured.";
// Set up the SCTP configuration watcher and timer.
if (requested_authentication == SctpAuthMethod::kAuth && HasSctpAuth()) {
+ CHECK(sctp_config_request_.valid())
+ << ": Must have SctpConfig channel configured to use SCTP "
+ "authentication.";
event_loop_->MakeWatcher("/aos", [this](const SctpConfig &config) {
if (config.has_key()) {
server_.SetAuthKey(*config.key());
@@ -846,6 +850,7 @@
}
void MessageBridgeServer::RequestAuthKey() {
+ CHECK(sctp_config_request_.valid());
auto sender = sctp_config_request_.MakeBuilder();
auto builder = sender.MakeBuilder<SctpConfigRequest>();
builder.add_request_key(true);
diff --git a/aos/realtime.cc b/aos/realtime.cc
index 8b34ada..94dfa4e 100644
--- a/aos/realtime.cc
+++ b/aos/realtime.cc
@@ -331,7 +331,9 @@
if (FLAGS_die_on_malloc) {
// tcmalloc redefines __libc_malloc, so use this as a feature test.
if (&__libc_malloc == &tc_malloc) {
- RAW_LOG(INFO, "Hooking tcmalloc for die_on_malloc");
+ if (VLOG_IS_ON(1)) {
+ RAW_LOG(INFO, "Hooking tcmalloc for die_on_malloc");
+ }
if (&MallocHook_AddNewHook != nullptr) {
CHECK(MallocHook_AddNewHook(&NewHook));
} else {
diff --git a/frc971/BUILD b/frc971/BUILD
index d6a3af8..5613737 100644
--- a/frc971/BUILD
+++ b/frc971/BUILD
@@ -1,3 +1,5 @@
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
+
package(default_visibility = ["//visibility:public"])
cc_library(
@@ -21,3 +23,12 @@
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"],
)
+
+flatbuffer_cc_library(
+ name = "can_configuration_fbs",
+ srcs = [
+ ":can_configuration.fbs",
+ ],
+ gen_reflections = 1,
+ visibility = ["//visibility:public"],
+)
diff --git a/y2023/can_configuration.fbs b/frc971/can_configuration.fbs
similarity index 93%
rename from y2023/can_configuration.fbs
rename to frc971/can_configuration.fbs
index 75e2691..4ce70ab 100644
--- a/y2023/can_configuration.fbs
+++ b/frc971/can_configuration.fbs
@@ -1,4 +1,4 @@
-namespace y2023;
+namespace frc971;
// Message which triggers wpilib_interface to print out the current
// configuration, and optionally re-apply it.
diff --git a/frc971/wpilib/BUILD b/frc971/wpilib/BUILD
index a9d4ebf..33a3cd1 100644
--- a/frc971/wpilib/BUILD
+++ b/frc971/wpilib/BUILD
@@ -506,11 +506,12 @@
target_compatible_with = ["//tools/platforms/hardware:roborio"],
deps = [
"//aos:init",
+ "//aos:math",
"//aos/events:shm_event_loop",
"//aos/logging",
"//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
"//third_party:phoenix",
- "//third_party:phoenixpro",
+ "//third_party:phoenix6",
"//third_party:wpilib",
"@com_github_google_glog//:glog",
],
diff --git a/frc971/wpilib/can_sensor_reader.cc b/frc971/wpilib/can_sensor_reader.cc
index 5a19e8f..ad244fb 100644
--- a/frc971/wpilib/can_sensor_reader.cc
+++ b/frc971/wpilib/can_sensor_reader.cc
@@ -5,18 +5,19 @@
CANSensorReader::CANSensorReader(
aos::EventLoop *event_loop,
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_registry,
- std::vector<std::shared_ptr<Falcon>> falcons)
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry,
+ std::vector<std::shared_ptr<Falcon>> falcons,
+ std::function<void(ctre::phoenix::StatusCode status)> flatbuffer_callback)
: event_loop_(event_loop),
signals_(signals_registry.begin(), signals_registry.end()),
- can_position_sender_(
- event_loop->MakeSender<control_loops::drivetrain::CANPosition>(
- "/drivetrain")),
- falcons_(falcons) {
+ falcons_(falcons),
+ flatbuffer_callback_(flatbuffer_callback) {
event_loop->SetRuntimeRealtimePriority(40);
// TODO(max): Decide if we want to keep this on this core.
event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({1}));
+
+ CHECK(flatbuffer_callback_);
timer_handler_ = event_loop->AddTimer([this]() { Loop(); });
timer_handler_->set_name("CANSensorReader Loop");
@@ -28,37 +29,12 @@
void CANSensorReader::Loop() {
ctre::phoenix::StatusCode status =
- ctre::phoenixpro::BaseStatusSignalValue::WaitForAll(20_ms, signals_);
+ ctre::phoenix6::BaseStatusSignal::WaitForAll(20_ms, signals_);
if (!status.IsOK()) {
AOS_LOG(ERROR, "Failed to read signals from falcons: %s: %s",
status.GetName(), status.GetDescription());
}
- auto builder = can_position_sender_.MakeBuilder();
-
- for (auto falcon : falcons_) {
- falcon->RefreshNontimesyncedSignals();
- falcon->SerializePosition(builder.fbb());
- }
-
- auto falcon_offsets =
- builder.fbb()
- ->CreateVector<flatbuffers::Offset<control_loops::CANFalcon>>(
- falcons_.size(), [this](size_t index) {
- auto offset = falcons_.at(index)->TakeOffset();
- CHECK(offset.has_value());
- return offset.value();
- });
-
- control_loops::drivetrain::CANPosition::Builder can_position_builder =
- builder.MakeBuilder<control_loops::drivetrain::CANPosition>();
-
- can_position_builder.add_falcons(falcon_offsets);
- if (!falcons_.empty()) {
- can_position_builder.add_timestamp(falcons_.at(0)->GetTimestamp());
- }
- can_position_builder.add_status(static_cast<int>(status));
-
- builder.CheckOk(builder.Send(can_position_builder.Finish()));
+ flatbuffer_callback_(status);
}
diff --git a/frc971/wpilib/can_sensor_reader.h b/frc971/wpilib/can_sensor_reader.h
index 2e1a406..764a041 100644
--- a/frc971/wpilib/can_sensor_reader.h
+++ b/frc971/wpilib/can_sensor_reader.h
@@ -15,16 +15,17 @@
public:
CANSensorReader(
aos::EventLoop *event_loop,
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_registry,
- std::vector<std::shared_ptr<Falcon>> falcons);
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry,
+ std::vector<std::shared_ptr<Falcon>> falcons,
+ std::function<void(ctre::phoenix::StatusCode status)>
+ flatbuffer_callback);
private:
void Loop();
aos::EventLoop *event_loop_;
- const std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_;
- aos::Sender<control_loops::drivetrain::CANPosition> can_position_sender_;
+ const std::vector<ctre::phoenix6::BaseStatusSignal *> signals_;
// This is a vector of falcons becuase we don't need to care
// about falcons individually.
@@ -32,6 +33,9 @@
// Pointer to the timer handler used to modify the wakeup.
::aos::TimerHandler *timer_handler_;
+
+ // Callback used to send the CANPosition flatbuffer
+ std::function<void(ctre::phoenix::StatusCode status)> flatbuffer_callback_;
};
} // namespace wpilib
} // namespace frc971
diff --git a/frc971/wpilib/falcon.cc b/frc971/wpilib/falcon.cc
index 2dee390..6be83aa 100644
--- a/frc971/wpilib/falcon.cc
+++ b/frc971/wpilib/falcon.cc
@@ -1,9 +1,10 @@
#include "frc971/wpilib/falcon.h"
using frc971::wpilib::Falcon;
+using frc971::wpilib::kMaxBringupPower;
Falcon::Falcon(int device_id, std::string canbus,
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> *signals,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
double stator_current_limit, double supply_current_limit)
: talon_(device_id, canbus),
device_id_(device_id),
@@ -37,7 +38,7 @@
}
void Falcon::PrintConfigs() {
- ctre::phoenixpro::configs::TalonFXConfiguration configuration;
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
ctre::phoenix::StatusCode status =
talon_.GetConfigurator().Refresh(configuration);
if (!status.IsOK()) {
@@ -47,23 +48,22 @@
AOS_LOG(INFO, "configuration: %s", configuration.ToString().c_str());
}
-void Falcon::WriteConfigs(ctre::phoenixpro::signals::InvertedValue invert) {
+void Falcon::WriteConfigs(ctre::phoenix6::signals::InvertedValue invert) {
inverted_ = invert;
- ctre::phoenixpro::configs::CurrentLimitsConfigs current_limits;
+ ctre::phoenix6::configs::CurrentLimitsConfigs current_limits;
current_limits.StatorCurrentLimit = stator_current_limit_;
current_limits.StatorCurrentLimitEnable = true;
current_limits.SupplyCurrentLimit = supply_current_limit_;
current_limits.SupplyCurrentLimitEnable = true;
- ctre::phoenixpro::configs::MotorOutputConfigs output_configs;
- output_configs.NeutralMode =
- ctre::phoenixpro::signals::NeutralModeValue::Brake;
+ ctre::phoenix6::configs::MotorOutputConfigs output_configs;
+ output_configs.NeutralMode = ctre::phoenix6::signals::NeutralModeValue::Brake;
output_configs.DutyCycleNeutralDeadband = 0;
output_configs.Inverted = inverted_;
- ctre::phoenixpro::configs::TalonFXConfiguration configuration;
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
configuration.CurrentLimits = current_limits;
configuration.MotorOutput = output_configs;
@@ -77,6 +77,23 @@
PrintConfigs();
}
+ctre::phoenix::StatusCode Falcon::WriteCurrent(double current,
+ double max_voltage) {
+ ctre::phoenix6::controls::TorqueCurrentFOC control(
+ static_cast<units::current::ampere_t>(current));
+ // Using 0_Hz here makes it a one-shot update.
+ control.UpdateFreqHz = 0_Hz;
+ control.MaxAbsDutyCycle =
+ ::aos::Clip(max_voltage, -kMaxBringupPower, kMaxBringupPower) / 12.0;
+ ctre::phoenix::StatusCode status = talon()->SetControl(control);
+ if (!status.IsOK()) {
+ AOS_LOG(ERROR, "Failed to write control to falcon %d: %s: %s", device_id(),
+ status.GetName(), status.GetDescription());
+ }
+
+ return status;
+}
+
void Falcon::SerializePosition(flatbuffers::FlatBufferBuilder *fbb) {
control_loops::CANFalcon::Builder builder(*fbb);
builder.add_id(device_id_);
diff --git a/frc971/wpilib/falcon.h b/frc971/wpilib/falcon.h
index 7137d82..8f0f1f0 100644
--- a/frc971/wpilib/falcon.h
+++ b/frc971/wpilib/falcon.h
@@ -5,9 +5,10 @@
#include <cinttypes>
#include <vector>
-#include "ctre/phoenixpro/TalonFX.hpp"
+#include "ctre/phoenix6/TalonFX.hpp"
#include "glog/logging.h"
+#include "aos/commonmath.h"
#include "aos/init.h"
#include "aos/logging/logging.h"
#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
@@ -18,19 +19,21 @@
namespace wpilib {
static constexpr units::frequency::hertz_t kCANUpdateFreqHz = 200_Hz;
+static constexpr double kMaxBringupPower = 12.0;
// Gets info from and writes to falcon motors using the TalonFX controller.
class Falcon {
public:
Falcon(int device_id, std::string canbus,
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> *signals,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
double stator_current_limit, double supply_current_limit);
void PrintConfigs();
- void WriteConfigs(ctre::phoenixpro::signals::InvertedValue invert);
+ void WriteConfigs(ctre::phoenix6::signals::InvertedValue invert);
+ ctre::phoenix::StatusCode WriteCurrent(double current, double max_voltage);
- ctre::phoenixpro::hardware::TalonFX *talon() { return &talon_; }
+ ctre::phoenix6::hardware::TalonFX *talon() { return &talon_; }
void SerializePosition(flatbuffers::FlatBufferBuilder *fbb);
@@ -66,19 +69,17 @@
}
private:
- ctre::phoenixpro::hardware::TalonFX talon_;
+ ctre::phoenix6::hardware::TalonFX talon_;
int device_id_;
- ctre::phoenixpro::signals::InvertedValue inverted_;
+ ctre::phoenix6::signals::InvertedValue inverted_;
- ctre::phoenixpro::StatusSignalValue<units::temperature::celsius_t>
- device_temp_;
- ctre::phoenixpro::StatusSignalValue<units::voltage::volt_t> supply_voltage_;
- ctre::phoenixpro::StatusSignalValue<units::current::ampere_t> supply_current_,
+ ctre::phoenix6::StatusSignal<units::temperature::celsius_t> device_temp_;
+ ctre::phoenix6::StatusSignal<units::voltage::volt_t> supply_voltage_;
+ ctre::phoenix6::StatusSignal<units::current::ampere_t> supply_current_,
torque_current_;
- ctre::phoenixpro::StatusSignalValue<units::angle::turn_t> position_;
- ctre::phoenixpro::StatusSignalValue<units::dimensionless::scalar_t>
- duty_cycle_;
+ ctre::phoenix6::StatusSignal<units::angle::turn_t> position_;
+ ctre::phoenix6::StatusSignal<units::dimensionless::scalar_t> duty_cycle_;
double stator_current_limit_;
double supply_current_limit_;
diff --git a/frc971/wpilib/swerve/BUILD b/frc971/wpilib/swerve/BUILD
new file mode 100644
index 0000000..9f559f6
--- /dev/null
+++ b/frc971/wpilib/swerve/BUILD
@@ -0,0 +1,30 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "swerve_drivetrain_writer",
+ srcs = [
+ "swerve_drivetrain_writer.cc",
+ ],
+ hdrs = [
+ "swerve_drivetrain_writer.h",
+ ],
+ deps = [
+ ":swerve_module",
+ "//aos/logging",
+ "//frc971:can_configuration_fbs",
+ "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_output_fbs",
+ "//frc971/wpilib:falcon",
+ "//frc971/wpilib:loop_output_handler",
+ "//third_party:phoenix6",
+ ],
+)
+
+cc_library(
+ name = "swerve_module",
+ hdrs = [
+ "swerve_module.h",
+ ],
+ deps = [
+ "//frc971/wpilib:falcon",
+ ],
+)
diff --git a/frc971/wpilib/swerve/swerve_drivetrain_writer.cc b/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
new file mode 100644
index 0000000..2b6ef9e
--- /dev/null
+++ b/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
@@ -0,0 +1,60 @@
+#include "frc971/wpilib/swerve/swerve_drivetrain_writer.h"
+
+using frc971::wpilib::swerve::DrivetrainWriter;
+
+DrivetrainWriter::DrivetrainWriter(::aos::EventLoop *event_loop,
+ int drivetrain_writer_priority,
+ double max_voltage)
+ : ::frc971::wpilib::LoopOutputHandler<
+ ::frc971::control_loops::drivetrain::swerve::Output>(event_loop,
+ "/drivetrain"),
+ max_voltage_(max_voltage) {
+ event_loop->SetRuntimeRealtimePriority(drivetrain_writer_priority);
+
+ event_loop->OnRun([this]() { WriteConfigs(); });
+}
+
+void DrivetrainWriter::set_falcons(std::shared_ptr<SwerveModule> front_left,
+ std::shared_ptr<SwerveModule> front_right,
+ std::shared_ptr<SwerveModule> back_left,
+ std::shared_ptr<SwerveModule> back_right) {
+ front_left_ = std::move(front_left);
+ front_right_ = std::move(front_right);
+ back_left_ = std::move(back_left);
+ back_right_ = std::move(back_right);
+}
+
+void DrivetrainWriter::HandleCANConfiguration(
+ const CANConfiguration &configuration) {
+ for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
+ module->rotation->PrintConfigs();
+ module->translation->PrintConfigs();
+ }
+ if (configuration.reapply()) {
+ WriteConfigs();
+ }
+}
+
+void DrivetrainWriter::WriteConfigs() {
+ for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
+ module->rotation->WriteConfigs(false);
+ module->translation->WriteConfigs(false);
+ }
+}
+
+void DrivetrainWriter::Write(
+ const ::frc971::control_loops::drivetrain::swerve::Output &output) {
+ front_left_->WriteModule(output.front_left_output(), max_voltage_);
+ front_right_->WriteModule(output.front_right_output(), max_voltage_);
+ back_left_->WriteModule(output.back_left_output(), max_voltage_);
+ back_right_->WriteModule(output.back_right_output(), max_voltage_);
+}
+
+void DrivetrainWriter::Stop() {
+ AOS_LOG(WARNING, "drivetrain output too old\n");
+
+ for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
+ module->rotation->WriteCurrent(0, 0);
+ module->translation->WriteCurrent(0, 0);
+ }
+}
diff --git a/frc971/wpilib/swerve/swerve_drivetrain_writer.h b/frc971/wpilib/swerve/swerve_drivetrain_writer.h
new file mode 100644
index 0000000..4bd6639
--- /dev/null
+++ b/frc971/wpilib/swerve/swerve_drivetrain_writer.h
@@ -0,0 +1,52 @@
+#ifndef FRC971_WPILIB_SWERVE_DRIVETRAIN_WRITER_H_
+#define FRC971_WPILIB_SWERVE_DRIVETRAIN_WRITER_H_
+
+#include "ctre/phoenix6/TalonFX.hpp"
+
+#include "frc971/can_configuration_generated.h"
+#include "frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output_generated.h"
+#include "frc971/wpilib/falcon.h"
+#include "frc971/wpilib/loop_output_handler.h"
+#include "frc971/wpilib/swerve/swerve_module.h"
+
+namespace frc971 {
+namespace wpilib {
+namespace swerve {
+
+// Reads from the swerve output flatbuffer and uses wpilib to set the current
+// for each motor.
+class DrivetrainWriter
+ : public ::frc971::wpilib::LoopOutputHandler<
+ ::frc971::control_loops::drivetrain::swerve::Output> {
+ public:
+ DrivetrainWriter(::aos::EventLoop *event_loop, int drivetrain_writer_priority,
+ double max_voltage);
+
+ void set_falcons(std::shared_ptr<SwerveModule> front_left,
+ std::shared_ptr<SwerveModule> front_right,
+ std::shared_ptr<SwerveModule> back_left,
+ std::shared_ptr<SwerveModule> back_right);
+
+ void HandleCANConfiguration(const CANConfiguration &configuration);
+
+ private:
+ void WriteConfigs();
+
+ void Write(const ::frc971::control_loops::drivetrain::swerve::Output &output)
+ override;
+
+ void Stop() override;
+
+ double SafeSpeed(double voltage);
+
+ std::shared_ptr<SwerveModule> front_left_, front_right_, back_left_,
+ back_right_;
+
+ double max_voltage_;
+};
+
+} // namespace swerve
+} // namespace wpilib
+} // namespace frc971
+
+#endif // FRC971_WPILIB_SWERVE_DRIVETRAIN_WRITER_H_
diff --git a/frc971/wpilib/swerve/swerve_module.h b/frc971/wpilib/swerve/swerve_module.h
new file mode 100644
index 0000000..534f0ce
--- /dev/null
+++ b/frc971/wpilib/swerve/swerve_module.h
@@ -0,0 +1,44 @@
+#ifndef FRC971_WPILIB_SWERVE_SWERVE_MODULE_H_
+#define FRC971_WPILIB_SWERVE_SWERVE_MODULE_H_
+
+#include "frc971/wpilib/falcon.h"
+
+namespace frc971 {
+namespace wpilib {
+namespace swerve {
+
+struct SwerveModule {
+ SwerveModule(int rotation_id, int translation_id, std::string canbus,
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals,
+ double stator_current_limit, double supply_current_limit)
+ : rotation(std::make_shared<Falcon>(rotation_id, canbus, signals,
+ stator_current_limit,
+ supply_current_limit)),
+ translation(std::make_shared<Falcon>(translation_id, canbus, signals,
+ stator_current_limit,
+ supply_current_limit)) {}
+
+ void WriteModule(
+ const frc971::control_loops::drivetrain::swerve::SwerveModuleOutput
+ *module_output,
+ double max_voltage) {
+ double rotation_current = 0.0;
+ double translation_current = 0.0;
+
+ if (module_output != nullptr) {
+ rotation_current = module_output->rotation_current();
+ translation_current = module_output->translation_current();
+ }
+
+ rotation->WriteCurrent(rotation_current, max_voltage);
+ translation->WriteCurrent(translation_current, max_voltage);
+ }
+
+ std::shared_ptr<Falcon> rotation;
+ std::shared_ptr<Falcon> translation;
+};
+
+} // namespace swerve
+} // namespace wpilib
+} // namespace frc971
+#endif // FRC971_WPILIB_SWERVE_SWERVE_MODULE_H_
diff --git a/scouting/BUILD b/scouting/BUILD
index d6c09b2..b7e50fa 100644
--- a/scouting/BUILD
+++ b/scouting/BUILD
@@ -19,6 +19,11 @@
],
)
+# TODO(philipp): Sandbox the following:
+# - libnss3
+# - libdrm2
+# - libgbm1
+# - x11-xkb-utils (See TODO in scouting/scouting_test_runner.js)
cypress_test(
name = "scouting_test",
data = [
diff --git a/scouting/scouting_test_runner.js b/scouting/scouting_test_runner.js
index 3106ee7..c2ef027 100644
--- a/scouting/scouting_test_runner.js
+++ b/scouting/scouting_test_runner.js
@@ -4,9 +4,13 @@
const cypress = require('cypress');
// Set up the xvfb binary.
-process.env[
- 'PATH'
-] = `${process.env.RUNFILES_DIR}/xvfb_amd64/wrapped_bin:${process.env.PATH}`;
+// TODO(philipp): Figure out how to point Xvfb at the sandboxed usr/bin
+// directory. Currently impossible as it's hardcoded to use /usr/bin.
+process.env['PATH'] = [
+ `${process.env.RUNFILES_DIR}/xvfb_amd64/wrapped_bin`,
+ `${process.env.RUNFILES_DIR}/xvfb_amd64/usr/bin`,
+ process.env.PATH,
+].join(':');
// Start the web server, database, and fake TBA server.
// We use file descriptor 3 ('pipe') for the test server to let us know when
diff --git a/third_party/BUILD b/third_party/BUILD
index 53b5d24..7195123 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -31,17 +31,17 @@
target_compatible_with = ["//tools/platforms/hardware:roborio"],
visibility = ["//visibility:public"],
deps = [
+ "@ctre_phoenix6_tools_athena//:tools",
+ "@ctre_phoenix6_tools_headers//:tools",
"@ctre_phoenix_api_cpp_athena//:api-cpp",
"@ctre_phoenix_api_cpp_headers//:api-cpp",
"@ctre_phoenix_cci_athena//:cci",
"@ctre_phoenix_cci_headers//:cci",
- "@ctre_phoenixpro_tools_athena//:tools",
- "@ctre_phoenixpro_tools_headers//:tools",
],
)
cc_library(
- name = "phoenixpro",
+ name = "phoenix6",
linkopts = [
"-Wl,-rpath",
"-Wl,.",
@@ -49,10 +49,10 @@
target_compatible_with = ["//tools/platforms/hardware:roborio"],
visibility = ["//visibility:public"],
deps = [
- "@ctre_phoenixpro_api_cpp_athena//:api-cpp",
- "@ctre_phoenixpro_api_cpp_headers//:api-cpp",
- "@ctre_phoenixpro_tools_athena//:tools",
- "@ctre_phoenixpro_tools_headers//:tools",
+ "@ctre_phoenix6_api_cpp_athena//:api-cpp",
+ "@ctre_phoenix6_api_cpp_headers//:api-cpp",
+ "@ctre_phoenix6_tools_athena//:tools",
+ "@ctre_phoenix6_tools_headers//:tools",
],
)
diff --git a/third_party/autocxx/.github/ISSUE_TEMPLATE/bug_report.md b/third_party/autocxx/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..59bdb4d
--- /dev/null
+++ b/third_party/autocxx/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,22 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior with appropriate Rust and C++ code snippets. Ideally, please raise a new pull request with a failing test - instructions are [here](https://google.github.io/autocxx/contributing.html#reporting-bugs). If that isn't possible, a few other options are listed too.
+
+About half of the time people report bugs, they're not readily reproducible. That wastes time for everyone. That's why it's incredibly useful to have a test case which definitely fails. Thanks!
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/third_party/autocxx/.github/workflows/ci.yml b/third_party/autocxx/.github/workflows/ci.yml
index 367b729..563b8ff 100644
--- a/third_party/autocxx/.github/workflows/ci.yml
+++ b/third_party/autocxx/.github/workflows/ci.yml
@@ -32,9 +32,10 @@
- name: macOS
rust: nightly
os: macos
- - name: Windows (gnu)
- rust: nightly-x86_64-pc-windows-gnu
- os: windows
+ # Windows GNU disabled due to https://github.com/google/autocxx/issues/1134
+ # - name: Windows (gnu)
+ # rust: nightly-x86_64-pc-windows-gnu
+ # os: windows
- name: Windows (msvc)
rust: nightly-x86_64-pc-windows-msvc
os: windows
@@ -141,9 +142,16 @@
run: cargo build
- name: Build reference-wrappers example
working-directory: ./examples/reference-wrappers
+ if: matrix.rust == 'nightly'
run: cargo build
- # We do not build the LLVM example because even 'apt-get install llvm-13-dev'
- # does not work to install the LLVM 13 headers.
+ - name: Build cpp_calling_rust example
+ working-directory: ./examples/cpp_calling_rust
+ run: cargo build
+ - name: Build llvm example
+ working-directory: ./examples/llvm
+ # llvm example needs to install LLVM 13 headers via apt-get.
+ if: matrix.os == ''
+ run: sudo apt-get install llvm-13-dev && cargo build
sanitizer:
name: Address Sanitizer
@@ -169,6 +177,17 @@
RUST_BACKTRACE: "0"
run: cargo -Z build-std test --workspace --target x86_64-unknown-linux-gnu
+ force-wrapper-generation:
+ name: Test forcing wrapper generation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: Swatinem/rust-cache@v1
+ - name: Tests generating all possible shims
+ env:
+ AUTOCXX_FORCE_WRAPPER_GENERATION: 1
+ run: cargo test --workspace
+
# Clippy check
clippy:
name: Clippy
diff --git a/third_party/autocxx/Cargo.lock b/third_party/autocxx/Cargo.lock
index 4f58182..a7872e3 100644
--- a/third_party/autocxx/Cargo.lock
+++ b/third_party/autocxx/Cargo.lock
@@ -4,9 +4,9 @@
[[package]]
name = "addr2line"
-version = "0.17.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
dependencies = [
"gimli",
]
@@ -18,48 +18,115 @@
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
-name = "aho-corasick"
-version = "0.7.18"
+name = "ahash"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
dependencies = [
"memchr",
]
[[package]]
-name = "ansi_term"
-version = "0.12.1"
+name = "android-tzdata"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
- "winapi",
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is-terminal",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
+dependencies = [
+ "anstyle",
+ "windows-sys",
]
[[package]]
name = "anyhow"
-version = "1.0.56"
+version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
name = "aquamarine"
-version = "0.1.11"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96e14cb2a51c8b45d26a4219981985c7350fc05eacb7b5b2939bceb2ffefdf3e"
+checksum = "a941c39708478e8eea39243b5983f1c42d2717b3620ee91f4a52115fd02ac43f"
dependencies = [
"itertools 0.9.0",
"proc-macro-error",
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
name = "assert_cmd"
-version = "1.0.8"
+version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe"
+checksum = "86d6b683edf8d1119fe420a94f8a7e389239666aa72e65495d91c00462510151"
dependencies = [
+ "anstyle",
"bstr",
"doc-comment",
"predicates",
@@ -74,7 +141,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
"libc",
"winapi",
]
@@ -87,7 +154,7 @@
[[package]]
name = "autocxx"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"aquamarine",
"autocxx-macro",
@@ -97,41 +164,41 @@
[[package]]
name = "autocxx-bindgen"
-version = "0.59.17"
+version = "0.65.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a9a26dd38d385d23b1bf61bd231b77f690c4368aef4c77cee1b7a6da2e2042"
+checksum = "6c9fb7b8dd83a582e12157367773d8d1195f2dea54d4250aaf3426abae3237aa"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"cexpr",
"clang-sys",
- "clap 2.34.0",
- "env_logger 0.9.0",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
+ "prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
+ "syn 2.0.23",
"which",
]
[[package]]
name = "autocxx-build"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"autocxx-engine",
- "env_logger 0.9.0",
+ "env_logger 0.9.3",
"indexmap",
- "syn",
+ "syn 2.0.23",
]
[[package]]
name = "autocxx-demo"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"autocxx",
"autocxx-build",
@@ -141,7 +208,7 @@
[[package]]
name = "autocxx-engine"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"aquamarine",
"autocxx-bindgen",
@@ -150,16 +217,17 @@
"cxx-gen",
"indexmap",
"indoc",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"log",
"miette",
"once_cell",
+ "prettyplease",
"proc-macro2",
"quote",
"regex",
+ "rustversion",
"serde_json",
- "strum_macros",
- "syn",
+ "syn 2.0.23",
"tempfile",
"thiserror",
"version_check",
@@ -167,17 +235,17 @@
[[package]]
name = "autocxx-gen"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"assert_cmd",
"autocxx",
"autocxx-engine",
"autocxx-integration-tests",
- "clap 3.1.9",
+ "clap 3.2.25",
"cxx",
- "env_logger 0.9.0",
+ "env_logger 0.9.3",
"indexmap",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"miette",
"pathdiff",
"proc-macro2",
@@ -186,22 +254,25 @@
[[package]]
name = "autocxx-integration-tests"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"autocxx",
"autocxx-engine",
"cc",
"cxx",
- "env_logger 0.9.0",
+ "env_logger 0.9.3",
"indoc",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"link-cplusplus",
"log",
+ "moveit",
"once_cell",
"proc-macro2",
"quote",
"rust_info",
- "syn",
+ "rustversion",
+ "static_assertions",
+ "syn 1.0.109",
"tempfile",
"test-log",
"trybuild",
@@ -209,76 +280,76 @@
[[package]]
name = "autocxx-macro"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"autocxx-parser",
"proc-macro-error",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.23",
]
[[package]]
name = "autocxx-mdbook-preprocessor"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"anyhow",
"autocxx-integration-tests",
- "clap 3.1.9",
- "env_logger 0.9.0",
+ "clap 3.2.25",
+ "env_logger 0.9.3",
"gag",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"mdbook",
"proc-macro2",
"rayon",
"regex",
"serde_json",
- "syn",
+ "syn 1.0.109",
]
[[package]]
name = "autocxx-parser"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"indexmap",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"log",
"once_cell",
"proc-macro2",
"quote",
"serde",
"serde_json",
- "syn",
+ "syn 2.0.23",
"thiserror",
]
[[package]]
name = "autocxx-reduce"
-version = "0.22.3"
+version = "0.26.0"
dependencies = [
"assert_cmd",
"autocxx-engine",
"autocxx-parser",
- "clap 3.1.9",
+ "clap 3.2.25",
"cxx-gen",
"indexmap",
"indoc",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_derive",
"serde_json",
- "syn",
+ "syn 2.0.23",
"tempfile",
]
[[package]]
name = "backtrace"
-version = "0.3.64"
+version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
+checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
dependencies = [
"addr2line",
"cc",
@@ -290,60 +361,67 @@
]
[[package]]
+name = "backtrace-ext"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
+dependencies = [
+ "backtrace",
+]
+
+[[package]]
+name = "basic-toml"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f838d03a705d72b12389b8930bd14cacf493be1380bfb15720d4d12db5ab03ac"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
-name = "block-buffer"
-version = "0.7.3"
+name = "bitflags"
+version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
+checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
- "block-padding",
- "byte-tools",
- "byteorder",
"generic-array",
]
[[package]]
-name = "block-padding"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
-dependencies = [
- "byte-tools",
-]
-
-[[package]]
name = "bstr"
-version = "0.2.17"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5"
dependencies = [
- "lazy_static",
"memchr",
- "regex-automata",
+ "once_cell",
+ "regex-automata 0.1.10",
+ "serde",
]
[[package]]
-name = "byte-tools"
-version = "0.3.1"
+name = "bumpalo"
+version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
-
-[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "cc"
-version = "1.0.73"
+version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cexpr"
@@ -362,22 +440,21 @@
[[package]]
name = "chrono"
-version = "0.4.19"
+version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
dependencies = [
- "libc",
- "num-integer",
+ "android-tzdata",
+ "iana-time-zone",
"num-traits",
- "time",
"winapi",
]
[[package]]
name = "clang-sys"
-version = "1.3.1"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21"
+checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
dependencies = [
"glob",
"libc",
@@ -386,54 +463,68 @@
[[package]]
name = "clap"
-version = "2.34.0"
+version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
- "ansi_term",
"atty",
- "bitflags",
- "strsim 0.8.0",
- "textwrap 0.11.0",
- "unicode-width",
- "vec_map",
+ "bitflags 1.3.2",
+ "clap_lex 0.2.4",
+ "indexmap",
+ "once_cell",
+ "strsim",
+ "termcolor",
+ "textwrap 0.16.0",
]
[[package]]
name = "clap"
-version = "3.1.9"
+version = "4.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aad2534fad53df1cc12519c5cda696dd3e20e6118a027e24054aea14a0bdcbe"
+checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a"
dependencies = [
- "atty",
- "bitflags",
- "clap_lex",
- "indexmap",
- "lazy_static",
- "strsim 0.10.0",
- "termcolor",
- "textwrap 0.15.0",
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex 0.5.0",
+ "once_cell",
+ "strsim",
+ "terminal_size 0.2.6",
]
[[package]]
name = "clap_complete"
-version = "3.1.1"
+version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
+checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b"
dependencies = [
- "clap 3.1.9",
+ "clap 4.3.10",
]
[[package]]
name = "clap_lex"
-version = "0.1.1"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "189ddd3b5d32a70b35e7686054371742a937b0d99128e76dde6340210e966669"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
+name = "clap_lex"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
+
+[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -444,10 +535,31 @@
]
[[package]]
-name = "crossbeam-channel"
-version = "0.5.4"
+name = "colorchoice"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -455,9 +567,9 @@
[[package]]
name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@@ -466,33 +578,41 @@
[[package]]
name = "crossbeam-epoch"
-version = "0.9.8"
+version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
- "lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
- "lazy_static",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
]
[[package]]
name = "cxx"
-version = "1.0.68"
+version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e599641dff337570f6aa9c304ecca92341d30bf72e1c50287869ed6a36615a6"
+checksum = "e88abab2f5abbe4c56e8f1fb431b784d710b709888f35755a160e62e33fe38e8"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -502,31 +622,31 @@
[[package]]
name = "cxx-gen"
-version = "0.7.68"
+version = "0.7.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e2c726d93799c3129c65224ab09eae1a31276bc593d4f7344be1c592c16a1ec"
+checksum = "83f6f8cddb97c1510ef1e7e849a40d60cd97377766187633ac6b9162dd862fd8"
dependencies = [
"codespan-reporting",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.23",
]
[[package]]
name = "cxxbridge-flags"
-version = "1.0.68"
+version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3894ad0c6d517cb5a4ce8ec20b37cd0ea31b480fe582a104c5db67ae21270853"
+checksum = "8d3816ed957c008ccd4728485511e3d9aaf7db419aa321e3d2c5a2f3411e36c8"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.68"
+version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34fa7e395dc1c001083c7eed28c8f0f0b5a225610f3b6284675f444af6fab86b"
+checksum = "a26acccf6f445af85ea056362561a24ef56cdc15fcc685f03aec50b9c702cb6d"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.23",
]
[[package]]
@@ -537,11 +657,12 @@
[[package]]
name = "digest"
-version = "0.8.1"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
- "generic-array",
+ "block-buffer",
+ "crypto-common",
]
[[package]]
@@ -552,18 +673,18 @@
[[package]]
name = "either"
-version = "1.6.1"
+version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "env_logger"
-version = "0.7.1"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
- "humantime 1.3.0",
+ "humantime",
"log",
"regex",
"termcolor",
@@ -571,28 +692,43 @@
[[package]]
name = "env_logger"
-version = "0.9.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
- "atty",
- "humantime 2.1.0",
+ "humantime",
+ "is-terminal",
"log",
"regex",
"termcolor",
]
[[package]]
-name = "fake-simd"
+name = "errno"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
[[package]]
name = "fastrand"
-version = "1.7.0"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
dependencies = [
"instant",
]
@@ -620,50 +756,59 @@
[[package]]
name = "generic-array"
-version = "0.12.4"
+version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
]
[[package]]
name = "gimli"
-version = "0.26.1"
+version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "glob"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "handlebars"
-version = "4.2.2"
+version = "4.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b"
+checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d"
dependencies = [
"log",
"pest",
"pest_derive",
- "quick-error 2.0.1",
"serde",
"serde_json",
+ "thiserror",
]
[[package]]
name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-
-[[package]]
-name = "heck"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash",
+]
[[package]]
name = "hermit-abi"
@@ -675,13 +820,10 @@
]
[[package]]
-name = "humantime"
-version = "1.3.0"
+name = "hermit-abi"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
-dependencies = [
- "quick-error 1.2.3",
-]
+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "humantime"
@@ -690,10 +832,33 @@
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
-name = "indexmap"
-version = "1.8.1"
+name = "iana-time-zone"
+version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
+checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown",
@@ -702,12 +867,9 @@
[[package]]
name = "indoc"
-version = "1.0.4"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e"
-dependencies = [
- "unindent",
-]
+checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
[[package]]
name = "instant"
@@ -719,6 +881,28 @@
]
[[package]]
+name = "io-lifetimes"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
+dependencies = [
+ "hermit-abi 0.3.2",
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
+dependencies = [
+ "hermit-abi 0.3.2",
+ "rustix 0.38.3",
+ "windows-sys",
+]
+
+[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -735,18 +919,27 @@
[[package]]
name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
-version = "1.0.1"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
+checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
+
+[[package]]
+name = "js-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+dependencies = [
+ "wasm-bindgen",
+]
[[package]]
name = "lazy_static"
@@ -762,15 +955,15 @@
[[package]]
name = "libc"
-version = "0.2.123"
+version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
@@ -778,48 +971,50 @@
[[package]]
name = "link-cplusplus"
-version = "1.0.6"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8cae2cd7ba2f3f63938b9c724475dfb7b9861b545a90324476324ed21dbc8c8"
+checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9"
dependencies = [
"cc",
]
[[package]]
-name = "log"
-version = "0.4.16"
+name = "linux-raw-sys"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
-dependencies = [
- "cfg-if",
-]
+checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
-name = "maplit"
-version = "1.0.2"
+name = "linux-raw-sys"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
+checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
+
+[[package]]
+name = "log"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
[[package]]
name = "mdbook"
-version = "0.4.18"
+version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74612ae81a3e5ee509854049dfa4c7975ae033c06f5fc4735c7dfbe60ee2a39d"
+checksum = "7b67ee4a744f36e6280792016c17e69921b51df357181d1eb17d620fcc3609f3"
dependencies = [
"anyhow",
"chrono",
- "clap 3.1.9",
+ "clap 4.3.10",
"clap_complete",
- "env_logger 0.7.1",
+ "env_logger 0.10.0",
"handlebars",
- "lazy_static",
"log",
"memchr",
+ "once_cell",
"opener",
"pulldown-cmark",
"regex",
"serde",
- "serde_derive",
"serde_json",
"shlex",
"tempfile",
@@ -829,48 +1024,49 @@
[[package]]
name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
-version = "0.6.5"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "miette"
-version = "4.4.0"
+version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a097de91d72c13382f60213ed9f7f7a26afd8bee0ea320b47f886a9a67ca5a1"
+checksum = "a236ff270093b0b67451bc50a509bd1bad302cb1d3c7d37d5efe931238581fa9"
dependencies = [
- "atty",
"backtrace",
+ "backtrace-ext",
+ "is-terminal",
"miette-derive",
"once_cell",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
- "terminal_size",
- "textwrap 0.15.0",
+ "terminal_size 0.1.17",
+ "textwrap 0.15.2",
"thiserror",
"unicode-width",
]
[[package]]
name = "miette-derive"
-version = "4.4.0"
+version = "5.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45a95a48d0bc28f9af628286e8a4da09f96f34a97744a2e9a5a4db9814ad527d"
+checksum = "4901771e1d44ddb37964565c654a3223ba41a594d02b8da471cc4464912b5cfa"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.23",
]
[[package]]
@@ -881,88 +1077,71 @@
[[package]]
name = "miniz_oxide"
-version = "0.4.4"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
- "autocfg",
]
[[package]]
name = "moveit"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "815d5988a1dd22f08bad572a83ee654563bb422ece5d5bce41f31ec49399dcb5"
+checksum = "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba"
dependencies = [
"cxx",
]
[[package]]
name = "nom"
-version = "7.1.1"
+version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
-name = "num-integer"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
-dependencies = [
- "autocfg",
- "num-traits",
-]
-
-[[package]]
name = "num-traits"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
-version = "1.13.1"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.3.2",
"libc",
]
[[package]]
name = "object"
-version = "0.27.1"
+version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
-version = "1.10.0"
+version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
-
-[[package]]
-name = "opaque-debug"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "opener"
-version = "0.5.0"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952"
+checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005"
dependencies = [
"bstr",
"winapi",
@@ -970,15 +1149,15 @@
[[package]]
name = "os_str_bytes"
-version = "6.0.0"
+version = "6.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
[[package]]
name = "owo-colors"
-version = "3.3.0"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e72e30578e0d0993c8ae20823dd9cff2bc5517d2f586a8aef462a581e8a03eb"
+checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "pathdiff"
@@ -994,18 +1173,19 @@
[[package]]
name = "pest"
-version = "2.1.3"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
+checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9"
dependencies = [
+ "thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
-version = "2.1.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
+checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b"
dependencies = [
"pest",
"pest_generator",
@@ -1013,56 +1193,67 @@
[[package]]
name = "pest_generator"
-version = "2.1.3"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
+checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.23",
]
[[package]]
name = "pest_meta"
-version = "2.1.3"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
+checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0"
dependencies = [
- "maplit",
+ "once_cell",
"pest",
- "sha-1",
+ "sha2",
]
[[package]]
name = "predicates"
-version = "2.1.1"
+version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
+checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9"
dependencies = [
+ "anstyle",
"difflib",
- "itertools 0.10.3",
+ "itertools 0.10.5",
"predicates-core",
]
[[package]]
name = "predicates-core"
-version = "1.0.3"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
+checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
[[package]]
name = "predicates-tree"
-version = "1.0.5"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
+checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
dependencies = [
"predicates-core",
"termtree",
]
[[package]]
+name = "prettyplease"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92139198957b410250d43fad93e630d956499a625c527eda65175c8680f83387"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.23",
+]
+
+[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1071,7 +1262,7 @@
"proc-macro-error-attr",
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
"version_check",
]
@@ -1088,62 +1279,48 @@
[[package]]
name = "proc-macro2"
-version = "1.0.37"
+version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "pulldown-cmark"
-version = "0.9.1"
+version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
+checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
"memchr",
"unicase",
]
[[package]]
-name = "quick-error"
-version = "1.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
-
-[[package]]
-name = "quick-error"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
-
-[[package]]
name = "quote"
-version = "1.0.18"
+version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
+checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
-version = "1.5.2"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221"
+checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
- "autocfg",
- "crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
-version = "1.9.2"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4"
+checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
@@ -1153,21 +1330,22 @@
[[package]]
name = "redox_syscall"
-version = "0.2.13"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
- "bitflags",
+ "bitflags 1.3.2",
]
[[package]]
name = "regex"
-version = "1.5.5"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484"
dependencies = [
"aho-corasick",
"memchr",
+ "regex-automata 0.3.0",
"regex-syntax",
]
@@ -1178,19 +1356,21 @@
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
-name = "regex-syntax"
-version = "0.6.25"
+name = "regex-automata"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
+name = "regex-syntax"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
+checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846"
[[package]]
name = "rust_info"
@@ -1200,9 +1380,9 @@
[[package]]
name = "rustc-demangle"
-version = "0.1.21"
+version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
@@ -1211,16 +1391,43 @@
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
-name = "rustversion"
-version = "1.0.6"
+name = "rustix"
+version = "0.37.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06"
+dependencies = [
+ "bitflags 1.3.2",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys 0.3.8",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4"
+dependencies = [
+ "bitflags 2.3.3",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.3",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f"
[[package]]
name = "ryu"
-version = "1.0.9"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
+checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
[[package]]
name = "scopeguard"
@@ -1230,29 +1437,29 @@
[[package]]
name = "serde"
-version = "1.0.136"
+version = "1.0.166"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
+checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.136"
+version = "1.0.166"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
+checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.23",
]
[[package]]
name = "serde_json"
-version = "1.0.79"
+version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
+checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
dependencies = [
"itoa",
"ryu",
@@ -1260,15 +1467,14 @@
]
[[package]]
-name = "sha-1"
-version = "0.8.2"
+name = "sha2"
+version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
+checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
dependencies = [
- "block-buffer",
+ "cfg-if",
+ "cpufeatures",
"digest",
- "fake-simd",
- "opaque-debug",
]
[[package]]
@@ -1284,10 +1490,10 @@
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
[[package]]
-name = "strsim"
-version = "0.8.0"
+name = "static_assertions"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
@@ -1296,76 +1502,74 @@
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
-name = "strum_macros"
-version = "0.24.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "rustversion",
- "syn",
-]
-
-[[package]]
name = "supports-color"
-version = "1.3.0"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4872ced36b91d47bae8a214a683fe54e7078875b399dfa251df346c9b547d1f9"
+checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354"
dependencies = [
- "atty",
+ "is-terminal",
"is_ci",
]
[[package]]
name = "supports-hyperlinks"
-version = "1.2.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406"
+checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
dependencies = [
- "atty",
+ "is-terminal",
]
[[package]]
name = "supports-unicode"
-version = "1.0.2"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8b945e45b417b125a8ec51f1b7df2f8df7920367700d1f98aedd21e5735f8b2"
+checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7"
dependencies = [
- "atty",
+ "is-terminal",
]
[[package]]
name = "syn"
-version = "1.0.91"
+version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
- "unicode-xid",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
]
[[package]]
name = "tempfile"
-version = "3.3.0"
+version = "3.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
dependencies = [
+ "autocfg",
"cfg-if",
"fastrand",
- "libc",
"redox_syscall",
- "remove_dir_all",
- "winapi",
+ "rustix 0.37.23",
+ "windows-sys",
]
[[package]]
name = "termcolor"
-version = "1.1.3"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
@@ -1381,36 +1585,37 @@
]
[[package]]
-name = "termtree"
-version = "0.2.4"
+name = "terminal_size"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
+checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
+dependencies = [
+ "rustix 0.37.23",
+ "windows-sys",
+]
+
+[[package]]
+name = "termtree"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[[package]]
name = "test-log"
-version = "0.2.10"
+version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4235dbf7ea878b3ef12dea20a59c134b405a66aafc4fc2c7b9935916e289e735"
+checksum = "d9601d162c1d77e62c1ea0bc8116cd1caf143ce3af947536c3c9052a1677fe0c"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
name = "textwrap"
-version = "0.11.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
-[[package]]
-name = "textwrap"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
+checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
dependencies = [
"smawk",
"unicode-linebreak",
@@ -1418,77 +1623,72 @@
]
[[package]]
-name = "thiserror"
-version = "1.0.30"
+name = "textwrap"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+
+[[package]]
+name = "thiserror"
+version = "1.0.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.30"
+version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59"
dependencies = [
"proc-macro2",
"quote",
- "syn",
-]
-
-[[package]]
-name = "time"
-version = "0.1.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
-dependencies = [
- "libc",
- "wasi",
- "winapi",
+ "syn 2.0.23",
]
[[package]]
name = "toml"
-version = "0.5.9"
+version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "topological-sort"
-version = "0.1.0"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa7c7f42dea4b1b99439786f5633aeb9c14c1b53f75e282803c2ec2ad545873c"
+checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
[[package]]
name = "trybuild"
-version = "1.0.59"
+version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "606ab3fe0065741fdbb51f64bcb6ba76f13fad49f1723030041826c631782764"
+checksum = "04366e99ff743345622cd00af2af01d711dc2d1ef59250d7347698d21b546729"
dependencies = [
+ "basic-toml",
"glob",
"once_cell",
"serde",
"serde_derive",
"serde_json",
"termcolor",
- "toml",
]
[[package]]
name = "typenum"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unicase"
@@ -1500,37 +1700,32 @@
]
[[package]]
-name = "unicode-linebreak"
-version = "0.1.2"
+name = "unicode-ident"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
+checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
+
+[[package]]
+name = "unicode-linebreak"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137"
dependencies = [
+ "hashbrown",
"regex",
]
[[package]]
name = "unicode-width"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
-name = "unicode-xid"
-version = "0.2.2"
+name = "utf8parse"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
-[[package]]
-name = "unindent"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
-
-[[package]]
-name = "vec_map"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
@@ -1549,19 +1744,73 @@
[[package]]
name = "wasi"
-version = "0.10.0+wasi-snapshot-preview1"
+version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.23",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.23",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "which"
-version = "4.2.5"
+version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
+checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
dependencies = [
"either",
- "lazy_static",
"libc",
+ "once_cell",
]
[[package]]
@@ -1594,3 +1843,78 @@
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/third_party/autocxx/Cargo.toml b/third_party/autocxx/Cargo.toml
index a741ece..7a30fc7 100644
--- a/third_party/autocxx/Cargo.toml
+++ b/third_party/autocxx/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
license = "MIT OR Apache-2.0"
description = "Safe autogenerated interop between Rust and C++"
@@ -25,10 +25,14 @@
resolver = "2"
[dependencies]
-autocxx-macro = { path="macro", version="0.22.3" }
-cxx = "1.0.68" # ... also needed because expansion of type_id refers to ::cxx
+autocxx-macro = { path="macro", version="0.26.0" }
+cxx = "1.0.78" # ... also needed because expansion of type_id refers to ::cxx
aquamarine = "0.1" # docs
-moveit = { version = "0.5", features = [ "cxx" ] }
+moveit = { version = "0.6", features = [ "cxx" ] }
+
+#[workspace]
+#members = ["parser", "engine", "gen/cmd", "gen/build", "macro", "demo", "tools/reduce", "tools/mdbook-preprocessor", "integration-tests"]
+#exclude = ["examples/s2", "examples/steam-mini", "examples/subclass", "examples/chromium-fake-render-frame-host", "examples/pod", "examples/non-trivial-type-on-stack", "examples/llvm", "examples/reference-wrappers", "examples/cpp_calling_rust", "tools/stress-test"]
#[patch.crates-io]
#cxx = { path="../cxx" }
diff --git a/third_party/autocxx/book/src/building.md b/third_party/autocxx/book/src/building.md
index 4d5d919..d4abd09 100644
--- a/third_party/autocxx/book/src/building.md
+++ b/third_party/autocxx/book/src/building.md
@@ -12,7 +12,7 @@
let mut b = autocxx_build::Builder::new("src/main.rs", &[&path])
.extra_clang_args(&["-std=c++17"])
.expect_build();
- b.flag_if_supported("-std=c++17")
+ b.flag_if_supported("-std=c++17") // use "-std:c++17" here if using msvc on windows
.compile("autocxx-demo"); // arbitrary library name, pick anything
println!("cargo:rerun-if-changed=src/main.rs");
// Add instructions to link to any C++ libraries you need.
@@ -58,3 +58,14 @@
```
This interop inevitably involves lots of fiddly small functions. It's likely to perform far better if you can achieve cross-language link-time-optimization (LTO). [This issue](https://github.com/dtolnay/cxx/issues/371) may give some useful hints - see also all the build-related help in [the cxx manual](https://cxx.rs/) which all applies here too.
+
+## C++ versions and other compiler command-line flags
+
+The code generated by cxx and autocxx requires C++ 14, so it's not possible to use an earlier version of C++ than that.
+
+To use a later version, you need to:
+
+* Build the generated code with a later C++ version, for example using the clang argument `-std=c++17`. If you're using autocxx's cargo support, then you would do this by calling methods on the returned `cc::Build` object, for instance [`flag_if_supported`](https://docs.rs/cc/latest/cc/struct.Build.html#method.flag_if_supported).
+* _Also_ give similar directives to the C++ parsing which happens _within_ autocxx (specifically, by autocxx's version of bindgen). To do that, use [`Builder::extra_clang_args`](https://docs.rs/autocxx-engine/latest/autocxx_engine/struct.Builder.html#method.extra_clang_args).
+
+The same applies with the command-line `autocxx_gen` support - you'll need to pass such extra compiler options to `autocxx_gen` and also use them when building the generated C++ code.
diff --git a/third_party/autocxx/book/src/contributing.md b/third_party/autocxx/book/src/contributing.md
index e95ca5a..d82e64e 100644
--- a/third_party/autocxx/book/src/contributing.md
+++ b/third_party/autocxx/book/src/contributing.md
@@ -71,7 +71,11 @@
This is especially valuable to see the `bindgen` output Rust code, and then the converted Rust code which we pass into cxx. Usually, most problems are due to some mis-conversion somewhere
in `engine/src/conversion`. See [here](https://docs.rs/autocxx-engine/latest/autocxx_engine/struct.IncludeCppEngine.html) for documentation and diagrams on how the engine works.
-You may also wish to set `AUTOCXX_ASAN=1` on Linux when running tests.
+You may also wish to set `AUTOCXX_ASAN=1` on Linux when running tests. To exercise all
+the code paths related to generating both C++ and Rust side shims, you can set
+`AUTOCXX_FORCE_WRAPPER_GENERATION=1`. The test suite doesn't do this by default because
+we also want to test the normal code paths. (In the future we might want to
+parameterize the test suite to do both.)
## Reporting bugs
@@ -99,6 +103,17 @@
the C++ bindings as distilled by `bindgen`, and then the version which
we've converted and moulded to be suitable for use by `cxx`.
+## Bugs related to linking problems
+
+Unfortunately, _linking_ C++ binaries is a complex area subject in itself, and
+we won't be able to debug your linking issues by means of an autocxx bug report.
+Assuming you're using autocxx's build.rs support, the actual C++ build and
+managed by the [`cc`](https://crates.io/crates/cc) crate. You can find
+many of its options on its [`Build` type](https://docs.rs/cc/latest/cc/struct.Build.html).
+If you need to bring in an external library, you may also need to emit certain
+[print statements from your `build.rs`](https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib)
+to instruct cargo to link against that library.
+
## How to contribute to this manual
More examples in this manual are _very_ welcome!
diff --git a/third_party/autocxx/book/src/examples.md b/third_party/autocxx/book/src/examples.md
index d0246f5..e7f2afe 100644
--- a/third_party/autocxx/book/src/examples.md
+++ b/third_party/autocxx/book/src/examples.md
@@ -4,7 +4,7 @@
* [S2 example](https://github.com/google/autocxx/tree/main/examples/s2) - example using S2 geometry library
* [Steam example](https://github.com/google/autocxx/tree/main/examples/steam-mini) - example using (something like) the Steam client library
* [Subclass example](https://github.com/google/autocxx/tree/main/examples/subclass) - example using subclasses
-* [Integration tests](https://github.com/google/autocxx/blob/main/integration-tests/src/tests.rs)
+* [Integration tests](https://github.com/google/autocxx/blob/main/integration-tests/tests/integration_test.rs)
- hundreds of small snippets
Contributions of more examples to the `examples` directory are much appreciated!
diff --git a/third_party/autocxx/book/src/rust_calls.md b/third_party/autocxx/book/src/rust_calls.md
index ebd37c5..369c304 100644
--- a/third_party/autocxx/book/src/rust_calls.md
+++ b/third_party/autocxx/book/src/rust_calls.md
@@ -36,8 +36,7 @@
}
}
",
-"#include <memory>
-class GoatObserver {
+"class GoatObserver {
public:
virtual void goat_full() const = 0;
virtual ~GoatObserver() {}
@@ -62,7 +61,7 @@
use ffi::*;
-#[is_subclass(superclass("GoatObserver"))]
+#[subclass]
#[derive(Default)]
pub struct MyGoatObserver;
@@ -124,8 +123,6 @@
virtual ~Dinosaur() {}
};
-// Currently, autocxx requires at least one 'generate!' call.
-inline void do_a_thing() {};
",
{
use autocxx::prelude::*;
@@ -136,16 +133,15 @@
safety!(unsafe_ffi)
subclass!("Dinosaur", TRex)
subclass!("Dinosaur", Diplodocus)
- generate!("do_a_thing")
}
use ffi::*;
-#[is_subclass(superclass("Dinosaur"))]
+#[subclass]
#[derive(Default)]
pub struct TRex;
-#[is_subclass(superclass("Dinosaur"))]
+#[subclass]
#[derive(Default)]
pub struct Diplodocus;
diff --git a/third_party/autocxx/book/src/tutorial.md b/third_party/autocxx/book/src/tutorial.md
index 3e8e5b2..5582cd9 100644
--- a/third_party/autocxx/book/src/tutorial.md
+++ b/third_party/autocxx/book/src/tutorial.md
@@ -21,12 +21,12 @@
```toml
[dependencies]
-autocxx = "0.22.3"
+autocxx = "0.26.0"
cxx = "1.0"
[build-dependencies]
-autocxx-build = "0.22.3"
-miette = { version="4.3", features=["fancy"] } # optional but gives nicer error messages!
+autocxx-build = "0.26.0"
+miette = { version = "5", features = ["fancy"] } # optional but gives nicer error messages!
```
Now, add a `build.rs` next to your `Cargo.toml` (this is a standard `cargo` [build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html)). This is where you need your include path:
diff --git a/third_party/autocxx/build.rs b/third_party/autocxx/build.rs
new file mode 100644
index 0000000..b2de2dc
--- /dev/null
+++ b/third_party/autocxx/build.rs
@@ -0,0 +1,27 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// It would be nice to use the rustversion crate here instead,
+// but that doesn't work with inner attributes.
+fn main() {
+ if let Some(ver) = rustc_version() {
+ if ver.contains("nightly") {
+ println!("cargo:rustc-cfg=nightly")
+ }
+ }
+}
+
+fn rustc_version() -> Option<String> {
+ let rustc = std::env::var_os("RUSTC")?;
+ let output = std::process::Command::new(rustc)
+ .arg("--version")
+ .output()
+ .ok()?;
+ let version = String::from_utf8(output.stdout).ok()?;
+ Some(version)
+}
diff --git a/third_party/autocxx/demo/Cargo.toml b/third_party/autocxx/demo/Cargo.toml
index e81cb80..7064bea 100644
--- a/third_party/autocxx/demo/Cargo.toml
+++ b/third_party/autocxx/demo/Cargo.toml
@@ -8,14 +8,14 @@
[package]
name = "autocxx-demo"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../gen/build", version="0.22.3" }
-miette = { version="4.3", features=["fancy"]}
+autocxx-build = { path = "../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/demo/build.rs b/third_party/autocxx/demo/build.rs
index 9a16a34..69c632c 100644
--- a/third_party/autocxx/demo/build.rs
+++ b/third_party/autocxx/demo/build.rs
@@ -8,7 +8,7 @@
fn main() -> miette::Result<()> {
let path = std::path::PathBuf::from("src");
- let mut b = autocxx_build::Builder::new("src/main.rs", &[&path]).build()?;
+ let mut b = autocxx_build::Builder::new("src/main.rs", [&path]).build()?;
b.flag_if_supported("-std=c++14").compile("autocxx-demo");
println!("cargo:rerun-if-changed=src/main.rs");
diff --git a/third_party/autocxx/engine/BUILD b/third_party/autocxx/engine/BUILD
index fd4fc83..7f72ea0 100644
--- a/third_party/autocxx/engine/BUILD
+++ b/third_party/autocxx/engine/BUILD
@@ -17,9 +17,9 @@
crate_root = "src/lib.rs",
edition = "2021",
proc_macro_deps = [
+ "@crate_index//:rustversion",
"@crate_index//:indoc",
"@crate_index//:aquamarine",
- "@crate_index//:strum_macros",
],
rustc_flags = [
"--cap-lints=allow",
@@ -39,13 +39,13 @@
"@crate_index//:log",
"@crate_index//:miette",
"@crate_index//:once_cell",
+ "@crate_index//:prettyplease",
"@crate_index//:proc-macro2",
"@crate_index//:quote",
"@crate_index//:regex",
"@crate_index//:serde_json",
- "@crate_index//:syn",
+ "@crate_index//:syn-2.0.28",
"@crate_index//:tempfile",
"@crate_index//:thiserror",
- "@crate_index//:version_check",
],
)
diff --git a/third_party/autocxx/engine/Cargo.toml b/third_party/autocxx/engine/Cargo.toml
index 1400847..9736db9 100644
--- a/third_party/autocxx/engine/Cargo.toml
+++ b/third_party/autocxx/engine/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx-engine"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
license = "MIT OR Apache-2.0"
description = "Safe autogenerated interop between Rust and C++"
@@ -18,42 +18,43 @@
categories = ["development-tools::ffi", "api-bindings"]
[features]
-default = [ "reproduction_case" ]
+default = ["reproduction_case", "runtime"]
build = ["cc"]
-nightly = [] # for doc generation purposes only; used by docs.rs
-reproduction_case = [ "serde_json", "autocxx-parser/reproduction_case" ]
-runtime = [ "autocxx-bindgen/runtime" ]
-static = [ "autocxx-bindgen/static" ]
+nightly = [] # for doc generation purposes only; used by docs.rs
+reproduction_case = ["serde_json", "autocxx-parser/reproduction_case"]
+runtime = ["autocxx-bindgen/runtime"]
+static = ["autocxx-bindgen/static"]
[dependencies]
log = "0.4"
proc-macro2 = "1.0.11"
quote = "1.0"
indoc = "1.0"
-autocxx-bindgen = "=0.59.17"
-#autocxx-bindgen = { git = "https://github.com/adetaylor/rust-bindgen", branch = "pollute-fewer-typedefs" }
+autocxx-bindgen = { version = "=0.65.1", default-features = false, features = ["logging", "which-rustfmt"] }
+#autocxx-bindgen = { git = "https://github.com/maurer/rust-bindgen", branch = "update-0.65.1", default-features = false, features = ["logging", "which-rustfmt"] }
itertools = "0.10.3"
cc = { version = "1.0", optional = true }
# Note: Keep the patch-level version of cxx-gen and cxx in sync.
# There can be interdependencies between the code generated by cxx-gen and
# what cxx expects to be there.
-cxx-gen = "0.7.68"
-autocxx-parser = { version = "=0.22.3", path="../parser" }
+cxx-gen = "0.7.78"
+autocxx-parser = { version = "=0.26.0", path = "../parser" }
version_check = "0.9"
-aquamarine = "0.1" # docs
-tempfile = "3.1"
+aquamarine = "0.1" # docs
+tempfile = "3.4"
once_cell = "1.7"
-strum_macros = "0.24"
serde_json = { version = "1.0", optional = true }
-miette = "4.3"
+miette = "5"
thiserror = "1"
regex = "1.5"
indexmap = "1.8"
+prettyplease = { version = "0.2.6", features = ["verbatim"] }
+rustversion = "1.0"
[dependencies.syn]
-version = "1.0.39"
-features = [ "full", "printing" ]
-#features = [ "full", "printing", "extra-traits" ]
+version = "2.0.1"
+features = ["full", "printing", "visit-mut"]
+#features = [ "full", "printing", "visit-mut", "extra-traits" ]
[package.metadata.docs.rs]
features = ["build", "nightly"]
diff --git a/third_party/autocxx/engine/src/ast_discoverer.rs b/third_party/autocxx/engine/src/ast_discoverer.rs
index 8840899..f555419 100644
--- a/third_party/autocxx/engine/src/ast_discoverer.rs
+++ b/third_party/autocxx/engine/src/ast_discoverer.rs
@@ -14,12 +14,13 @@
};
use itertools::Itertools;
use proc_macro2::Ident;
+use syn::visit_mut::{visit_type_mut, VisitMut};
use syn::{
- parse_quote, punctuated::Punctuated, Attribute, Binding, Expr, ExprAssign, ExprAssignOp,
- ExprAwait, ExprBinary, ExprBox, ExprBreak, ExprCast, ExprField, ExprGroup, ExprLet, ExprParen,
- ExprReference, ExprTry, ExprType, ExprUnary, ImplItem, Item, ItemEnum, ItemStruct, Pat, PatBox,
- PatReference, PatSlice, PatTuple, Path, Receiver, ReturnType, Signature, Stmt, TraitItem, Type,
- TypeArray, TypeGroup, TypeParamBound, TypeParen, TypePtr, TypeReference, TypeSlice,
+ parse_quote, punctuated::Punctuated, AssocConst, AssocType, Attribute, Expr, ExprAssign,
+ ExprAwait, ExprBinary, ExprBlock, ExprBreak, ExprCast, ExprConst, ExprField, ExprGroup,
+ ExprLet, ExprParen, ExprReference, ExprTry, ExprUnary, ImplItem, Item, ItemEnum, ItemStruct,
+ LocalInit, Pat, PatReference, PatSlice, PatTuple, Path, ReturnType, Signature, Stmt, TraitItem,
+ Type, TypeArray, TypeGroup, TypeParamBound, TypeParen, TypePtr, TypeReference, TypeSlice,
};
use thiserror::Error;
@@ -34,8 +35,6 @@
pub enum DiscoveryErr {
#[error("#[extern_rust_function] was attached to a method in an impl block that was too complex for autocxx. autocxx supports only \"impl X {{...}}\" where X is a single identifier, not a path or more complex type.")]
FoundExternRustFunOnTypeWithoutClearReceiver,
- #[error("#[extern_rust_function] was attached to a method taking no parameters.")]
- NonReferenceReceiver,
#[error("#[extern_rust_function] was attached to a method taking a receiver by value.")]
NoParameterOnMethod,
#[error("#[extern_rust_function] was in an impl block nested wihtin another block. This is only supported in the outermost mod of a file, alongside the include_cpp!.")]
@@ -103,7 +102,7 @@
self.discoveries.extern_rust_funs.push(RustFun {
path: self.deeper_path(&fun.sig.ident),
sig: fun.sig.clone(),
- receiver: None,
+ has_receiver: false,
});
}
}
@@ -178,7 +177,7 @@
}
fn search_trait_item(&mut self, itm: &TraitItem) -> Result<(), DiscoveryErr> {
- if let TraitItem::Method(itm) = itm {
+ if let TraitItem::Fn(itm) = itm {
if let Some(block) = &itm.default {
self.search_stmts(block.stmts.iter())?
}
@@ -199,13 +198,14 @@
fn search_stmt(&mut self, stmt: &Stmt) -> Result<(), DiscoveryErr> {
match stmt {
Stmt::Local(lcl) => {
- if let Some((_, expr)) = &lcl.init {
+ if let Some(LocalInit { expr, .. }) = &lcl.init {
self.search_expr(expr)?
}
self.search_pat(&lcl.pat)
}
Stmt::Item(itm) => self.search_item(itm),
- Stmt::Expr(exp) | Stmt::Semi(exp, _) => self.search_expr(exp),
+ Stmt::Expr(exp, _) => self.search_expr(exp),
+ Stmt::Macro(_) => Ok(()),
}
}
@@ -214,10 +214,9 @@
Expr::Path(exp) => {
self.search_path(&exp.path)?;
}
- Expr::Macro(_) => {}
+ Expr::Macro(_) | Expr::Infer(_) => {}
Expr::Array(array) => self.search_exprs(array.elems.iter())?,
Expr::Assign(ExprAssign { left, right, .. })
- | Expr::AssignOp(ExprAssignOp { left, right, .. })
| Expr::Binary(ExprBinary { left, right, .. }) => {
self.search_expr(left)?;
self.search_expr(right)?;
@@ -226,9 +225,10 @@
Expr::Await(ExprAwait { base, .. }) | Expr::Field(ExprField { base, .. }) => {
self.search_expr(base)?
}
- Expr::Block(blck) => self.search_stmts(blck.block.stmts.iter())?,
- Expr::Box(ExprBox { expr, .. })
- | Expr::Break(ExprBreak {
+ Expr::Block(ExprBlock { block, .. }) | Expr::Const(ExprConst { block, .. }) => {
+ self.search_stmts(block.stmts.iter())?
+ }
+ Expr::Break(ExprBreak {
expr: Some(expr), ..
})
| Expr::Cast(ExprCast { expr, .. })
@@ -236,7 +236,6 @@
| Expr::Paren(ExprParen { expr, .. })
| Expr::Reference(ExprReference { expr, .. })
| Expr::Try(ExprTry { expr, .. })
- | Expr::Type(ExprType { expr, .. })
| Expr::Unary(ExprUnary { expr, .. }) => self.search_expr(expr)?,
Expr::Call(exc) => {
self.search_expr(&exc.func)?;
@@ -281,8 +280,8 @@
self.search_exprs(mtc.args.iter())?;
}
Expr::Range(exr) => {
- self.search_option_expr(&exr.from)?;
- self.search_option_expr(&exr.to)?;
+ self.search_option_expr(&exr.start)?;
+ self.search_option_expr(&exr.end)?;
}
Expr::Repeat(exr) => {
self.search_expr(&exr.expr)?;
@@ -334,7 +333,7 @@
impl_item: &ImplItem,
receiver: Option<&RustPath>,
) -> Result<(), DiscoveryErr> {
- if let ImplItem::Method(itm) = impl_item {
+ if let ImplItem::Fn(itm) = impl_item {
if Self::has_attr(&itm.attrs, EXTERN_RUST_FUN) {
if self.mod_path.is_some() {
return Err(DiscoveryErr::FoundExternRustFunWithinMod);
@@ -347,7 +346,7 @@
self.discoveries.extern_rust_funs.push(RustFun {
path: self.deeper_path(&itm.sig.ident),
sig,
- receiver: Some(receiver.get_final_ident().clone()),
+ has_receiver: true,
});
self.discoveries.extern_rust_types.push(receiver.clone())
} else {
@@ -363,10 +362,15 @@
fn search_pat(&mut self, pat: &Pat) -> Result<(), DiscoveryErr> {
match pat {
- Pat::Box(PatBox { pat, .. }) | Pat::Reference(PatReference { pat, .. }) => {
- self.search_pat(pat)
+ Pat::Const(const_) => {
+ for stmt in &const_.block.stmts {
+ self.search_stmt(stmt)?
+ }
+ Ok(())
}
+ Pat::Reference(PatReference { pat, .. }) => self.search_pat(pat),
Pat::Ident(_) | Pat::Lit(_) | Pat::Macro(_) | Pat::Range(_) | Pat::Rest(_) => Ok(()),
+ Pat::Paren(paren) => self.search_pat(&paren.pat),
Pat::Or(pator) => {
for case in &pator.cases {
self.search_pat(case)?;
@@ -389,7 +393,7 @@
}
Pat::TupleStruct(tps) => {
self.search_path(&tps.path)?;
- for f in &tps.pat.elems {
+ for f in &tps.elems {
self.search_pat(f)?;
}
Ok(())
@@ -398,6 +402,7 @@
self.search_pat(&pt.pat)?;
self.search_type(&pt.ty)
}
+ Pat::Verbatim(_) | Pat::Wild(_) => Ok(()),
_ => Ok(()),
}
}
@@ -438,7 +443,7 @@
fn search_type_param_bounds(
&mut self,
- bounds: &Punctuated<TypeParamBound, syn::token::Add>,
+ bounds: &Punctuated<TypeParamBound, syn::token::Plus>,
) -> Result<(), DiscoveryErr> {
for b in bounds {
if let syn::TypeParamBound::Trait(tpbt) = b {
@@ -467,13 +472,17 @@
match arg {
syn::GenericArgument::Lifetime(_) => {}
syn::GenericArgument::Type(ty)
- | syn::GenericArgument::Binding(Binding { ty, .. }) => {
+ | syn::GenericArgument::AssocType(AssocType { ty, .. }) => {
self.search_type(ty)?
}
syn::GenericArgument::Constraint(c) => {
self.search_type_param_bounds(&c.bounds)?
}
- syn::GenericArgument::Const(c) => self.search_expr(c)?,
+ syn::GenericArgument::Const(value)
+ | syn::GenericArgument::AssocConst(AssocConst { value, .. }) => {
+ self.search_expr(value)?
+ }
+ _ => {}
}
}
}
@@ -489,7 +498,7 @@
fn has_attr(attrs: &[Attribute], attr_name: &str) -> bool {
attrs.iter().any(|attr| {
- attr.path
+ attr.path()
.segments
.last()
.map(|seg| seg.ident == attr_name)
@@ -498,6 +507,24 @@
}
}
+struct SelfSubstituter<'a> {
+ self_ty: &'a Ident,
+}
+
+impl<'a> SelfSubstituter<'a> {
+ pub fn new(self_ty: &'a Ident) -> Self {
+ Self { self_ty }
+ }
+}
+
+impl<'a> VisitMut for SelfSubstituter<'a> {
+ fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) {
+ if i.qself.is_none() && i.path.is_ident("Self") {
+ i.path = Path::from(self.self_ty.clone());
+ }
+ }
+}
+
/// Take a method signature that may be `fn a(&self)`
/// and turn it into `fn a(self: &A)` which is what we will
/// need to specify to cxx.
@@ -505,25 +532,19 @@
let mut sig = sig.clone();
match sig.inputs.iter_mut().next() {
Some(first_arg) => match first_arg {
- syn::FnArg::Receiver(Receiver {
- reference: Some(_),
- mutability: Some(_),
- ..
- }) => {
+ syn::FnArg::Receiver(rec_arg) => {
+ let mut substituted_type = rec_arg.ty.clone();
+ visit_type_mut(&mut SelfSubstituter::new(receiver), &mut substituted_type);
*first_arg = parse_quote! {
- self: &mut #receiver
+ qelf: #substituted_type
+ };
+ if let syn::FnArg::Typed(ref mut pat_type) = *first_arg {
+ if let syn::Pat::Ident(ref mut pat_ident) = *pat_type.pat {
+ assert_eq!(pat_ident.ident.to_string(), "qelf");
+ pat_ident.ident = Ident::new("self", pat_ident.ident.span());
+ }
}
}
- syn::FnArg::Receiver(Receiver {
- reference: Some(_),
- mutability: None,
- ..
- }) => {
- *first_arg = parse_quote! {
- self: &#receiver
- }
- }
- syn::FnArg::Receiver(..) => return Err(DiscoveryErr::NonReferenceReceiver),
syn::FnArg::Typed(_) => {}
},
None => return Err(DiscoveryErr::NoParameterOnMethod),
@@ -534,7 +555,7 @@
#[cfg(test)]
mod tests {
use quote::{quote, ToTokens};
- use syn::{parse_quote, ImplItemMethod};
+ use syn::{parse_quote, ImplItemFn};
use crate::{ast_discoverer::add_receiver, types::make_ident};
@@ -690,7 +711,7 @@
#[test]
fn test_add_receiver() {
- let meth: ImplItemMethod = parse_quote! {
+ let meth: ImplItemFn = parse_quote! {
fn a(&self) {}
};
let a = make_ident("A");
@@ -702,7 +723,7 @@
quote! { fn a(self: &A) }.to_string()
);
- let meth: ImplItemMethod = parse_quote! {
+ let meth: ImplItemFn = parse_quote! {
fn a(&mut self, b: u32) -> Foo {}
};
assert_eq!(
@@ -713,12 +734,7 @@
quote! { fn a(self: &mut A, b: u32) -> Foo }.to_string()
);
- let meth: ImplItemMethod = parse_quote! {
- fn a(self) {}
- };
- assert!(add_receiver(&meth.sig, &a).is_err());
-
- let meth: ImplItemMethod = parse_quote! {
+ let meth: ImplItemFn = parse_quote! {
fn a() {}
};
assert!(add_receiver(&meth.sig, &a).is_err());
diff --git a/third_party/autocxx/engine/src/builder.rs b/third_party/autocxx/engine/src/builder.rs
index d0b5199..064056e 100644
--- a/third_party/autocxx/engine/src/builder.rs
+++ b/third_party/autocxx/engine/src/builder.rs
@@ -10,8 +10,8 @@
use miette::Diagnostic;
use thiserror::Error;
-use crate::generate_rs_single;
-use crate::{strip_system_headers, CppCodegenOptions, ParseError, RebuildDependencyRecorder};
+use crate::{generate_rs_single, CodegenOptions};
+use crate::{get_cxx_header_bytes, CppCodegenOptions, ParseError, RebuildDependencyRecorder};
use std::ffi::OsStr;
use std::ffi::OsString;
use std::fs::File;
@@ -63,8 +63,16 @@
/// An object to allow building of bindings from a `build.rs` file.
///
-/// It would be unusual to use this directly - see the `autocxx_build` or
+/// It would be unusual to create this directly - see the `autocxx_build` or
/// `autocxx_gen` crates.
+///
+/// Once you've got one of these objects, you may set some configuration
+/// options but then you're likely to want to call the [`build`] method.
+///
+/// # Setting C++ version
+///
+/// Ensure you use [`extra_clang_args`] as well as giving an appropriate
+/// option to the [`cc::Build`] which you receive from the [`build`] function.
#[cfg_attr(feature = "nightly", doc(cfg(feature = "build")))]
pub struct Builder<'a, BuilderContext> {
rs_file: PathBuf,
@@ -73,7 +81,7 @@
dependency_recorder: Option<Box<dyn RebuildDependencyRecorder>>,
custom_gendir: Option<PathBuf>,
auto_allowlist: bool,
- cpp_codegen_options: CppCodegenOptions<'a>,
+ codegen_options: CodegenOptions<'a>,
// This member is to ensure that this type is parameterized
// by a BuilderContext. The goal is to balance three needs:
// (1) have most of the functionality over in autocxx_engine,
@@ -108,12 +116,14 @@
dependency_recorder: CTX::get_dependency_recorder(),
custom_gendir: None,
auto_allowlist: false,
- cpp_codegen_options: CppCodegenOptions::default(),
+ codegen_options: CodegenOptions::default(),
ctx: PhantomData,
}
}
- /// Specify extra arguments for clang.
+ /// Specify extra arguments for clang. These are used when parsing
+ /// C++ headers. For example, you might want to provide
+ /// `-std=c++17` to specify C++17.
pub fn extra_clang_args(mut self, extra_clang_args: &[&str]) -> Self {
self.extra_clang_args = extra_clang_args.iter().map(|s| s.to_string()).collect();
self
@@ -130,7 +140,7 @@
where
F: FnOnce(&mut CppCodegenOptions),
{
- modifier(&mut self.cpp_codegen_options);
+ modifier(&mut self.codegen_options.cpp_codegen_options);
self
}
@@ -152,20 +162,33 @@
self
}
+ #[doc(hidden)]
+ /// Whether to force autocxx always to generate extra Rust and C++
+ /// side shims. This is only used by the integration test suite to
+ /// exercise more code paths - don't use it!
+ pub fn force_wrapper_generation(mut self, do_it: bool) -> Self {
+ self.codegen_options.force_wrapper_gen = do_it;
+ self
+ }
+
/// Whether to suppress inclusion of system headers (`memory`, `string` etc.)
/// from generated C++ bindings code. This should not normally be used,
/// but can occasionally be useful if you're reducing a test case and you
/// have a preprocessed header file which already contains absolutely everything
/// that the bindings could ever need.
pub fn suppress_system_headers(mut self, do_it: bool) -> Self {
- self.cpp_codegen_options.suppress_system_headers = do_it;
+ self.codegen_options
+ .cpp_codegen_options
+ .suppress_system_headers = do_it;
self
}
/// An annotation optionally to include on each C++ function.
/// For example to export the symbol from a library.
pub fn cxx_impl_annotations(mut self, cxx_impl_annotations: Option<String>) -> Self {
- self.cpp_codegen_options.cxx_impl_annotations = cxx_impl_annotations;
+ self.codegen_options
+ .cpp_codegen_options
+ .cxx_impl_annotations = cxx_impl_annotations;
self
}
@@ -176,6 +199,17 @@
/// so if you use the `miette` crate and its `fancy` feature, then simply
/// return a `miette::Result` from your main function, you should get nicely
/// printed diagnostics.
+ ///
+ /// As this is a [`cc::Build`] there are lots of options you can apply to
+ /// the resulting options, but please bear in mind that these only apply
+ /// to the build process for the generated code - such options will not
+ /// influence autocxx's process for parsing header files.
+ ///
+ /// For example, if you wish to set the C++ version to C++17, you might
+ /// be tempted to use [`cc::Build::flag_if_supported`] to add the
+ /// `-std=c++17` flag. However, this won't affect the header parsing which
+ /// autocxx does internally (by means of bindgen) so you _additionally_
+ /// should call [`extra_clang_args`] with that same option.
pub fn build(self) -> Result<BuilderBuild, BuilderError> {
self.build_listing_files().map(|r| r.0)
}
@@ -208,7 +242,11 @@
write_to_file(
&incdir,
"cxx.h",
- &Self::get_cxx_header_bytes(self.cpp_codegen_options.suppress_system_headers),
+ &get_cxx_header_bytes(
+ self.codegen_options
+ .cpp_codegen_options
+ .suppress_system_headers,
+ ),
)?;
let autocxx_inc = build_autocxx_inc(self.autocxx_incs, &incdir);
@@ -221,7 +259,7 @@
autocxx_inc,
clang_args,
self.dependency_recorder,
- &self.cpp_codegen_options,
+ &self.codegen_options,
)
.map_err(BuilderError::ParseError)?;
let mut counter = 0;
@@ -235,10 +273,10 @@
builder.includes(parsed_file.include_dirs());
for include_cpp in parsed_file.get_cpp_buildables() {
let generated_code = include_cpp
- .generate_h_and_cxx(&self.cpp_codegen_options)
+ .generate_h_and_cxx(&self.codegen_options.cpp_codegen_options)
.map_err(BuilderError::InvalidCxx)?;
for filepair in generated_code.0 {
- let fname = format!("gen{}.cxx", counter);
+ let fname = format!("gen{counter}.cxx");
counter += 1;
if let Some(implementation) = &filepair.implementation {
let gen_cxx_path = write_to_file(&cxxdir, &fname, implementation)?;
@@ -260,10 +298,6 @@
Ok(BuilderSuccess(builder, generated_rs, generated_cpp))
}
}
-
- fn get_cxx_header_bytes(suppress_system_headers: bool) -> Vec<u8> {
- strip_system_headers(crate::HEADER.as_bytes().to_vec(), suppress_system_headers)
- }
}
fn ensure_created(dir: &Path) -> Result<(), BuilderError> {
@@ -285,6 +319,13 @@
fn write_to_file(dir: &Path, filename: &str, content: &[u8]) -> Result<PathBuf, BuilderError> {
let path = dir.join(filename);
+ if let Ok(existing_contents) = std::fs::read(&path) {
+ // Avoid altering timestamps on disk if the file already exists,
+ // to stop downstream build steps recurring.
+ if existing_contents == content {
+ return Ok(path);
+ }
+ }
try_write_to_file(&path, content).map_err(|e| BuilderError::FileWriteFail(e, path.clone()))?;
Ok(path)
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/abstract_types.rs b/third_party/autocxx/engine/src/conversion/analysis/abstract_types.rs
index dac9684..884cbd0 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/abstract_types.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/abstract_types.rs
@@ -6,6 +6,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use indexmap::map::IndexMap as HashMap;
+use syn::{punctuated::Punctuated, token::Comma, FnArg};
+
use super::{
fun::{
FnAnalysis, FnKind, FnPhase, FnPrePhase2, MethodKind, PodAndConstructorAnalysis,
@@ -13,106 +16,164 @@
},
pod::PodAnalysis,
};
-use crate::conversion::{api::Api, apivec::ApiVec};
use crate::conversion::{
- api::TypeKind,
+ analysis::{depth_first::fields_and_bases_first, fun::ReceiverMutability},
+ api::{ApiName, TypeKind},
error_reporter::{convert_apis, convert_item_apis},
- ConvertError,
+ ConvertErrorFromCpp,
+};
+use crate::{
+ conversion::{api::Api, apivec::ApiVec},
+ types::QualifiedName,
};
use indexmap::set::IndexSet as HashSet;
+#[derive(Hash, PartialEq, Eq, Clone, Debug)]
+struct Signature {
+ name: String,
+ args: Vec<syn::Type>,
+ constness: ReceiverMutability,
+}
+
+impl Signature {
+ fn new(
+ name: &ApiName,
+ params: &Punctuated<FnArg, Comma>,
+ constness: ReceiverMutability,
+ ) -> Self {
+ Signature {
+ name: name.cpp_name(),
+ args: params
+ .iter()
+ .skip(1) // skip `this` implicit argument
+ .filter_map(|p| {
+ if let FnArg::Typed(t) = p {
+ Some((*t.ty).clone())
+ } else {
+ None
+ }
+ })
+ .collect(),
+ constness,
+ }
+ }
+}
+
/// Spot types with pure virtual functions and mark them abstract.
-pub(crate) fn mark_types_abstract(mut apis: ApiVec<FnPrePhase2>) -> ApiVec<FnPrePhase2> {
- let mut abstract_types: HashSet<_> = apis
- .iter()
- .filter_map(|api| match &api {
- Api::Function {
- analysis:
- FnAnalysis {
- kind:
- FnKind::Method {
- impl_for: self_ty_name,
- method_kind: MethodKind::PureVirtual(_),
- ..
- },
- ..
- },
- ..
- } => Some(self_ty_name.clone()),
- _ => None,
+pub(crate) fn mark_types_abstract(apis: ApiVec<FnPrePhase2>) -> ApiVec<FnPrePhase2> {
+ #[derive(Default, Debug, Clone)]
+ struct ClassAbstractState {
+ undefined: HashSet<Signature>,
+ defined: HashSet<Signature>,
+ }
+ let mut class_states: HashMap<QualifiedName, ClassAbstractState> = HashMap::new();
+ let mut abstract_classes = HashSet::new();
+
+ for api in apis.iter() {
+ if let Api::Function {
+ name,
+ analysis:
+ FnAnalysis {
+ kind:
+ FnKind::Method {
+ impl_for: self_ty_name,
+ method_kind,
+ ..
+ },
+ params,
+ ..
+ },
+ ..
+ } = api
+ {
+ match method_kind {
+ MethodKind::PureVirtual(constness) => {
+ class_states
+ .entry(self_ty_name.clone())
+ .or_default()
+ .undefined
+ .insert(Signature::new(name, params, *constness));
+ }
+ MethodKind::Virtual(constness) => {
+ class_states
+ .entry(self_ty_name.clone())
+ .or_default()
+ .defined
+ .insert(Signature::new(name, params, *constness));
+ }
+ _ => {}
+ }
+ }
+ }
+
+ for api in fields_and_bases_first(apis.iter()) {
+ if let Api::Struct {
+ analysis:
+ PodAndConstructorAnalysis {
+ pod:
+ PodAnalysis {
+ bases,
+ kind: TypeKind::Pod | TypeKind::NonPod,
+ ..
+ },
+ ..
+ },
+ name,
+ ..
+ } = api
+ {
+ // resolve virtuals for a class: start with new pure virtuals in this class
+ let mut self_cs = class_states.get(&name.name).cloned().unwrap_or_default();
+
+ // then add pure virtuals of bases
+ for base in bases.iter() {
+ if let Some(base_cs) = class_states.get(base) {
+ self_cs.undefined.extend(base_cs.undefined.iter().cloned());
+ }
+ }
+
+ // then remove virtuals defined in this class
+ self_cs
+ .undefined
+ .retain(|und| !self_cs.defined.contains(und));
+
+ // if there are undefined functions, mark as virtual
+ if !self_cs.undefined.is_empty() {
+ abstract_classes.insert(name.name.clone());
+ }
+
+ // store it back so child classes can read it properly
+ *class_states.entry(name.name.clone()).or_default() = self_cs;
+ }
+ }
+
+ // mark abstract types as abstract
+ let mut apis: ApiVec<_> = apis
+ .into_iter()
+ .map(|mut api| {
+ if let Api::Struct { name, analysis, .. } = &mut api {
+ if abstract_classes.contains(&name.name) {
+ analysis.pod.kind = TypeKind::Abstract;
+ }
+ }
+ api
})
.collect();
- // Spot any derived classes (recursively). Also, any types which have a base
- // class that's not on the allowlist are presumed to be abstract, because we
- // have no way of knowing (as they're not on the allowlist, there will be
- // no methods associated so we won't be able to spot pure virtual methods).
- let mut iterate = true;
- while iterate {
- iterate = false;
- apis = apis
- .into_iter()
- .map(|api| {
- match api {
- Api::Struct {
- analysis:
- PodAndConstructorAnalysis {
- pod:
- PodAnalysis {
- bases,
- kind: TypeKind::Pod | TypeKind::NonPod,
- castable_bases,
- field_deps,
- field_info,
- is_generic,
- in_anonymous_namespace,
- },
- constructors,
- },
- name,
- details,
- } if abstract_types.contains(&name.name)
- || !abstract_types.is_disjoint(&bases) =>
- {
- abstract_types.insert(name.name.clone());
- // Recurse in case there are further dependent types
- iterate = true;
- Api::Struct {
- analysis: PodAndConstructorAnalysis {
- pod: PodAnalysis {
- bases,
- kind: TypeKind::Abstract,
- castable_bases,
- field_deps,
- field_info,
- is_generic,
- in_anonymous_namespace,
- },
- constructors,
- },
- name,
- details,
- }
- }
- _ => api,
- }
- })
- .collect()
- }
-
// We also need to remove any constructors belonging to these
// abstract types.
apis.retain(|api| {
!matches!(&api,
- Api::Function {
- analysis:
- FnAnalysis {
- kind: FnKind::Method{impl_for: self_ty, method_kind: MethodKind::Constructor{..}, ..}
- | FnKind::TraitMethod{ kind: TraitMethodKind::CopyConstructor | TraitMethodKind::MoveConstructor, impl_for: self_ty, ..},
+ Api::Function {
+ analysis:
+ FnAnalysis {
+ kind: FnKind::Method{impl_for: self_ty, method_kind: MethodKind::Constructor{..}, ..}
+ | FnKind::TraitMethod{ kind: TraitMethodKind::CopyConstructor | TraitMethodKind::MoveConstructor, impl_for: self_ty, ..},
+ ..
+ },
..
- },
- ..
- } if abstract_types.contains(self_ty))
+ } if abstract_classes.contains(self_ty)
+ )
});
// Finally, if there are any types which are nested inside other types,
@@ -143,10 +204,11 @@
.map(|n| n.contains("::"))
.unwrap_or_default() =>
{
- Err(ConvertError::AbstractNestedType)
+ Err(ConvertErrorFromCpp::AbstractNestedType)
}
_ => Ok(Box::new(std::iter::once(api))),
});
+
results
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/allocators.rs b/third_party/autocxx/engine/src/conversion/analysis/allocators.rs
index 3695de0..da25a77 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/allocators.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/allocators.rs
@@ -12,9 +12,13 @@
use crate::{
conversion::{
- api::{Api, ApiName, CppVisibility, FuncToConvert, Provenance, References, TraitSynthesis},
+ api::{
+ Api, ApiName, CppVisibility, DeletedOrDefaulted, FuncToConvert, Provenance, References,
+ TraitSynthesis,
+ },
apivec::ApiVec,
},
+ minisyn::minisynize_punctuated,
types::{make_ident, QualifiedName},
};
@@ -73,8 +77,8 @@
fun: Box::new(FuncToConvert {
ident,
doc_attrs: Vec::new(),
- inputs,
- output,
+ inputs: minisynize_punctuated(inputs),
+ output: output.into(),
vis: parse_quote! { pub },
virtualness: crate::conversion::api::Virtualness::None,
cpp_vis: CppVisibility::Public,
@@ -86,7 +90,7 @@
synthesized_this_type: None,
synthetic_cpp: Some((cpp_function_body, CppFunctionKind::Function)),
add_to_trait: Some(synthesis),
- is_deleted: false,
+ is_deleted: DeletedOrDefaulted::Neither,
provenance: Provenance::SynthesizedOther,
variadic: false,
}),
diff --git a/third_party/autocxx/engine/src/conversion/analysis/casts.rs b/third_party/autocxx/engine/src/conversion/analysis/casts.rs
index 5f493f9..2426a50 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/casts.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/casts.rs
@@ -6,13 +6,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use crate::minisyn::FnArg;
use itertools::Itertools;
use quote::quote;
-use syn::{parse_quote, FnArg};
+use syn::parse_quote;
use crate::{
conversion::{
- api::{Api, ApiName, CastMutability, Provenance, References, TraitSynthesis},
+ api::{
+ Api, ApiName, CastMutability, DeletedOrDefaulted, Provenance, References,
+ TraitSynthesis,
+ },
apivec::ApiVec,
},
types::{make_ident, QualifiedName},
@@ -112,7 +116,7 @@
mutable,
}),
synthetic_cpp: Some((CppFunctionBody::Cast, CppFunctionKind::Function)),
- is_deleted: false,
+ is_deleted: DeletedOrDefaulted::Neither,
provenance: Provenance::SynthesizedOther,
variadic: false,
}),
diff --git a/third_party/autocxx/engine/src/conversion/analysis/ctypes.rs b/third_party/autocxx/engine/src/conversion/analysis/ctypes.rs
index b2ce840..bc6f096 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/ctypes.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/ctypes.rs
@@ -8,7 +8,7 @@
use indexmap::map::IndexMap as HashMap;
-use syn::Ident;
+use crate::minisyn::Ident;
use crate::conversion::api::ApiName;
use crate::conversion::apivec::ApiVec;
diff --git a/third_party/autocxx/engine/src/conversion/analysis/deps.rs b/third_party/autocxx/engine/src/conversion/analysis/deps.rs
index 7aca96c..a301090 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/deps.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/deps.rs
@@ -6,8 +6,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use itertools::Itertools;
-
use crate::{
conversion::api::{Api, TypeKind},
types::QualifiedName,
@@ -22,10 +20,6 @@
pub(crate) trait HasDependencies {
fn name(&self) -> &QualifiedName;
fn deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_>;
-
- fn format_deps(&self) -> String {
- self.deps().join(",")
- }
}
impl HasDependencies for Api<FnPrePhase1> {
@@ -37,13 +31,9 @@
..
} => Box::new(old_tyname.iter().chain(deps.iter())),
Api::Struct {
- analysis:
- PodAnalysis {
- kind: TypeKind::Pod,
- bases,
- field_deps,
- ..
- },
+ analysis: PodAnalysis {
+ bases, field_deps, ..
+ },
..
} => Box::new(field_deps.iter().chain(bases.iter())),
Api::Function { analysis, .. } => Box::new(analysis.deps.iter()),
@@ -52,7 +42,7 @@
superclass,
} => Box::new(std::iter::once(superclass)),
Api::RustSubclassFn { details, .. } => Box::new(details.dependencies.iter()),
- Api::RustFn { receiver, .. } => Box::new(receiver.iter()),
+ Api::RustFn { deps, .. } => Box::new(deps.iter()),
_ => Box::new(std::iter::empty()),
}
}
@@ -105,7 +95,7 @@
superclass,
} => Box::new(std::iter::once(superclass)),
Api::RustSubclassFn { details, .. } => Box::new(details.dependencies.iter()),
- Api::RustFn { receiver, .. } => Box::new(receiver.iter()),
+ Api::RustFn { deps, .. } => Box::new(deps.iter()),
_ => Box::new(std::iter::empty()),
}
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/depth_first.rs b/third_party/autocxx/engine/src/conversion/analysis/depth_first.rs
index 02459e1..baadbd7 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/depth_first.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/depth_first.rs
@@ -14,10 +14,20 @@
use crate::types::QualifiedName;
-use super::deps::HasDependencies;
+/// A little like `HasDependencies` but accounts for only direct fiele
+/// and bases.
+pub(crate) trait HasFieldsAndBases {
+ fn name(&self) -> &QualifiedName;
+ /// Return field and base class dependencies of this item.
+ /// This should only include those items where a definition is required,
+ /// not merely a declaration. So if the field type is
+ /// `std::unique_ptr<A>`, this should only return `std::unique_ptr`.
+ fn field_and_base_deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_>;
+}
-/// Return APIs in a depth-first order, i.e. those with no dependencies first.
-pub(super) fn depth_first<'a, T: HasDependencies + Debug + 'a>(
+/// Iterate through APIs in an order such that later APIs have no fields or bases
+/// other than those whose types have already been processed.
+pub(super) fn fields_and_bases_first<'a, T: HasFieldsAndBases + Debug + 'a>(
inputs: impl Iterator<Item = &'a T> + 'a,
) -> impl Iterator<Item = &'a T> {
let queue: VecDeque<_> = inputs.collect();
@@ -25,18 +35,21 @@
DepthFirstIter { queue, yet_to_do }
}
-struct DepthFirstIter<'a, T: HasDependencies + Debug> {
+struct DepthFirstIter<'a, T: HasFieldsAndBases + Debug> {
queue: VecDeque<&'a T>,
yet_to_do: HashSet<&'a QualifiedName>,
}
-impl<'a, T: HasDependencies + Debug> Iterator for DepthFirstIter<'a, T> {
+impl<'a, T: HasFieldsAndBases + Debug> Iterator for DepthFirstIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let first_candidate = self.queue.get(0).map(|api| api.name());
while let Some(candidate) = self.queue.pop_front() {
- if !candidate.deps().any(|d| self.yet_to_do.contains(&d)) {
+ if !candidate
+ .field_and_base_deps()
+ .any(|d| self.yet_to_do.contains(&d))
+ {
self.yet_to_do.remove(candidate.name());
return Some(candidate);
}
@@ -46,7 +59,11 @@
"Failed to find a candidate; there must be a circular dependency. Queue is {}",
self.queue
.iter()
- .map(|item| format!("{}: {}", item.name(), item.deps().join(",")))
+ .map(|item| format!(
+ "{}: {}",
+ item.name(),
+ item.field_and_base_deps().join(",")
+ ))
.join("\n")
);
}
@@ -59,17 +76,17 @@
mod test {
use crate::types::QualifiedName;
- use super::{depth_first, HasDependencies};
+ use super::{fields_and_bases_first, HasFieldsAndBases};
#[derive(Debug)]
struct Thing(QualifiedName, Vec<QualifiedName>);
- impl HasDependencies for Thing {
+ impl HasFieldsAndBases for Thing {
fn name(&self) -> &QualifiedName {
&self.0
}
- fn deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
+ fn field_and_base_deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
Box::new(self.1.iter())
}
}
@@ -89,7 +106,7 @@
vec![QualifiedName::new_from_cpp_name("a")],
);
let api_list = vec![a, b, c];
- let mut it = depth_first(api_list.iter());
+ let mut it = fields_and_bases_first(api_list.iter());
assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("a"));
assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("c"));
assert_eq!(it.next().unwrap().0, QualifiedName::new_from_cpp_name("b"));
diff --git a/third_party/autocxx/engine/src/conversion/analysis/fun/bridge_name_tracker.rs b/third_party/autocxx/engine/src/conversion/analysis/fun/bridge_name_tracker.rs
index 7e81c59..c98beaf 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/fun/bridge_name_tracker.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/fun/bridge_name_tracker.rs
@@ -104,7 +104,7 @@
*count += 1;
prefix
} else {
- let r = format!("{}_autocxx{}", prefix, count);
+ let r = format!("{prefix}_autocxx{count}");
*count += 1;
r
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/fun/function_wrapper.rs b/third_party/autocxx/engine/src/conversion/analysis/fun/function_wrapper.rs
index ab3b7d9..0495533 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/fun/function_wrapper.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/fun/function_wrapper.rs
@@ -6,12 +6,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use crate::minisyn::Ident;
use crate::{
- conversion::api::SubclassName,
+ conversion::{api::SubclassName, type_helpers::extract_pinned_mutable_reference_type},
types::{Namespace, QualifiedName},
};
use quote::ToTokens;
-use syn::{parse_quote, Ident, Type, TypeReference};
+use syn::{parse_quote, Type, TypeReference};
#[derive(Clone, Debug)]
pub(crate) enum CppConversionType {
@@ -85,9 +86,9 @@
/// variant params. That would remove the possibility of various runtime
/// panics by enforcing (for example) that conversion from a pointer always
/// has a Type::Ptr.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct TypeConversionPolicy {
- unwrapped_type: Type,
+ unwrapped_type: crate::minisyn::Type,
pub(crate) cpp_conversion: CppConversionType,
pub(crate) rust_conversion: RustConversionType,
}
@@ -103,7 +104,7 @@
rust_conversion: RustConversionType,
) -> Self {
Self {
- unwrapped_type: ty,
+ unwrapped_type: ty.into(),
cpp_conversion,
rust_conversion,
}
@@ -118,7 +119,14 @@
Type::Reference(TypeReference {
elem, mutability, ..
}) => (*elem, mutability.is_some()),
- _ => panic!("Not a ptr: {}", ty.to_token_stream()),
+ Type::Path(ref tp) => {
+ if let Some(unwrapped_type) = extract_pinned_mutable_reference_type(tp) {
+ (unwrapped_type.clone(), true)
+ } else {
+ panic!("Path was not a mutable reference: {}", ty.to_token_stream())
+ }
+ }
+ _ => panic!("Not a reference: {}", ty.to_token_stream()),
};
TypeConversionPolicy {
unwrapped_type: if is_mut {
@@ -133,7 +141,7 @@
pub(crate) fn new_to_unique_ptr(ty: Type) -> Self {
TypeConversionPolicy {
- unwrapped_type: ty,
+ unwrapped_type: ty.into(),
cpp_conversion: CppConversionType::FromValueToUniquePtr,
rust_conversion: RustConversionType::None,
}
@@ -141,7 +149,7 @@
pub(crate) fn new_for_placement_return(ty: Type) -> Self {
TypeConversionPolicy {
- unwrapped_type: ty,
+ unwrapped_type: ty.into(),
cpp_conversion: CppConversionType::FromReturnValueToPlacementPtr,
// Rust conversion is marked as none here, since this policy
// will be applied to the return value, and the Rust-side
@@ -157,7 +165,7 @@
pub(crate) fn unconverted_rust_type(&self) -> Type {
match self.cpp_conversion {
CppConversionType::FromValueToUniquePtr => self.make_unique_ptr_type(),
- _ => self.unwrapped_type.clone(),
+ _ => self.unwrapped_type.clone().into(),
}
}
@@ -170,7 +178,7 @@
*mut #innerty
}
}
- _ => self.unwrapped_type.clone(),
+ _ => self.unwrapped_type.clone().into(),
}
}
@@ -222,7 +230,7 @@
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum CppFunctionBody {
FunctionCall(Namespace, Ident),
StaticMethodCall(Namespace, Ident, Ident),
@@ -234,7 +242,7 @@
FreeUninitialized(QualifiedName),
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum CppFunctionKind {
Function,
Method,
@@ -243,10 +251,10 @@
SynthesizedConstructor,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct CppFunction {
pub(crate) payload: CppFunctionBody,
- pub(crate) wrapper_function_name: Ident,
+ pub(crate) wrapper_function_name: crate::minisyn::Ident,
pub(crate) original_cpp_name: String,
pub(crate) return_conversion: Option<TypeConversionPolicy>,
pub(crate) argument_conversion: Vec<TypeConversionPolicy>,
diff --git a/third_party/autocxx/engine/src/conversion/analysis/fun/implicit_constructors.rs b/third_party/autocxx/engine/src/conversion/analysis/fun/implicit_constructors.rs
index 469ed89..a1ebf27 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/fun/implicit_constructors.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/fun/implicit_constructors.rs
@@ -11,13 +11,16 @@
use syn::{Type, TypeArray};
+use crate::conversion::api::DeletedOrDefaulted;
use crate::{
conversion::{
- analysis::{depth_first::depth_first, pod::PodAnalysis, type_converter::TypeKind},
+ analysis::{
+ depth_first::fields_and_bases_first, pod::PodAnalysis, type_converter::TypeKind,
+ },
api::{Api, ApiName, CppVisibility, FuncToConvert, SpecialMemberKind},
apivec::ApiVec,
convert_error::ConvertErrorWithContext,
- ConvertError,
+ ConvertErrorFromCpp,
},
known_types::{known_types, KnownTypeConstructorDetails},
types::QualifiedName,
@@ -177,6 +180,13 @@
apis: &ApiVec<FnPrePhase1>,
) -> HashMap<QualifiedName, ItemsFound> {
let (explicits, unknown_types) = find_explicit_items(apis);
+ let enums: HashSet<QualifiedName> = apis
+ .iter()
+ .filter_map(|api| match api {
+ Api::Enum { name, .. } => Some(name.name.clone()),
+ _ => None,
+ })
+ .collect();
// These contain all the classes we've seen so far with the relevant properties on their
// constructors of each kind. We iterate via [`depth_first`], so analyzing later classes
@@ -189,7 +199,7 @@
// These analyses include all bases and members of each class.
let mut all_items_found: HashMap<QualifiedName, ItemsFound> = HashMap::new();
- for api in depth_first(apis.iter()) {
+ for api in fields_and_bases_first(apis.iter()) {
if let Api::Struct {
name,
analysis:
@@ -211,7 +221,17 @@
})
};
let get_items_found = |qn: &QualifiedName| -> Option<ItemsFound> {
- if let Some(constructor_details) = known_types().get_constructor_details(qn) {
+ if enums.contains(qn) {
+ Some(ItemsFound {
+ default_constructor: SpecialMemberFound::NotPresent,
+ destructor: SpecialMemberFound::Implicit,
+ const_copy_constructor: SpecialMemberFound::Implicit,
+ non_const_copy_constructor: SpecialMemberFound::NotPresent,
+ move_constructor: SpecialMemberFound::Implicit,
+ name: Some(name.clone()),
+ })
+ } else if let Some(constructor_details) = known_types().get_constructor_details(qn)
+ {
Some(known_type_items_found(constructor_details))
} else {
all_items_found.get(qn).cloned()
@@ -539,8 +559,7 @@
all_items_found
.insert(name.name.clone(), items_found)
.is_none(),
- "Duplicate struct: {:?}",
- name
+ "Duplicate struct: {name:?}"
);
}
}
@@ -556,7 +575,7 @@
.entry(ExplicitType { ty, kind })
{
Entry::Vacant(entry) => {
- entry.insert(if fun.is_deleted {
+ entry.insert(if matches!(fun.is_deleted, DeletedOrDefaulted::Deleted) {
ExplicitFound::Deleted
} else {
ExplicitFound::UserDefined(fun.cpp_vis)
@@ -575,7 +594,8 @@
kind: FnKind::Method { impl_for, .. },
param_details,
ignore_reason:
- Ok(()) | Err(ConvertErrorWithContext(ConvertError::AssignmentOperator, _)),
+ Ok(())
+ | Err(ConvertErrorWithContext(ConvertErrorFromCpp::AssignmentOperator, _)),
..
},
fun,
diff --git a/third_party/autocxx/engine/src/conversion/analysis/fun/mod.rs b/third_party/autocxx/engine/src/conversion/analysis/fun/mod.rs
index 7194746..415e40a 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/fun/mod.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/fun/mod.rs
@@ -19,9 +19,9 @@
type_converter::{self, add_analysis, TypeConversionContext, TypeConverter},
},
api::{
- ApiName, CastMutability, CppVisibility, FuncToConvert, NullPhase, Provenance,
- References, SpecialMemberKind, SubclassName, TraitImplSignature, TraitSynthesis,
- UnsafetyNeeded, Virtualness,
+ ApiName, CastMutability, CppVisibility, DeletedOrDefaulted, FuncToConvert, NullPhase,
+ Provenance, References, SpecialMemberKind, SubclassName, TraitImplSignature,
+ TraitSynthesis, UnsafetyNeeded, Virtualness,
},
apivec::ApiVec,
convert_error::ErrorContext,
@@ -29,6 +29,7 @@
error_reporter::{convert_apis, report_any_error},
},
known_types::known_types,
+ minisyn::minisynize_punctuated,
types::validate_ident_ok_for_rust,
};
use indexmap::map::IndexMap as HashMap;
@@ -40,14 +41,14 @@
use proc_macro2::Span;
use quote::quote;
use syn::{
- parse_quote, punctuated::Punctuated, token::Comma, FnArg, Ident, Pat, ReturnType, Type,
- TypePath, TypePtr, TypeReference, Visibility,
+ parse_quote, punctuated::Punctuated, token::Comma, FnArg, Ident, Pat, PatType, ReturnType,
+ Type, TypePath, TypePtr, TypeReference, Visibility,
};
use crate::{
conversion::{
api::{AnalysisPhase, Api, TypeKind},
- ConvertError,
+ ConvertErrorFromCpp,
},
types::{make_ident, validate_ident_ok_for_cxx, Namespace, QualifiedName},
};
@@ -64,13 +65,14 @@
};
use super::{
+ depth_first::HasFieldsAndBases,
doc_label::make_doc_attrs,
pod::{PodAnalysis, PodPhase},
tdef::TypedefAnalysis,
type_converter::{Annotated, PointerTreatment},
};
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub(crate) enum ReceiverMutability {
Const,
Mutable,
@@ -85,7 +87,7 @@
PureVirtual(ReceiverMutability),
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum TraitMethodKind {
CopyConstructor,
MoveConstructor,
@@ -95,11 +97,11 @@
Dealloc,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct TraitMethodDetails {
pub(crate) trt: TraitImplSignature,
pub(crate) avoid_self: bool,
- pub(crate) method_name: Ident,
+ pub(crate) method_name: crate::minisyn::Ident,
/// For traits, where we're trying to implement a specific existing
/// interface, we may need to reorder the parameters to fit that
/// interface.
@@ -109,7 +111,7 @@
pub(crate) trait_call_is_unsafe: bool,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum FnKind {
Function,
Method {
@@ -129,31 +131,31 @@
/// Strategy for ensuring that the final, callable, Rust name
/// is what the user originally expected.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum RustRenameStrategy {
/// cxx::bridge name matches user expectations
None,
/// Even the #[rust_name] attribute would cause conflicts, and we need
/// to use a 'use XYZ as ABC'
- RenameInOutputMod(Ident),
+ RenameInOutputMod(crate::minisyn::Ident),
/// This function requires us to generate a Rust function to do
/// parameter conversion.
RenameUsingWrapperFunction,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct FnAnalysis {
/// Each entry in the cxx::bridge needs to have a unique name, even if
/// (from the perspective of Rust and C++) things are in different
/// namespaces/mods.
- pub(crate) cxxbridge_name: Ident,
+ pub(crate) cxxbridge_name: crate::minisyn::Ident,
/// ... so record also the name under which we wish to expose it in Rust.
pub(crate) rust_name: String,
pub(crate) rust_rename_strategy: RustRenameStrategy,
pub(crate) params: Punctuated<FnArg, Comma>,
pub(crate) kind: FnKind,
- pub(crate) ret_type: ReturnType,
+ pub(crate) ret_type: crate::minisyn::ReturnType,
pub(crate) param_details: Vec<ArgumentAnalysis>,
pub(crate) ret_conversion: Option<TypeConversionPolicy>,
pub(crate) requires_unsafe: UnsafetyNeeded,
@@ -172,12 +174,13 @@
pub(crate) rust_wrapper_needed: bool,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct ArgumentAnalysis {
pub(crate) conversion: TypeConversionPolicy,
- pub(crate) name: Pat,
+ pub(crate) name: crate::minisyn::Pat,
pub(crate) self_type: Option<(QualifiedName, ReceiverMutability)>,
pub(crate) has_lifetime: bool,
+ pub(crate) is_mutable_reference: bool,
pub(crate) deps: HashSet<QualifiedName>,
pub(crate) requires_unsafe: UnsafetyNeeded,
pub(crate) is_placement_return_destination: bool,
@@ -187,6 +190,7 @@
rt: ReturnType,
conversion: Option<TypeConversionPolicy>,
was_reference: bool,
+ was_mutable_reference: bool,
deps: HashSet<QualifiedName>,
placement_param_needed: Option<(FnArg, ArgumentAnalysis)>,
}
@@ -197,12 +201,14 @@
rt: parse_quote! {},
conversion: None,
was_reference: false,
+ was_mutable_reference: false,
deps: Default::default(),
placement_param_needed: None,
}
}
}
+#[derive(std::fmt::Debug)]
pub(crate) struct PodAndConstructorAnalysis {
pub(crate) pod: PodAnalysis,
pub(crate) constructors: PublicConstructors,
@@ -210,6 +216,7 @@
/// An analysis phase where we've analyzed each function, but
/// haven't yet determined which constructors/etc. belong to each type.
+#[derive(std::fmt::Debug)]
pub(crate) struct FnPrePhase1;
impl AnalysisPhase for FnPrePhase1 {
@@ -220,6 +227,7 @@
/// An analysis phase where we've analyzed each function, and identified
/// what implicit constructors/destructors are present in each type.
+#[derive(std::fmt::Debug)]
pub(crate) struct FnPrePhase2;
impl AnalysisPhase for FnPrePhase2 {
@@ -228,6 +236,7 @@
type FunAnalysis = FnAnalysis;
}
+#[derive(Debug)]
pub(crate) struct PodAndDepAnalysis {
pub(crate) pod: PodAnalysis,
pub(crate) constructor_and_allocator_deps: Vec<QualifiedName>,
@@ -236,6 +245,7 @@
/// Analysis phase after we've finished analyzing functions and determined
/// which constructors etc. belong to them.
+#[derive(std::fmt::Debug)]
pub(crate) struct FnPhase;
/// Indicates which kinds of public constructors are known to exist for a type.
@@ -283,6 +293,7 @@
generic_types: HashSet<QualifiedName>,
types_in_anonymous_namespace: HashSet<QualifiedName>,
existing_superclass_trait_api_names: HashSet<QualifiedName>,
+ force_wrapper_generation: bool,
}
impl<'a> FnAnalyzer<'a> {
@@ -290,6 +301,7 @@
apis: ApiVec<PodPhase>,
unsafe_policy: &'a UnsafePolicy,
config: &'a IncludeCppConfig,
+ force_wrapper_generation: bool,
) -> ApiVec<FnPrePhase2> {
let mut me = Self {
unsafe_policy,
@@ -305,6 +317,7 @@
generic_types: Self::build_generic_type_set(&apis),
existing_superclass_trait_api_names: HashSet::new(),
types_in_anonymous_namespace: Self::build_types_in_anonymous_namespace(&apis),
+ force_wrapper_generation,
};
let mut results = ApiVec::new();
convert_apis(
@@ -427,7 +440,7 @@
ty: Box<Type>,
ns: &Namespace,
pointer_treatment: PointerTreatment,
- ) -> Result<Annotated<Box<Type>>, ConvertError> {
+ ) -> Result<Annotated<Box<Type>>, ConvertErrorFromCpp> {
let ctx = TypeConversionContext::OuterType { pointer_treatment };
let mut annotated = self.type_converter.convert_boxed_type(ty, ns, &ctx)?;
self.extra_apis.append(&mut annotated.extra_apis);
@@ -513,7 +526,7 @@
**fun,
FuncToConvert {
special_member: Some(SpecialMemberKind::Destructor),
- is_deleted: false,
+ is_deleted: DeletedOrDefaulted::Neither | DeletedOrDefaulted::Defaulted,
cpp_vis: CppVisibility::Public,
..
}
@@ -741,6 +754,10 @@
sophistication,
false,
)
+ .map_err(|err| ConvertErrorFromCpp::Argument {
+ arg: describe_arg(i),
+ err: Box::new(err),
+ })
})
.partition(Result::is_ok);
let (mut params, mut param_details): (Punctuated<_, Comma>, Vec<_>) =
@@ -775,7 +792,7 @@
if initial_rust_name.ends_with('_') {
initial_rust_name // case 2
} else if validate_ident_ok_for_rust(cpp_name).is_err() {
- format!("{}_", cpp_name) // case 5
+ format!("{cpp_name}_") // case 5
} else {
cpp_name.to_string() // cases 3, 4, 6
}
@@ -829,7 +846,7 @@
let is_move =
matches!(fun.special_member, Some(SpecialMemberKind::MoveConstructor));
if let Some(constructor_suffix) = rust_name.strip_prefix(nested_type_ident) {
- rust_name = format!("new{}", constructor_suffix);
+ rust_name = format!("new{constructor_suffix}");
}
rust_name = predetermined_rust_name
.unwrap_or_else(|| self.get_overload_name(ns, type_ident, rust_name));
@@ -868,7 +885,7 @@
impl_for: self_ty,
details: Box::new(TraitMethodDetails {
trt: TraitImplSignature {
- ty,
+ ty: ty.into(),
trait_signature: parse_quote! {
autocxx::moveit::new:: #trait_id
},
@@ -904,7 +921,7 @@
impl_for: self_ty,
details: Box::new(TraitMethodDetails {
trt: TraitImplSignature {
- ty,
+ ty: ty.into(),
trait_signature: parse_quote! {
Drop
},
@@ -934,7 +951,7 @@
// fn make_unique(...args) -> UniquePtr<Type>
// If there are multiple constructors, bindgen generates
// new, new1, new2 etc. and we'll keep those suffixes.
- rust_name = format!("new{}", constructor_suffix);
+ rust_name = format!("new{constructor_suffix}");
MethodKind::Constructor {
is_default: matches!(
fun.special_member,
@@ -1033,10 +1050,10 @@
..
} => {
if param_details.len() < 2 {
- set_ignore_reason(ConvertError::ConstructorWithOnlyOneParam);
+ set_ignore_reason(ConvertErrorFromCpp::ConstructorWithOnlyOneParam);
}
if param_details.len() > 2 {
- set_ignore_reason(ConvertError::ConstructorWithMultipleParams);
+ set_ignore_reason(ConvertErrorFromCpp::ConstructorWithMultipleParams);
}
self.reanalyze_parameter(
0,
@@ -1058,10 +1075,10 @@
..
} => {
if param_details.len() < 2 {
- set_ignore_reason(ConvertError::ConstructorWithOnlyOneParam);
+ set_ignore_reason(ConvertErrorFromCpp::ConstructorWithOnlyOneParam);
}
if param_details.len() > 2 {
- set_ignore_reason(ConvertError::ConstructorWithMultipleParams);
+ set_ignore_reason(ConvertErrorFromCpp::ConstructorWithMultipleParams);
}
self.reanalyze_parameter(
0,
@@ -1099,14 +1116,14 @@
// or note whether the type is abstract.
let externally_callable = match fun.cpp_vis {
CppVisibility::Private => {
- set_ignore_reason(ConvertError::PrivateMethod);
+ set_ignore_reason(ConvertErrorFromCpp::PrivateMethod);
false
}
CppVisibility::Protected => false,
CppVisibility::Public => true,
};
if fun.variadic {
- set_ignore_reason(ConvertError::Variadic);
+ set_ignore_reason(ConvertErrorFromCpp::Variadic);
}
if let Some(problem) = bads.into_iter().next() {
match problem {
@@ -1116,7 +1133,7 @@
} else if fun.unused_template_param {
// This indicates that bindgen essentially flaked out because templates
// were too complex.
- set_ignore_reason(ConvertError::UnusedTemplateParam)
+ set_ignore_reason(ConvertErrorFromCpp::UnusedTemplateParam)
} else if matches!(
fun.special_member,
Some(SpecialMemberKind::AssignmentOperator)
@@ -1124,11 +1141,11 @@
// Be careful with the order of this if-else tree. Anything above here means we won't
// treat it as an assignment operator, but anything below we still consider when
// deciding which other C++ special member functions are implicitly defined.
- set_ignore_reason(ConvertError::AssignmentOperator)
+ set_ignore_reason(ConvertErrorFromCpp::AssignmentOperator)
} else if fun.references.rvalue_ref_return {
- set_ignore_reason(ConvertError::RValueReturn)
- } else if fun.is_deleted {
- set_ignore_reason(ConvertError::Deleted)
+ set_ignore_reason(ConvertErrorFromCpp::RValueReturn)
+ } else if matches!(fun.is_deleted, DeletedOrDefaulted::Deleted) {
+ set_ignore_reason(ConvertErrorFromCpp::Deleted)
} else {
match kind {
FnKind::Method {
@@ -1140,21 +1157,21 @@
| MethodKind::Virtual(..),
..
} if !known_types().is_cxx_acceptable_receiver(impl_for) => {
- set_ignore_reason(ConvertError::UnsupportedReceiver);
+ set_ignore_reason(ConvertErrorFromCpp::UnsupportedReceiver);
}
FnKind::Method { ref impl_for, .. } if !self.is_on_allowlist(impl_for) => {
// Bindgen will output methods for types which have been encountered
// virally as arguments on other allowlisted types. But we don't want
// to generate methods unless the user has specifically asked us to.
// It may, for instance, be a private type.
- set_ignore_reason(ConvertError::MethodOfNonAllowlistedType);
+ set_ignore_reason(ConvertErrorFromCpp::MethodOfNonAllowlistedType);
}
FnKind::Method { ref impl_for, .. } | FnKind::TraitMethod { ref impl_for, .. } => {
if self.is_generic_type(impl_for) {
- set_ignore_reason(ConvertError::MethodOfGenericType);
+ set_ignore_reason(ConvertErrorFromCpp::MethodOfGenericType);
}
if self.types_in_anonymous_namespace.contains(impl_for) {
- set_ignore_reason(ConvertError::MethodInAnonymousNamespace);
+ set_ignore_reason(ConvertErrorFromCpp::MethodInAnonymousNamespace);
}
}
_ => {}
@@ -1199,12 +1216,46 @@
let requires_unsafe = self.should_be_unsafe(¶m_details, &kind);
- let num_input_references = param_details.iter().filter(|pd| pd.has_lifetime).count();
- if num_input_references != 1 && return_analysis.was_reference {
+ // The following sections reject some types of function because of the arrangement
+ // of Rust references. We could lift these restrictions when/if we switch to using
+ // CppRef to represent C++ references.
+ if return_analysis.was_reference {
// cxx only allows functions to return a reference if they take exactly
- // one reference as a parameter. Let's see...
- set_ignore_reason(ConvertError::NotOneInputReference(rust_name.clone()));
+ // one reference as a parameter. Let's see.
+ let num_input_references = param_details.iter().filter(|pd| pd.has_lifetime).count();
+ if num_input_references == 0 {
+ set_ignore_reason(ConvertErrorFromCpp::NoInputReference(rust_name.clone()));
+ }
+ if num_input_references > 1 {
+ set_ignore_reason(ConvertErrorFromCpp::MultipleInputReferences(
+ rust_name.clone(),
+ ));
+ }
}
+ if return_analysis.was_mutable_reference {
+ // This one's a bit more subtle. We can't have:
+ // fn foo(thing: &Thing) -> &mut OtherThing
+ // because Rust doesn't allow it.
+ // We could probably allow:
+ // fn foo(thing: &mut Thing, thing2: &mut OtherThing) -> &mut OtherThing
+ // but probably cxx doesn't allow that. (I haven't checked). Even if it did,
+ // there's ambiguity here so won't allow it.
+ let num_input_mutable_references = param_details
+ .iter()
+ .filter(|pd| pd.has_lifetime && pd.is_mutable_reference)
+ .count();
+ if num_input_mutable_references == 0 {
+ set_ignore_reason(ConvertErrorFromCpp::NoMutableInputReference(
+ rust_name.clone(),
+ ));
+ }
+ if num_input_mutable_references > 1 {
+ set_ignore_reason(ConvertErrorFromCpp::MultipleMutableInputReferences(
+ rust_name.clone(),
+ ));
+ }
+ }
+
let mut ret_type = return_analysis.rt;
let ret_type_conversion = return_analysis.conversion;
@@ -1248,19 +1299,23 @@
_ if ret_type_conversion_needed => true,
_ if cpp_name_incompatible_with_cxx => true,
_ if fun.synthetic_cpp.is_some() => true,
+ _ if self.force_wrapper_generation => true,
_ => false,
};
let cpp_wrapper = if wrapper_function_needed {
// Generate a new layer of C++ code to wrap/unwrap parameters
// and return values into/out of std::unique_ptrs.
- let cpp_construction_ident = make_ident(&effective_cpp_name);
+ let cpp_construction_ident = make_ident(effective_cpp_name);
let joiner = if cxxbridge_name.to_string().ends_with('_') {
""
} else {
"_"
};
- cxxbridge_name = make_ident(&format!("{}{}autocxx_wrapper", cxxbridge_name, joiner));
+ cxxbridge_name = make_ident(
+ self.config
+ .uniquify_name_per_mod(&format!("{cxxbridge_name}{joiner}autocxx_wrapper")),
+ );
let (payload, cpp_function_kind) = match fun.synthetic_cpp.as_ref().cloned() {
Some((payload, cpp_function_kind)) => (payload, cpp_function_kind),
None => match kind {
@@ -1321,10 +1376,10 @@
params.clear();
for pd in ¶m_details {
let type_name = pd.conversion.converted_rust_type();
- let arg_name = if pd.self_type.is_some() {
+ let arg_name: syn::Pat = if pd.self_type.is_some() {
parse_quote!(autocxx_gen_this)
} else {
- pd.name.clone()
+ pd.name.clone().into()
};
params.push(parse_quote!(
#arg_name: #type_name
@@ -1358,12 +1413,15 @@
_ if any_param_needs_rust_conversion || return_needs_rust_conversion => true,
FnKind::TraitMethod { .. } => true,
FnKind::Method { .. } => cxxbridge_name != rust_name,
+ _ if self.force_wrapper_generation => true,
_ => false,
};
// Naming, part two.
// Work out our final naming strategy.
- validate_ident_ok_for_cxx(&cxxbridge_name.to_string()).unwrap_or_else(set_ignore_reason);
+ validate_ident_ok_for_cxx(&cxxbridge_name.to_string())
+ .map_err(ConvertErrorFromCpp::InvalidIdent)
+ .unwrap_or_else(set_ignore_reason);
let rust_name_ident = make_ident(&rust_name);
let rust_rename_strategy = match kind {
_ if rust_wrapper_needed => RustRenameStrategy::RenameUsingWrapperFunction,
@@ -1380,10 +1438,10 @@
params,
ret_conversion: ret_type_conversion,
kind,
- ret_type,
+ ret_type: ret_type.into(),
param_details,
requires_unsafe,
- vis,
+ vis: vis.into(),
cpp_wrapper,
deps,
ignore_reason,
@@ -1422,7 +1480,7 @@
sophistication: TypeConversionSophistication,
construct_into_self: bool,
is_move_constructor: bool,
- ) -> Result<(), ConvertError> {
+ ) -> Result<(), ConvertErrorFromCpp> {
self.convert_fn_arg(
fun.inputs.iter().nth(param_idx).unwrap(),
ns,
@@ -1484,7 +1542,7 @@
AsRef < #to_type >
},
parse_quote! {
- &'a mut ::std::pin::Pin < &'a mut #from_type_path >
+ &'a mut ::core::pin::Pin < &'a mut #from_type_path >
},
"as_ref",
),
@@ -1493,7 +1551,7 @@
autocxx::PinMut < #to_type >
},
parse_quote! {
- ::std::pin::Pin < &'a mut #from_type_path >
+ ::core::pin::Pin < &'a mut #from_type_path >
},
"pin_mut",
),
@@ -1505,7 +1563,7 @@
impl_for: from_type.clone(),
details: Box::new(TraitMethodDetails {
trt: TraitImplSignature {
- ty,
+ ty: ty.into(),
trait_signature,
unsafety: None,
},
@@ -1549,7 +1607,7 @@
impl_for: ty.clone(),
details: Box::new(TraitMethodDetails {
trt: TraitImplSignature {
- ty: Type::Path(typ),
+ ty: Type::Path(typ).into(),
trait_signature: parse_quote! { autocxx::moveit::MakeCppStorage },
unsafety: Some(parse_quote! { unsafe }),
},
@@ -1590,7 +1648,7 @@
force_rust_conversion: Option<RustConversionType>,
sophistication: TypeConversionSophistication,
construct_into_self: bool,
- ) -> Result<(FnArg, ArgumentAnalysis), ConvertError> {
+ ) -> Result<(FnArg, ArgumentAnalysis), ConvertErrorFromCpp> {
Ok(match arg {
FnArg::Typed(pt) => {
let mut pt = pt.clone();
@@ -1627,12 +1685,11 @@
};
Ok((this_type, receiver_mutability))
}
- _ => Err(ConvertError::UnexpectedThisType(QualifiedName::new(
- ns,
- make_ident(fn_name),
- ))),
+ _ => Err(ConvertErrorFromCpp::UnexpectedThisType(
+ QualifiedName::new(ns, make_ident(fn_name)),
+ )),
},
- _ => Err(ConvertError::UnexpectedThisType(QualifiedName::new(
+ _ => Err(ConvertErrorFromCpp::UnexpectedThisType(QualifiedName::new(
ns,
make_ident(fn_name),
))),
@@ -1646,8 +1703,9 @@
syn::Pat::Ident(pp)
}
syn::Pat::Ident(pp) => {
- validate_ident_ok_for_cxx(&pp.ident.to_string())?;
- pointer_treatment = references.param_treatment(&pp.ident);
+ validate_ident_ok_for_cxx(&pp.ident.to_string())
+ .map_err(ConvertErrorFromCpp::InvalidIdent)?;
+ pointer_treatment = references.param_treatment(&pp.ident.clone().into());
syn::Pat::Ident(pp)
}
_ => old_pat,
@@ -1684,13 +1742,17 @@
FnArg::Typed(pt),
ArgumentAnalysis {
self_type,
- name: new_pat,
+ name: new_pat.into(),
conversion,
has_lifetime: matches!(
annotated_type.kind,
type_converter::TypeKind::Reference
| type_converter::TypeKind::MutableReference
),
+ is_mutable_reference: matches!(
+ annotated_type.kind,
+ type_converter::TypeKind::MutableReference
+ ),
deps: annotated_type.types_encountered,
requires_unsafe,
is_placement_return_destination,
@@ -1859,7 +1921,7 @@
ns: &Namespace,
references: &References,
sophistication: TypeConversionSophistication,
- ) -> Result<ReturnTypeAnalysis, ConvertError> {
+ ) -> Result<ReturnTypeAnalysis, ConvertErrorFromCpp> {
Ok(match rt {
ReturnType::Default => ReturnTypeAnalysis::default(),
ReturnType::Type(rarrow, boxed_type) => {
@@ -1902,9 +1964,9 @@
conversion: Some(TypeConversionPolicy::new_for_placement_return(
ty.clone(),
)),
- was_reference: false,
deps: annotated_type.types_encountered,
placement_param_needed: Some((fnarg, analysis)),
+ ..Default::default()
}
} else {
// There are some types which we can't currently represent within a moveit::new::New.
@@ -1917,14 +1979,18 @@
ReturnTypeAnalysis {
rt: ReturnType::Type(*rarrow, boxed_type),
conversion,
- was_reference: false,
deps: annotated_type.types_encountered,
- placement_param_needed: None,
+ ..Default::default()
}
}
}
_ => {
- let was_reference = references.ref_return;
+ let was_mutable_reference = matches!(
+ annotated_type.kind,
+ type_converter::TypeKind::MutableReference
+ );
+ let was_reference = was_mutable_reference
+ || matches!(annotated_type.kind, type_converter::TypeKind::Reference);
let conversion = Some(
if was_reference
&& matches!(
@@ -1941,6 +2007,7 @@
rt: ReturnType::Type(*rarrow, boxed_type),
conversion,
was_reference,
+ was_mutable_reference,
deps: annotated_type.types_encountered,
placement_param_needed: None,
}
@@ -2091,9 +2158,12 @@
Box::new(FuncToConvert {
self_ty: Some(self_ty.clone()),
ident,
- doc_attrs: make_doc_attrs(format!("Synthesized {}.", special_member)),
- inputs,
- output: ReturnType::Default,
+ doc_attrs: make_doc_attrs(format!("Synthesized {special_member}."))
+ .into_iter()
+ .map(Into::into)
+ .collect(),
+ inputs: minisynize_punctuated(inputs),
+ output: ReturnType::Default.into(),
vis: parse_quote! { pub },
virtualness: Virtualness::None,
cpp_vis: CppVisibility::Public,
@@ -2102,7 +2172,7 @@
references,
original_name: None,
synthesized_this_type: None,
- is_deleted: false,
+ is_deleted: DeletedOrDefaulted::Neither,
add_to_trait: None,
synthetic_cpp: None,
provenance: Provenance::SynthesizedOther,
@@ -2192,7 +2262,7 @@
)
}
- pub(crate) fn cxxbridge_name(&self) -> Option<Ident> {
+ pub(crate) fn cxxbridge_name(&self) -> Option<crate::minisyn::Ident> {
match self {
Api::Function { ref analysis, .. } => Some(analysis.cxxbridge_name.clone()),
Api::StringConstructor { .. }
@@ -2224,3 +2294,60 @@
_ => panic!("did not find angle bracketed args"),
}
}
+
+impl HasFieldsAndBases for Api<FnPrePhase1> {
+ fn name(&self) -> &QualifiedName {
+ self.name()
+ }
+
+ fn field_and_base_deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
+ match self {
+ Api::Struct {
+ analysis:
+ PodAnalysis {
+ field_definition_deps,
+ bases,
+ ..
+ },
+ ..
+ } => Box::new(field_definition_deps.iter().chain(bases.iter())),
+ _ => Box::new(std::iter::empty()),
+ }
+ }
+}
+
+impl HasFieldsAndBases for Api<FnPrePhase2> {
+ fn name(&self) -> &QualifiedName {
+ self.name()
+ }
+
+ fn field_and_base_deps(&self) -> Box<dyn Iterator<Item = &QualifiedName> + '_> {
+ match self {
+ Api::Struct {
+ analysis:
+ PodAndConstructorAnalysis {
+ pod:
+ PodAnalysis {
+ field_definition_deps,
+ bases,
+ ..
+ },
+ ..
+ },
+ ..
+ } => Box::new(field_definition_deps.iter().chain(bases.iter())),
+ _ => Box::new(std::iter::empty()),
+ }
+ }
+}
+
+/// Stringify a function argument for diagnostics
+fn describe_arg(arg: &FnArg) -> String {
+ match arg {
+ FnArg::Receiver(_) => "the function receiver (this/self paramter)".into(),
+ FnArg::Typed(PatType { pat, .. }) => match pat.as_ref() {
+ Pat::Ident(pti) => pti.ident.to_string(),
+ _ => "another argument we don't know how to describe".into(),
+ },
+ }
+}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/fun/overload_tracker.rs b/third_party/autocxx/engine/src/conversion/analysis/fun/overload_tracker.rs
index 6fc532c..20165f5 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/fun/overload_tracker.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/fun/overload_tracker.rs
@@ -49,7 +49,7 @@
if this_offset == 0 {
cpp_method_name
} else {
- format!("{}{}", cpp_method_name, this_offset)
+ format!("{cpp_method_name}{this_offset}")
}
}
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/fun/subclass.rs b/third_party/autocxx/engine/src/conversion/analysis/fun/subclass.rs
index 6383d2c..8698539 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/fun/subclass.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/fun/subclass.rs
@@ -6,6 +6,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::ops::DerefMut;
+
use indexmap::map::IndexMap as HashMap;
use syn::{parse_quote, FnArg, PatType, Type, TypePtr};
@@ -17,6 +19,7 @@
SubclassName, SuperclassMethod, UnsafetyNeeded, Virtualness,
};
use crate::conversion::apivec::ApiVec;
+use crate::minisyn::minisynize_punctuated;
use crate::{
conversion::{
analysis::fun::function_wrapper::{
@@ -85,6 +88,7 @@
.param_details
.iter()
.map(|pd| pd.name.clone())
+ .map(Into::into)
.collect();
let requires_unsafe = if matches!(unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) {
UnsafetyNeeded::Always
@@ -95,10 +99,10 @@
name,
details: SuperclassMethod {
name: make_ident(&analysis.rust_name),
- params: analysis.params.clone(),
+ params: minisynize_punctuated(analysis.params.clone()),
ret_type: analysis.ret_type.clone(),
param_names,
- receiver_mutability: receiver_mutability.clone(),
+ receiver_mutability: *receiver_mutability,
requires_unsafe,
is_pure_virtual,
receiver,
@@ -122,10 +126,10 @@
sub.0.name.get_final_item(),
name.name.get_final_item()
));
- let params = std::iter::once(parse_quote! {
+ let params = std::iter::once(crate::minisyn::FnArg(parse_quote! {
me: & #holder_name
- })
- .chain(analysis.params.iter().skip(1).cloned())
+ }))
+ .chain(analysis.params.iter().skip(1).cloned().map(Into::into))
.collect();
let kind = if matches!(receiver_mutability, ReceiverMutability::Mutable) {
CppFunctionKind::Method
@@ -161,7 +165,7 @@
qualification: Some(cpp),
},
superclass: superclass.clone(),
- receiver_mutability: receiver_mutability.clone(),
+ receiver_mutability: *receiver_mutability,
dependencies,
requires_unsafe,
is_pure_virtual: matches!(
@@ -213,7 +217,9 @@
let subclass_constructor_name =
make_ident(format!("{}_{}", cpp.get_final_item(), cpp.get_final_item()));
let mut existing_params = fun.inputs.clone();
- if let Some(FnArg::Typed(PatType { ty, .. })) = existing_params.first_mut() {
+ if let Some(FnArg::Typed(PatType { ty, .. })) =
+ existing_params.first_mut().map(DerefMut::deref_mut)
+ {
if let Type::Ptr(TypePtr { elem, .. }) = &mut **ty {
*elem = Box::new(Type::Path(sub.cpp().to_type_path()));
} else {
@@ -229,7 +235,7 @@
};
let inputs = self_param
.into_iter()
- .chain(std::iter::once(boxed_holder_param))
+ .chain(std::iter::once(boxed_holder_param.into()))
.chain(existing_params)
.collect();
let maybe_wrap = Box::new(FuncToConvert {
diff --git a/third_party/autocxx/engine/src/conversion/analysis/name_check.rs b/third_party/autocxx/engine/src/conversion/analysis/name_check.rs
index 7547c7c..38b8db4 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/name_check.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/name_check.rs
@@ -8,14 +8,14 @@
use indexmap::map::IndexMap as HashMap;
-use syn::Ident;
+use crate::minisyn::Ident;
use crate::{
conversion::{
api::{Api, SubclassName},
apivec::ApiVec,
error_reporter::convert_item_apis,
- ConvertError,
+ ConvertErrorFromCpp,
},
types::{validate_ident_ok_for_cxx, QualifiedName},
};
@@ -92,7 +92,7 @@
if let Some(name) = my_name {
let symbols_for_this_name = names_found.entry(name).or_default();
if symbols_for_this_name.len() > 1usize {
- Err(ConvertError::DuplicateCxxBridgeName(
+ Err(ConvertErrorFromCpp::DuplicateCxxBridgeName(
symbols_for_this_name.clone(),
))
} else {
@@ -107,9 +107,9 @@
fn validate_all_segments_ok_for_cxx(
items: impl Iterator<Item = String>,
-) -> Result<(), ConvertError> {
+) -> Result<(), ConvertErrorFromCpp> {
for seg in items {
- validate_ident_ok_for_cxx(&seg)?;
+ validate_ident_ok_for_cxx(&seg).map_err(ConvertErrorFromCpp::InvalidIdent)?;
}
Ok(())
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/pod/byvalue_checker.rs b/third_party/autocxx/engine/src/conversion/analysis/pod/byvalue_checker.rs
index de72eec..6e2e9b9 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/pod/byvalue_checker.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/pod/byvalue_checker.rs
@@ -7,7 +7,7 @@
// except according to those terms.
use crate::conversion::apivec::ApiVec;
-use crate::{conversion::ConvertError, known_types::known_types};
+use crate::{conversion::ConvertErrorFromCpp, known_types::known_types};
use crate::{
conversion::{
analysis::tdef::TypedefPhase,
@@ -48,6 +48,9 @@
/// std::string contains a self-referential pointer.
/// It is possible that this is duplicative of the information stored
/// elsewhere in the `Api` list and could possibly be removed or simplified.
+/// In general this is one of the oldest parts of autocxx and
+/// the code here could quite possibly be simplified by reusing code
+/// elsewhere.
pub struct ByValueChecker {
// Mapping from type name to whether it is safe to be POD
results: HashMap<QualifiedName, StructDetails>,
@@ -60,7 +63,7 @@
let safety = if by_value_safe {
PodState::IsPod
} else {
- PodState::UnsafeToBePod(format!("type {} is not safe for POD", tn))
+ PodState::UnsafeToBePod(format!("type {tn} is not safe for POD"))
};
results.insert(tn.clone(), StructDetails::new(safety));
}
@@ -72,7 +75,7 @@
pub(crate) fn new_from_apis(
apis: &ApiVec<TypedefPhase>,
config: &IncludeCppConfig,
- ) -> Result<ByValueChecker, ConvertError> {
+ ) -> Result<ByValueChecker, ConvertErrorFromCpp> {
let mut byvalue_checker = ByValueChecker::new();
for blocklisted in config.get_blocklist() {
let tn = QualifiedName::new_from_cpp_name(blocklisted);
@@ -81,6 +84,11 @@
.results
.insert(tn, StructDetails::new(safety));
}
+ // As we do this analysis, we need to be aware that structs
+ // may depend on other types. Ideally we'd use the depth first iterator
+ // but that's awkward given that our ApiPhase does not yet have a fixed
+ // list of field/base types. Instead, we'll iterate first over non-struct
+ // types and then over structs.
for api in apis.iter() {
match api {
Api::Typedef { analysis, .. } => {
@@ -94,7 +102,7 @@
_ => None,
},
TypedefKind::Use(_, ref ty) => match **ty {
- Type::Path(ref typ) => {
+ crate::minisyn::Type(Type::Path(ref typ)) => {
let target_tn = QualifiedName::from_type_path(typ);
known_types().consider_substitution(&target_tn)
}
@@ -113,15 +121,7 @@
None => byvalue_checker.ingest_nonpod_type(name.clone()),
}
}
- Api::Struct { details, .. } => {
- byvalue_checker.ingest_struct(&details.item, api.name().get_namespace())
- }
- Api::Enum { .. } => {
- byvalue_checker
- .results
- .insert(api.name().clone(), StructDetails::new(PodState::IsPod));
- }
- Api::ExternCppType { pod: true, .. } => {
+ Api::Enum { .. } | Api::ExternCppType { pod: true, .. } => {
byvalue_checker
.results
.insert(api.name().clone(), StructDetails::new(PodState::IsPod));
@@ -129,6 +129,11 @@
_ => {}
}
}
+ for api in apis.iter() {
+ if let Api::Struct { details, .. } = api {
+ byvalue_checker.ingest_struct(&details.item, api.name().get_namespace())
+ }
+ }
let pod_requests = config
.get_pod_requests()
.iter()
@@ -136,27 +141,32 @@
.collect();
byvalue_checker
.satisfy_requests(pod_requests)
- .map_err(ConvertError::UnsafePodType)?;
+ .map_err(ConvertErrorFromCpp::UnsafePodType)?;
Ok(byvalue_checker)
}
fn ingest_struct(&mut self, def: &ItemStruct, ns: &Namespace) {
// For this struct, work out whether it _could_ be safe as a POD.
- let tyname = QualifiedName::new(ns, def.ident.clone());
+ let tyname = QualifiedName::new(ns, def.ident.clone().into());
let mut field_safety_problem = PodState::SafeToBePod;
let fieldlist = Self::get_field_types(def);
for ty_id in &fieldlist {
match self.results.get(ty_id) {
+ None if ty_id.get_final_item() == "__BindgenUnionField" => {
+ field_safety_problem = PodState::UnsafeToBePod(format!(
+ "Type {tyname} could not be POD because it is a union"
+ ));
+ break;
+ }
None => {
field_safety_problem = PodState::UnsafeToBePod(format!(
- "Type {} could not be POD because its dependent type {} isn't known",
- tyname, ty_id
+ "Type {tyname} could not be POD because its dependent type {ty_id} isn't known"
));
break;
}
Some(deets) => {
if let PodState::UnsafeToBePod(reason) = &deets.state {
- let new_reason = format!("Type {} could not be POD because its dependent type {} isn't safe to be POD. Because: {}", tyname, ty_id, reason);
+ let new_reason = format!("Type {tyname} could not be POD because its dependent type {ty_id} isn't safe to be POD. Because: {reason}");
field_safety_problem = PodState::UnsafeToBePod(new_reason);
break;
}
@@ -164,10 +174,8 @@
}
}
if Self::has_vtable(def) {
- let reason = format!(
- "Type {} could not be POD because it has virtual functions.",
- tyname
- );
+ let reason =
+ format!("Type {tyname} could not be POD because it has virtual functions.");
field_safety_problem = PodState::UnsafeToBePod(reason);
}
let mut my_details = StructDetails::new(field_safety_problem);
@@ -176,7 +184,7 @@
}
fn ingest_nonpod_type(&mut self, tyname: QualifiedName) {
- let new_reason = format!("Type {} is a typedef to a complex type", tyname);
+ let new_reason = format!("Type {tyname} is a typedef to a complex type");
self.results.insert(
tyname,
StructDetails::new(PodState::UnsafeToBePod(new_reason)),
@@ -191,8 +199,7 @@
match deets {
None => {
return Err(format!(
- "Unable to make {} POD because we never saw a struct definition",
- ty_id
+ "Unable to make {ty_id} POD because we never saw a struct definition"
))
}
Some(deets) => match &deets.state {
@@ -236,6 +243,10 @@
)
}
+ /// This is a miniature version of the analysis in `super::get_struct_field_types`.
+ /// It would be nice to unify them. However, this version only cares about spotting
+ /// fields which may be non-POD, so can largely concern itself with just `Type::Path`
+ /// fields.
fn get_field_types(def: &ItemStruct) -> Vec<QualifiedName> {
let mut results = Vec::new();
for f in &def.fields {
@@ -261,10 +272,11 @@
#[cfg(test)]
mod tests {
use super::ByValueChecker;
+ use crate::minisyn::ItemStruct;
use crate::types::{Namespace, QualifiedName};
- use syn::{parse_quote, Ident, ItemStruct};
+ use syn::parse_quote;
- fn ty_from_ident(id: &Ident) -> QualifiedName {
+ fn ty_from_ident(id: &syn::Ident) -> QualifiedName {
QualifiedName::new_from_cpp_name(&id.to_string())
}
diff --git a/third_party/autocxx/engine/src/conversion/analysis/pod/mod.rs b/third_party/autocxx/engine/src/conversion/analysis/pod/mod.rs
index eeb5051..2fafc95 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/pod/mod.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/pod/mod.rs
@@ -13,7 +13,7 @@
use autocxx_parser::IncludeCppConfig;
use byvalue_checker::ByValueChecker;
-use syn::{ItemEnum, ItemStruct, Type, Visibility};
+use syn::{ItemStruct, Type, Visibility};
use crate::{
conversion::{
@@ -23,18 +23,21 @@
convert_error::{ConvertErrorWithContext, ErrorContext},
error_reporter::convert_apis,
parse::BindgenSemanticAttributes,
- ConvertError,
+ ConvertErrorFromCpp,
},
types::{Namespace, QualifiedName},
};
use super::tdef::{TypedefAnalysis, TypedefPhase};
+#[derive(std::fmt::Debug)]
+
pub(crate) struct FieldInfo {
pub(crate) ty: Type,
pub(crate) type_kind: type_converter::TypeKind,
}
+#[derive(std::fmt::Debug)]
pub(crate) struct PodAnalysis {
pub(crate) kind: TypeKind,
pub(crate) bases: HashSet<QualifiedName>,
@@ -43,12 +46,18 @@
/// because otherwise we don't know whether they're
/// abstract or not.
pub(crate) castable_bases: HashSet<QualifiedName>,
+ /// All field types. e.g. for std::unique_ptr<A>, this would include
+ /// both std::unique_ptr and A
pub(crate) field_deps: HashSet<QualifiedName>,
+ /// Types within fields where we need a definition, e.g. for
+ /// std::unique_ptr<A> it would just be std::unique_ptr.
+ pub(crate) field_definition_deps: HashSet<QualifiedName>,
pub(crate) field_info: Vec<FieldInfo>,
pub(crate) is_generic: bool,
pub(crate) in_anonymous_namespace: bool,
}
+#[derive(std::fmt::Debug)]
pub(crate) struct PodPhase;
impl AnalysisPhase for PodPhase {
@@ -65,7 +74,7 @@
pub(crate) fn analyze_pod_apis(
apis: ApiVec<TypedefPhase>,
config: &IncludeCppConfig,
-) -> Result<ApiVec<PodPhase>, ConvertError> {
+) -> Result<ApiVec<PodPhase>, ConvertErrorFromCpp> {
// This next line will return an error if any of the 'generate_pod'
// directives from the user can't be met because, for instance,
// a type contains a std::string or some other type which can't be
@@ -118,7 +127,7 @@
fn analyze_enum(
name: ApiName,
- mut item: ItemEnum,
+ mut item: crate::minisyn::ItemEnum,
) -> Result<Box<dyn Iterator<Item = Api<PodPhase>>>, ConvertErrorWithContext> {
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut item.attrs);
metadata.check_for_fatal_attrs(&name.name.get_final_ident())?;
@@ -138,12 +147,14 @@
metadata.check_for_fatal_attrs(&id)?;
let bases = get_bases(&details.item);
let mut field_deps = HashSet::new();
+ let mut field_definition_deps = HashSet::new();
let mut field_info = Vec::new();
let field_conversion_errors = get_struct_field_types(
type_converter,
name.name.get_namespace(),
&details.item,
&mut field_deps,
+ &mut field_definition_deps,
&mut field_info,
extra_apis,
);
@@ -152,7 +163,7 @@
// Let's not allow anything to be POD if it's got rvalue reference fields.
if details.has_rvalue_reference_fields {
return Err(ConvertErrorWithContext(
- ConvertError::RValueReferenceField,
+ ConvertErrorFromCpp::RValueReferenceField,
Some(ErrorContext::new_for_item(id)),
));
}
@@ -186,6 +197,7 @@
bases: bases.into_keys().collect(),
castable_bases,
field_deps,
+ field_definition_deps,
field_info,
is_generic,
in_anonymous_namespace,
@@ -198,9 +210,10 @@
ns: &Namespace,
s: &ItemStruct,
field_deps: &mut HashSet<QualifiedName>,
+ field_definition_deps: &mut HashSet<QualifiedName>,
field_info: &mut Vec<FieldInfo>,
extra_apis: &mut ApiVec<NullPhase>,
-) -> Vec<ConvertError> {
+) -> Vec<ConvertErrorFromCpp> {
let mut convert_errors = Vec::new();
let struct_type_params = s
.generics
@@ -225,6 +238,14 @@
.unwrap_or(false)
{
field_deps.extend(r.types_encountered);
+ if let Type::Path(typ) = &r.ty {
+ // Later analyses need to know about the field
+ // types where we need full definitions, as opposed
+ // to just declarations. That means just the outermost
+ // type path.
+ // TODO: consider arrays.
+ field_definition_deps.insert(QualifiedName::from_type_path(typ));
+ }
field_info.push(FieldInfo {
ty: r.ty,
type_kind: r.kind,
diff --git a/third_party/autocxx/engine/src/conversion/analysis/remove_ignored.rs b/third_party/autocxx/engine/src/conversion/analysis/remove_ignored.rs
index bd11b13..4ed4b9f 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/remove_ignored.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/remove_ignored.rs
@@ -11,7 +11,7 @@
use super::deps::HasDependencies;
use super::fun::{FnAnalysis, FnKind, FnPhase};
use crate::conversion::apivec::ApiVec;
-use crate::conversion::{convert_error::ErrorContext, ConvertError};
+use crate::conversion::{convert_error::ErrorContext, ConvertErrorFromCpp};
use crate::{conversion::api::Api, known_types};
/// Remove any APIs which depend on other items which have been ignored.
@@ -44,7 +44,10 @@
if !ignored_dependents.is_empty() {
iterate_again = true;
ignored_items.insert(api.name().clone());
- create_ignore_item(api, ConvertError::IgnoredDependent(ignored_dependents))
+ create_ignore_item(
+ api,
+ ConvertErrorFromCpp::IgnoredDependent(ignored_dependents),
+ )
} else {
let mut missing_deps = api.deps().filter(|dep| {
!valid_types.contains(*dep) && !known_types().is_known_type(dep)
@@ -52,7 +55,10 @@
let first = missing_deps.next();
std::mem::drop(missing_deps);
if let Some(missing_dep) = first.cloned() {
- create_ignore_item(api, ConvertError::UnknownDependentType(missing_dep))
+ create_ignore_item(
+ api,
+ ConvertErrorFromCpp::UnknownDependentType(missing_dep),
+ )
} else {
api
}
@@ -63,7 +69,7 @@
apis
}
-fn create_ignore_item(api: Api<FnPhase>, err: ConvertError) -> Api<FnPhase> {
+fn create_ignore_item(api: Api<FnPhase>, err: ConvertErrorFromCpp) -> Api<FnPhase> {
let id = api.name().get_final_ident();
log::info!("Marking as ignored: {} because {}", id.to_string(), err);
Api::IgnoredItem {
diff --git a/third_party/autocxx/engine/src/conversion/analysis/replace_hopeless_typedef_targets.rs b/third_party/autocxx/engine/src/conversion/analysis/replace_hopeless_typedef_targets.rs
index 8d5d033..918fb8f 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/replace_hopeless_typedef_targets.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/replace_hopeless_typedef_targets.rs
@@ -15,7 +15,7 @@
api::Api,
apivec::ApiVec,
convert_error::{ConvertErrorWithContext, ErrorContext},
- ConvertError,
+ ConvertErrorFromCpp,
},
types::QualifiedName,
};
@@ -71,7 +71,7 @@
{
Api::IgnoredItem {
name: api.name_info().clone(),
- err: ConvertError::NestedOpaqueTypedef,
+ err: ConvertErrorFromCpp::NestedOpaqueTypedef,
ctx: Some(ErrorContext::new_for_item(name_id)),
}
} else {
diff --git a/third_party/autocxx/engine/src/conversion/analysis/tdef.rs b/third_party/autocxx/engine/src/conversion/analysis/tdef.rs
index 5a635f8..1c414e8 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/tdef.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/tdef.rs
@@ -19,11 +19,12 @@
convert_error::{ConvertErrorWithContext, ErrorContext},
error_reporter::convert_apis,
parse::BindgenSemanticAttributes,
- ConvertError,
+ ConvertErrorFromCpp,
},
types::QualifiedName,
};
+#[derive(std::fmt::Debug)]
pub(crate) struct TypedefAnalysis {
pub(crate) kind: TypedefKind,
pub(crate) deps: HashSet<QualifiedName>,
@@ -31,6 +32,7 @@
/// Analysis phase where typedef analysis has been performed but no other
/// analyses just yet.
+#[derive(std::fmt::Debug)]
pub(crate) struct TypedefPhase;
impl AnalysisPhase for TypedefPhase {
@@ -57,7 +59,7 @@
Ok(Box::new(std::iter::once(match item {
TypedefKind::Type(ity) => get_replacement_typedef(
name,
- ity,
+ ity.into(),
old_tyname,
&mut type_converter,
&mut extra_apis,
@@ -87,7 +89,7 @@
) -> Result<Api<TypedefPhase>, ConvertErrorWithContext> {
if !ity.generics.params.is_empty() {
return Err(ConvertErrorWithContext(
- ConvertError::TypedefTakesGenericParameters,
+ ConvertErrorFromCpp::TypedefTakesGenericParameters,
Some(ErrorContext::new_for_item(name.name.get_final_ident())),
));
}
@@ -108,7 +110,7 @@
ty: syn::Type::Path(ref typ),
..
}) if QualifiedName::from_type_path(typ) == name.name => Err(ConvertErrorWithContext(
- ConvertError::InfinitelyRecursiveTypedef(name.name.clone()),
+ ConvertErrorFromCpp::InfinitelyRecursiveTypedef(name.name.clone()),
Some(ErrorContext::new_for_item(name.name.get_final_ident())),
)),
Ok(mut final_type) => {
@@ -116,10 +118,10 @@
extra_apis.append(&mut final_type.extra_apis);
Ok(Api::Typedef {
name,
- item: TypedefKind::Type(ity),
+ item: TypedefKind::Type(ity.into()),
old_tyname,
analysis: TypedefAnalysis {
- kind: TypedefKind::Type(converted_type),
+ kind: TypedefKind::Type(converted_type.into()),
deps: final_type.types_encountered,
},
})
diff --git a/third_party/autocxx/engine/src/conversion/analysis/type_converter.rs b/third_party/autocxx/engine/src/conversion/analysis/type_converter.rs
index 7e2d2bd..63f7ae9 100644
--- a/third_party/autocxx/engine/src/conversion/analysis/type_converter.rs
+++ b/third_party/autocxx/engine/src/conversion/analysis/type_converter.rs
@@ -10,8 +10,8 @@
conversion::{
api::{AnalysisPhase, Api, ApiName, NullPhase, TypedefKind, UnanalyzedApi},
apivec::ApiVec,
- codegen_cpp::type_to_cpp::type_to_cpp,
- ConvertError,
+ codegen_cpp::type_to_cpp::CppNameMap,
+ ConvertErrorFromCpp,
},
known_types::{known_types, CxxGenericType},
types::{make_ident, Namespace, QualifiedName},
@@ -34,7 +34,7 @@
pub(crate) enum TypeKind {
Regular,
Pointer,
- SubclassHolder(Ident),
+ SubclassHolder(crate::minisyn::Ident),
Reference,
RValueReference,
MutableReference,
@@ -109,14 +109,9 @@
matches!(self, Self::WithinReference)
}
fn allowed_generic_type(&self, ident: &Ident) -> bool {
- match self {
+ !matches!(self,
Self::WithinStructField { struct_type_params }
- if struct_type_params.contains(ident) =>
- {
- false
- }
- _ => true,
- }
+ if struct_type_params.contains(ident))
}
}
@@ -135,6 +130,7 @@
forward_declarations: HashSet<QualifiedName>,
ignored_types: HashSet<QualifiedName>,
config: &'a IncludeCppConfig,
+ original_name_map: CppNameMap,
}
impl<'a> TypeConverter<'a> {
@@ -149,6 +145,7 @@
forward_declarations: Self::find_incomplete_types(apis),
ignored_types: Self::find_ignored_types(apis),
config,
+ original_name_map: CppNameMap::new_from_apis(apis),
}
}
@@ -157,7 +154,7 @@
ty: Box<Type>,
ns: &Namespace,
ctx: &TypeConversionContext,
- ) -> Result<Annotated<Box<Type>>, ConvertError> {
+ ) -> Result<Annotated<Box<Type>>, ConvertErrorFromCpp> {
Ok(self.convert_type(*ty, ns, ctx)?.map(Box::new))
}
@@ -166,7 +163,7 @@
ty: Type,
ns: &Namespace,
ctx: &TypeConversionContext,
- ) -> Result<Annotated<Type>, ConvertError> {
+ ) -> Result<Annotated<Type>, ConvertErrorFromCpp> {
let result = match ty {
Type::Path(p) => {
let newp = self.convert_type_path(p, ns, ctx)?;
@@ -175,7 +172,7 @@
if !ctx.allow_instantiation_of_forward_declaration()
&& self.forward_declarations.contains(&qn)
{
- return Err(ConvertError::TypeContainingForwardDeclaration(qn));
+ return Err(ConvertErrorFromCpp::TypeContainingForwardDeclaration(qn));
}
// Special handling because rust_Str (as emitted by bindgen)
// doesn't simply get renamed to a different type _identifier_.
@@ -220,7 +217,11 @@
)
}
Type::Ptr(ptr) => self.convert_ptr(ptr, ns, ctx.pointer_treatment())?,
- _ => return Err(ConvertError::UnknownType(ty.to_token_stream().to_string())),
+ _ => {
+ return Err(ConvertErrorFromCpp::UnknownType(
+ ty.to_token_stream().to_string(),
+ ))
+ }
};
Ok(result)
}
@@ -230,7 +231,7 @@
mut typ: TypePath,
ns: &Namespace,
ctx: &TypeConversionContext,
- ) -> Result<Annotated<Type>, ConvertError> {
+ ) -> Result<Annotated<Type>, ConvertErrorFromCpp> {
// First, qualify any unqualified paths.
if typ.path.segments.iter().next().unwrap().ident != "root" {
let ty = QualifiedName::from_type_path(&typ);
@@ -241,7 +242,7 @@
if !known_types().is_known_type(&ty) {
let num_segments = typ.path.segments.len();
if num_segments > 1 {
- return Err(ConvertError::UnsupportedBuiltInType(ty));
+ return Err(ConvertErrorFromCpp::UnsupportedBuiltInType(ty));
}
if !self.types_found.contains(&ty) {
typ.path.segments = std::iter::once(&"root".to_string())
@@ -257,9 +258,11 @@
}
let original_tn = QualifiedName::from_type_path(&typ);
- original_tn.validate_ok_for_cxx()?;
+ original_tn
+ .validate_ok_for_cxx()
+ .map_err(ConvertErrorFromCpp::InvalidIdent)?;
if self.config.is_on_blocklist(&original_tn.to_cpp_name()) {
- return Err(ConvertError::Blocked(original_tn));
+ return Err(ConvertErrorFromCpp::Blocked(original_tn));
}
let mut deps = HashSet::new();
@@ -331,7 +334,9 @@
)?;
deps.extend(innerty.types_encountered.drain(..));
} else {
- return Err(ConvertError::TemplatedTypeContainingNonPathArg(tn.clone()));
+ return Err(ConvertErrorFromCpp::TemplatedTypeContainingNonPathArg(
+ tn.clone(),
+ ));
}
} else {
// Oh poop. It's a generic type which cxx won't be able to handle.
@@ -347,7 +352,9 @@
if typ.path.segments.len() == 1
&& !ctx.allowed_generic_type(&seg.ident)
{
- return Err(ConvertError::ReferringToGenericTypeParam);
+ return Err(
+ ConvertErrorFromCpp::ReferringToGenericTypeParam,
+ );
}
}
}
@@ -361,7 +368,7 @@
// this a bit.
let qn = QualifiedName::from_type_path(&typ); // ignores generic params
if self.ignored_types.contains(&qn) {
- return Err(ConvertError::ConcreteVersionOfIgnoredTemplate);
+ return Err(ConvertErrorFromCpp::ConcreteVersionOfIgnoredTemplate);
}
let (new_tn, api) = self.get_templated_typename(&Type::Path(typ))?;
extra_apis.extend(api.into_iter());
@@ -385,7 +392,7 @@
pun: Punctuated<GenericArgument, P>,
ns: &Namespace,
ctx: &TypeConversionContext,
- ) -> Result<Annotated<Punctuated<GenericArgument, P>>, ConvertError>
+ ) -> Result<Annotated<Punctuated<GenericArgument, P>>, ConvertErrorFromCpp>
where
P: Default,
{
@@ -411,7 +418,10 @@
))
}
- fn resolve_typedef<'b>(&'b self, tn: &QualifiedName) -> Result<Option<&'b Type>, ConvertError> {
+ fn resolve_typedef<'b>(
+ &'b self,
+ tn: &QualifiedName,
+ ) -> Result<Option<&'b Type>, ConvertErrorFromCpp> {
let mut encountered = HashSet::new();
let mut tn = tn.clone();
let mut previous_typ = None;
@@ -422,7 +432,7 @@
previous_typ = r;
let new_tn = QualifiedName::from_type_path(typ);
if encountered.contains(&new_tn) {
- return Err(ConvertError::InfinitelyRecursiveTypedef(tn.clone()));
+ return Err(ConvertErrorFromCpp::InfinitelyRecursiveTypedef(tn.clone()));
}
if typ
.path
@@ -430,7 +440,7 @@
.iter()
.any(|seg| seg.ident.to_string().starts_with("_bindgen_mod"))
{
- return Err(ConvertError::TypedefToTypeInAnonymousNamespace);
+ return Err(ConvertErrorFromCpp::TypedefToTypeInAnonymousNamespace);
}
encountered.insert(new_tn.clone());
tn = new_tn;
@@ -446,10 +456,10 @@
mut ptr: TypePtr,
ns: &Namespace,
pointer_treatment: PointerTreatment,
- ) -> Result<Annotated<Type>, ConvertError> {
+ ) -> Result<Annotated<Type>, ConvertErrorFromCpp> {
match pointer_treatment {
PointerTreatment::Pointer => {
- crate::known_types::ensure_pointee_is_valid(&ptr)?;
+ Self::ensure_pointee_is_valid(&ptr)?;
let innerty =
self.convert_boxed_type(ptr.elem, ns, &TypeConversionContext::WithinReference)?;
ptr.elem = innerty.ty;
@@ -470,7 +480,7 @@
// be a plain value. We should detect and abort.
let mut outer = elem.map(|elem| match mutability {
Some(_) => Type::Path(parse_quote! {
- ::std::pin::Pin < & #mutability #elem >
+ ::core::pin::Pin < & #mutability #elem >
}),
None => Type::Reference(parse_quote! {
& #elem
@@ -484,7 +494,7 @@
Ok(outer)
}
PointerTreatment::RValueReference => {
- crate::known_types::ensure_pointee_is_valid(&ptr)?;
+ Self::ensure_pointee_is_valid(&ptr)?;
let innerty =
self.convert_boxed_type(ptr.elem, ns, &TypeConversionContext::WithinReference)?;
ptr.elem = innerty.ty;
@@ -498,15 +508,26 @@
}
}
+ fn ensure_pointee_is_valid(ptr: &TypePtr) -> Result<(), ConvertErrorFromCpp> {
+ match *ptr.elem {
+ Type::Path(..) => Ok(()),
+ Type::Array(..) => Err(ConvertErrorFromCpp::InvalidArrayPointee),
+ Type::Ptr(..) => Err(ConvertErrorFromCpp::InvalidPointerPointee),
+ _ => Err(ConvertErrorFromCpp::InvalidPointee(
+ ptr.elem.to_token_stream().to_string(),
+ )),
+ }
+ }
+
fn get_templated_typename(
&mut self,
rs_definition: &Type,
- ) -> Result<(QualifiedName, Option<UnanalyzedApi>), ConvertError> {
+ ) -> Result<(QualifiedName, Option<UnanalyzedApi>), ConvertErrorFromCpp> {
let count = self.concrete_templates.len();
// We just use this as a hash key, essentially.
// TODO: Once we've completed the TypeConverter refactoring (see #220),
// pass in an actual original_name_map here.
- let cpp_definition = type_to_cpp(rs_definition, &HashMap::new())?;
+ let cpp_definition = self.original_name_map.type_to_cpp(rs_definition)?;
let e = self.concrete_templates.get(&cpp_definition);
match e {
Some(tn) => Ok((tn.clone(), None)),
@@ -530,12 +551,12 @@
.find(|s| s == &synthetic_ident)
{
None => synthetic_ident,
- Some(_) => format!("AutocxxConcrete{}", count),
+ Some(_) => format!("AutocxxConcrete{count}"),
};
let api = UnanalyzedApi::ConcreteType {
- name: ApiName::new_in_root_namespace(make_ident(&synthetic_ident)),
+ name: ApiName::new_in_root_namespace(make_ident(synthetic_ident)),
cpp_definition: cpp_definition.clone(),
- rs_definition: Some(Box::new(rs_definition.clone())),
+ rs_definition: Some(Box::new(rs_definition.clone().into())),
};
self.concrete_templates
.insert(cpp_definition, api.name().clone());
@@ -550,21 +571,25 @@
desc: &QualifiedName,
generic_behavior: CxxGenericType,
forward_declarations_ok: bool,
- ) -> Result<TypeKind, ConvertError> {
+ ) -> Result<TypeKind, ConvertErrorFromCpp> {
for inner in path_args {
match inner {
GenericArgument::Type(Type::Path(typ)) => {
let inner_qn = QualifiedName::from_type_path(typ);
if !forward_declarations_ok && self.forward_declarations.contains(&inner_qn) {
- return Err(ConvertError::TypeContainingForwardDeclaration(inner_qn));
+ return Err(ConvertErrorFromCpp::TypeContainingForwardDeclaration(
+ inner_qn,
+ ));
}
match generic_behavior {
CxxGenericType::Rust => {
if !inner_qn.get_namespace().is_empty() {
- return Err(ConvertError::RustTypeWithAPath(inner_qn));
+ return Err(ConvertErrorFromCpp::RustTypeWithAPath(inner_qn));
}
if !self.config.is_rust_type(&inner_qn.get_final_ident()) {
- return Err(ConvertError::BoxContainingNonRustType(inner_qn));
+ return Err(ConvertErrorFromCpp::BoxContainingNonRustType(
+ inner_qn,
+ ));
}
if self
.config
@@ -577,12 +602,12 @@
}
CxxGenericType::CppPtr => {
if !known_types().permissible_within_unique_ptr(&inner_qn) {
- return Err(ConvertError::InvalidTypeForCppPtr(inner_qn));
+ return Err(ConvertErrorFromCpp::InvalidTypeForCppPtr(inner_qn));
}
}
CxxGenericType::CppVector => {
if !known_types().permissible_within_vector(&inner_qn) {
- return Err(ConvertError::InvalidTypeForCppVector(inner_qn));
+ return Err(ConvertErrorFromCpp::InvalidTypeForCppVector(inner_qn));
}
if matches!(
typ.path.segments.last().map(|ps| &ps.arguments),
@@ -591,14 +616,14 @@
| PathArguments::AngleBracketed(_)
)
) {
- return Err(ConvertError::GenericsWithinVector);
+ return Err(ConvertErrorFromCpp::GenericsWithinVector);
}
}
_ => {}
}
}
_ => {
- return Err(ConvertError::TemplatedTypeContainingNonPathArg(
+ return Err(ConvertErrorFromCpp::TemplatedTypeContainingNonPathArg(
desc.clone(),
))
}
diff --git a/third_party/autocxx/engine/src/conversion/api.rs b/third_party/autocxx/engine/src/conversion/api.rs
index c5a1b60..d5da41c 100644
--- a/third_party/autocxx/engine/src/conversion/api.rs
+++ b/third_party/autocxx/engine/src/conversion/api.rs
@@ -9,17 +9,20 @@
use indexmap::set::IndexSet as HashSet;
use std::fmt::Display;
-use crate::types::{make_ident, Namespace, QualifiedName};
-use autocxx_parser::{ExternCppType, RustFun, RustPath};
-use itertools::Itertools;
-use quote::ToTokens;
use syn::{
parse::Parse,
punctuated::Punctuated,
token::{Comma, Unsafe},
+};
+
+use crate::minisyn::{
Attribute, FnArg, Ident, ItemConst, ItemEnum, ItemStruct, ItemType, ItemUse, LitBool, LitInt,
Pat, ReturnType, Type, Visibility,
};
+use crate::types::{make_ident, Namespace, QualifiedName};
+use autocxx_parser::{ExternCppType, RustFun, RustPath};
+use itertools::Itertools;
+use quote::ToTokens;
use super::{
analysis::{
@@ -30,10 +33,10 @@
PointerTreatment,
},
convert_error::{ConvertErrorWithContext, ErrorContext},
- ConvertError,
+ ConvertErrorFromCpp,
};
-#[derive(Copy, Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub(crate) enum TypeKind {
Pod, // trivial. Can be moved and copied in Rust.
NonPod, // has destructor or non-trivial move constructors. Can only hold by UniquePtr
@@ -53,6 +56,7 @@
}
/// Details about a C++ struct.
+#[derive(Debug)]
pub(crate) struct StructDetails {
pub(crate) item: ItemStruct,
pub(crate) layout: Option<Layout>,
@@ -60,7 +64,7 @@
}
/// Layout of a type, equivalent to the same type in ir/layout.rs in bindgen
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct Layout {
/// The size (in bytes) of this layout.
pub(crate) size: usize,
@@ -85,14 +89,14 @@
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum Virtualness {
None,
Virtual,
PureVirtual,
}
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
pub(crate) enum CastMutability {
ConstToConst,
MutToConst,
@@ -101,7 +105,7 @@
/// Indicates that this function (which is synthetic) should
/// be a trait implementation rather than a method or free function.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum TraitSynthesis {
Cast {
to_type: QualifiedName,
@@ -113,7 +117,7 @@
/// Details of a subclass constructor.
/// TODO: zap this; replace with an extra API.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct SubclassConstructorDetails {
pub(crate) subclass: SubclassName,
pub(crate) is_trivial: bool,
@@ -124,7 +128,7 @@
/// Contributions to traits representing C++ superclasses that
/// we may implement as Rust subclasses.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct SuperclassMethod {
pub(crate) name: Ident,
pub(crate) receiver: QualifiedName,
@@ -139,7 +143,7 @@
/// Information about references (as opposed to pointers) to be found
/// within the function signature. This is derived from bindgen annotations
/// which is why it's not within `FuncToConvert::inputs`
-#[derive(Default, Clone)]
+#[derive(Default, Clone, Debug)]
pub(crate) struct References {
pub(crate) rvalue_ref_params: HashSet<Ident>,
pub(crate) ref_params: HashSet<Ident>,
@@ -175,7 +179,7 @@
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct TraitImplSignature {
pub(crate) ty: Type,
pub(crate) trait_signature: Type,
@@ -239,13 +243,21 @@
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum Provenance {
Bindgen,
SynthesizedOther,
SynthesizedSubclassConstructor(Box<SubclassConstructorDetails>),
}
+/// Whether a function has =delete or =default
+#[derive(Clone, Copy, Debug)]
+pub(crate) enum DeletedOrDefaulted {
+ Neither,
+ Deleted,
+ Defaulted,
+}
+
/// A C++ function for which we need to generate bindings, but haven't
/// yet analyzed in depth. This is little more than a `ForeignItemFn`
/// broken down into its constituent parts, plus some metadata from the
@@ -256,7 +268,7 @@
/// during normal bindgen parsing. If that happens, they'll create one
/// of these structures, and typically fill in some of the
/// `synthesized_*` members which are not filled in from bindgen.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) struct FuncToConvert {
pub(crate) provenance: Provenance,
pub(crate) ident: Ident,
@@ -283,18 +295,20 @@
/// If Some, this function didn't really exist in the original
/// C++ and instead we're synthesizing it.
pub(crate) synthetic_cpp: Option<(CppFunctionBody, CppFunctionKind)>,
- pub(crate) is_deleted: bool,
+ /// =delete
+ pub(crate) is_deleted: DeletedOrDefaulted,
}
/// Layers of analysis which may be applied to decorate each API.
/// See description of the purpose of this trait within `Api`.
-pub(crate) trait AnalysisPhase {
- type TypedefAnalysis;
- type StructAnalysis;
- type FunAnalysis;
+pub(crate) trait AnalysisPhase: std::fmt::Debug {
+ type TypedefAnalysis: std::fmt::Debug;
+ type StructAnalysis: std::fmt::Debug;
+ type FunAnalysis: std::fmt::Debug;
}
/// No analysis has been applied to this API.
+#[derive(std::fmt::Debug)]
pub(crate) struct NullPhase;
impl AnalysisPhase for NullPhase {
@@ -303,7 +317,7 @@
type FunAnalysis = ();
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum TypedefKind {
Use(ItemUse, Box<Type>),
Type(ItemType),
@@ -365,7 +379,7 @@
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)?;
if let Some(cpp_name) = &self.cpp_name {
- write!(f, " (cpp={})", cpp_name)?;
+ write!(f, " (cpp={cpp_name})")?;
}
Ok(())
}
@@ -418,7 +432,7 @@
}
// TODO this and the following should probably include both class name and method name
pub(crate) fn get_super_fn_name(superclass_namespace: &Namespace, id: &str) -> QualifiedName {
- let id = make_ident(format!("{}_super", id));
+ let id = make_ident(format!("{id}_super"));
QualifiedName::new(superclass_namespace, id)
}
pub(crate) fn get_methods_trait_name(superclass_name: &QualifiedName) -> QualifiedName {
@@ -434,7 +448,7 @@
}
}
-#[derive(strum_macros::Display)]
+#[derive(std::fmt::Debug)]
/// Different types of API we might encounter.
///
/// This type is parameterized over an `ApiAnalysis`. This is any additional
@@ -445,11 +459,9 @@
/// because sometimes we pass on the `bindgen` output directly in the
/// Rust codegen output.
///
-/// This derives from [strum_macros::Display] because we want to be
-/// able to debug-print the enum discriminant without worrying about
-/// the fact that their payloads may not be `Debug` or `Display`.
-/// (Specifically, allowing `syn` Types to be `Debug` requires
-/// enabling syn's `extra-traits` feature which increases compile time.)
+/// Any `syn` types represented in this `Api` type, or any of the types from
+/// which it is composed, should be wrapped in `crate::minisyn` equivalents
+/// to avoid excessively verbose `Debug` logging.
pub(crate) enum Api<T: AnalysisPhase> {
/// A forward declaration, which we mustn't store in a UniquePtr.
ForwardDeclaration {
@@ -522,7 +534,7 @@
/// dependent items.
IgnoredItem {
name: ApiName,
- err: ConvertError,
+ err: ConvertErrorFromCpp,
ctx: Option<ErrorContext>,
},
/// A Rust type which is not a C++ type.
@@ -531,7 +543,7 @@
RustFn {
name: ApiName,
details: RustFun,
- receiver: Option<QualifiedName>,
+ deps: Vec<QualifiedName>,
},
/// Some function for the extern "Rust" block.
RustSubclassFn {
@@ -559,6 +571,7 @@
},
}
+#[derive(Debug)]
pub(crate) struct RustSubclassFnDetails {
pub(crate) params: Punctuated<FnArg, Comma>,
pub(crate) ret: ReturnType,
@@ -646,12 +659,6 @@
}
}
-impl<T: AnalysisPhase> std::fmt::Debug for Api<T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?} (kind={})", self.name_info(), self)
- }
-}
-
pub(crate) type UnanalyzedApi = Api<NullPhase>;
impl<T: AnalysisPhase> Api<T> {
diff --git a/third_party/autocxx/engine/src/conversion/apivec.rs b/third_party/autocxx/engine/src/conversion/apivec.rs
index 1e440cc..24e70ed 100644
--- a/third_party/autocxx/engine/src/conversion/apivec.rs
+++ b/third_party/autocxx/engine/src/conversion/apivec.rs
@@ -15,7 +15,7 @@
use indexmap::set::IndexSet as HashSet;
use crate::{
- conversion::{api::ApiName, convert_error::ErrorContext, ConvertError},
+ conversion::{api::ApiName, convert_error::ErrorContext, ConvertErrorFromCpp},
types::QualifiedName,
};
@@ -64,7 +64,7 @@
self.retain(|api| api.name() != name);
self.push(Api::IgnoredItem {
name: ApiName::new_from_qualified_name(name.clone()),
- err: ConvertError::DuplicateItemsFoundInParsing,
+ err: ConvertErrorFromCpp::DuplicateItemsFoundInParsing,
ctx: Some(ErrorContext::new_for_item(name.get_final_ident())),
})
}
diff --git a/third_party/autocxx/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs b/third_party/autocxx/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs
index 5367626..661a5b3 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_cpp/function_wrapper_cpp.rs
@@ -11,16 +11,16 @@
use crate::conversion::{
analysis::fun::function_wrapper::{CppConversionType, TypeConversionPolicy},
api::Pointerness,
- ConvertError,
+ ConvertErrorFromCpp,
};
-use super::type_to_cpp::{type_to_cpp, CppNameMap};
+use super::type_to_cpp::CppNameMap;
impl TypeConversionPolicy {
pub(super) fn unconverted_type(
&self,
cpp_name_map: &CppNameMap,
- ) -> Result<String, ConvertError> {
+ ) -> Result<String, ConvertErrorFromCpp> {
match self.cpp_conversion {
CppConversionType::FromUniquePtrToValue => self.unique_ptr_wrapped_type(cpp_name_map),
CppConversionType::FromPtrToValue => {
@@ -30,7 +30,10 @@
}
}
- pub(super) fn converted_type(&self, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
+ pub(super) fn converted_type(
+ &self,
+ cpp_name_map: &CppNameMap,
+ ) -> Result<String, ConvertErrorFromCpp> {
match self.cpp_conversion {
CppConversionType::FromValueToUniquePtr => self.unique_ptr_wrapped_type(cpp_name_map),
CppConversionType::FromReferenceToPointer => {
@@ -46,15 +49,18 @@
Ok(format!(
"{}{}*",
const_string,
- type_to_cpp(ty, cpp_name_map)?
+ cpp_name_map.type_to_cpp(ty)?
))
}
_ => self.unwrapped_type_as_string(cpp_name_map),
}
}
- fn unwrapped_type_as_string(&self, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
- type_to_cpp(self.cxxbridge_type(), cpp_name_map)
+ fn unwrapped_type_as_string(
+ &self,
+ cpp_name_map: &CppNameMap,
+ ) -> Result<String, ConvertErrorFromCpp> {
+ cpp_name_map.type_to_cpp(self.cxxbridge_type())
}
pub(crate) fn is_a_pointer(&self) -> Pointerness {
@@ -71,7 +77,7 @@
fn unique_ptr_wrapped_type(
&self,
original_name_map: &CppNameMap,
- ) -> Result<String, ConvertError> {
+ ) -> Result<String, ConvertErrorFromCpp> {
Ok(format!(
"std::unique_ptr<{}>",
self.unwrapped_type_as_string(original_name_map)?
@@ -83,17 +89,17 @@
var_name: &str,
cpp_name_map: &CppNameMap,
is_return: bool,
- ) -> Result<Option<String>, ConvertError> {
+ ) -> Result<Option<String>, ConvertErrorFromCpp> {
// If is_return we want to avoid unnecessary std::moves because they
// make RVO less effective
Ok(match self.cpp_conversion {
CppConversionType::None | CppConversionType::FromReturnValueToPlacementPtr => {
Some(var_name.to_string())
}
- CppConversionType::FromPointerToReference { .. } => Some(format!("(*{})", var_name)),
- CppConversionType::Move => Some(format!("std::move({})", var_name)),
+ CppConversionType::FromPointerToReference { .. } => Some(format!("(*{var_name})")),
+ CppConversionType::Move => Some(format!("std::move({var_name})")),
CppConversionType::FromUniquePtrToValue | CppConversionType::FromPtrToMove => {
- Some(format!("std::move(*{})", var_name))
+ Some(format!("std::move(*{var_name})"))
}
CppConversionType::FromValueToUniquePtr => Some(format!(
"std::make_unique<{}>({})",
@@ -101,15 +107,15 @@
var_name
)),
CppConversionType::FromPtrToValue => {
- let dereference = format!("*{}", var_name);
+ let dereference = format!("*{var_name}");
Some(if is_return {
dereference
} else {
- format!("std::move({})", dereference)
+ format!("std::move({dereference})")
})
}
CppConversionType::IgnoredPlacementPtrParameter => None,
- CppConversionType::FromReferenceToPointer { .. } => Some(format!("&{}", var_name)),
+ CppConversionType::FromReferenceToPointer { .. } => Some(format!("&{var_name}")),
})
}
}
diff --git a/third_party/autocxx/engine/src/conversion/codegen_cpp/mod.rs b/third_party/autocxx/engine/src/conversion/codegen_cpp/mod.rs
index 0e6dcce..bb341a8 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_cpp/mod.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_cpp/mod.rs
@@ -20,11 +20,7 @@
use indexmap::set::IndexSet as HashSet;
use itertools::Itertools;
use std::borrow::Cow;
-use type_to_cpp::{original_name_map_from_apis, type_to_cpp, CppNameMap};
-
-use self::type_to_cpp::{
- final_ident_using_original_name_map, namespaced_name_using_original_name_map,
-};
+use type_to_cpp::CppNameMap;
use super::{
analysis::{
@@ -36,7 +32,7 @@
},
api::{Api, Provenance, SubclassName, TypeKind},
apivec::ApiVec,
- ConvertError,
+ ConvertErrorFromCpp,
};
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Hash)]
@@ -55,17 +51,17 @@
) -> String {
let blank = "".to_string();
match self {
- Self::System(name) => format!("#include <{}>", name),
+ Self::System(name) => format!("#include <{name}>"),
Self::CxxH => {
let prefix = cpp_codegen_options.path_to_cxx_h.as_ref().unwrap_or(&blank);
- format!("#include \"{}cxx.h\"", prefix)
+ format!("#include \"{prefix}cxx.h\"")
}
Self::CxxgenH => {
let prefix = cpp_codegen_options
.path_to_cxxgen_h
.as_ref()
.unwrap_or(&blank);
- format!("#include \"{}{}\"", prefix, cxxgen_header_name)
+ format!("#include \"{prefix}{cxxgen_header_name}\"")
}
Header::NewDeletePrelude => new_and_delete_prelude::NEW_AND_DELETE_PRELUDE.to_string(),
}
@@ -120,11 +116,11 @@
config: &'a IncludeCppConfig,
cpp_codegen_options: &CppCodegenOptions,
cxxgen_header_name: &str,
- ) -> Result<Option<CppFilePair>, ConvertError> {
+ ) -> Result<Option<CppFilePair>, ConvertErrorFromCpp> {
let mut gen = CppCodeGenerator {
additional_functions: Vec::new(),
inclusions,
- original_name_map: original_name_map_from_apis(apis),
+ original_name_map: CppNameMap::new_from_apis(apis),
config,
cpp_codegen_options,
cxxgen_header_name,
@@ -139,7 +135,7 @@
fn add_needs<'b>(
&mut self,
apis: impl Iterator<Item = &'a Api<FnPhase>>,
- ) -> Result<(), ConvertError> {
+ ) -> Result<(), ConvertErrorFromCpp> {
let mut constructors_by_subclass: HashMap<SubclassName, Vec<&CppFunction>> = HashMap::new();
let mut methods_by_subclass: HashMap<SubclassName, Vec<SubclassFunction>> = HashMap::new();
let mut deferred_apis = Vec::new();
@@ -172,7 +168,7 @@
} => {
let effective_cpp_definition = match rs_definition {
Some(rs_definition) => {
- Cow::Owned(type_to_cpp(rs_definition, &self.original_name_map)?)
+ Cow::Owned(self.original_name_map.type_to_cpp(rs_definition)?)
}
None => Cow::Borrowed(cpp_definition),
};
@@ -248,10 +244,8 @@
.any(|x| x.definition.is_some())
{
let definitions = self.concat_additional_items(|x| x.definition.as_ref());
- let definitions = format!(
- "#include \"{}\"\n{}\n{}",
- header_name, cpp_headers, definitions
- );
+ let definitions =
+ format!("#include \"{header_name}\"\n{cpp_headers}\n{definitions}");
log::info!("Additional C++ defs:\n{}", definitions);
Some(definitions.into_bytes())
} else {
@@ -302,7 +296,7 @@
// can result in destructors for nested types being called multiple times
// if we represent them as trivial types. So generate an extra
// assertion to make sure.
- let declaration = Some(format!("static_assert(::rust::IsRelocatable<{}>::value, \"type {} should be trivially move constructible and trivially destructible to be used with generate_pod! in autocxx\");", name, name));
+ let declaration = Some(format!("static_assert(::rust::IsRelocatable<{name}>::value, \"type {name} should be trivially move constructible and trivially destructible to be used with generate_pod! in autocxx\");"));
self.additional_functions.push(ExtraCpp {
declaration,
headers: vec![Header::CxxH],
@@ -312,7 +306,7 @@
fn generate_string_constructor(&mut self) {
let makestring_name = self.config.get_makestring_name();
- let declaration = Some(format!("inline std::unique_ptr<std::string> {}(::rust::Str str) {{ return std::make_unique<std::string>(std::string(str)); }}", makestring_name));
+ let declaration = Some(format!("inline std::unique_ptr<std::string> {makestring_name}(::rust::Str str) {{ return std::make_unique<std::string>(std::string(str)); }}"));
self.additional_functions.push(ExtraCpp {
declaration,
headers: vec![
@@ -324,7 +318,7 @@
})
}
- fn generate_cpp_function(&mut self, details: &CppFunction) -> Result<(), ConvertError> {
+ fn generate_cpp_function(&mut self, details: &CppFunction) -> Result<(), ConvertErrorFromCpp> {
self.additional_functions
.push(self.generate_cpp_function_inner(
details,
@@ -343,7 +337,7 @@
conversion_direction: ConversionDirection,
requires_rust_declarations: bool,
force_name: Option<&str>,
- ) -> Result<ExtraCpp, ConvertError> {
+ ) -> Result<ExtraCpp, ConvertErrorFromCpp> {
// Even if the original function call is in a namespace,
// we generate this wrapper in the global namespace.
// We could easily do this the other way round, and when
@@ -373,7 +367,7 @@
// may be able to remove this.
"autocxx_gen_this".to_string()
} else {
- format!("arg{}", counter)
+ format!("arg{counter}")
}
};
// If this returns a non-POD value, we may instead wish to emplace
@@ -425,16 +419,13 @@
CppFunctionKind::ConstMethod => " const",
_ => "",
};
- let declaration = format!("{} {}({}){}", ret_type, name, args, constness);
+ let declaration = format!("{ret_type} {name}({args}){constness}");
let qualification = if let Some(qualification) = &details.qualification {
format!("{}::", qualification.to_cpp_name())
} else {
"".to_string()
};
- let qualified_declaration = format!(
- "{} {}{}({}){}",
- ret_type, qualification, name, args, constness
- );
+ let qualified_declaration = format!("{ret_type} {qualification}{name}({args}){constness}");
// Whether there's a placement param in which to put the return value
let placement_param = details
.argument_conversion
@@ -491,13 +482,38 @@
)
}
CppFunctionBody::Destructor(ns, id) => {
- let ty_id = QualifiedName::new(ns, id.clone());
- let ty_id = final_ident_using_original_name_map(&ty_id, &self.original_name_map);
- (format!("{}->~{}()", arg_list, ty_id), "".to_string(), false)
+ let full_name = QualifiedName::new(ns, id.clone());
+ let ty_id = self.original_name_map.get_final_item(&full_name);
+ let is_a_nested_struct = self.original_name_map.get(&full_name).is_some();
+ // This is all super duper fiddly.
+ // All we want to do is call a destructor. Constraints:
+ // * an unnamed struct, e.g. typedef struct { .. } A, does not
+ // have any way of fully qualifying its destructor name.
+ // We have to use a 'using' statement.
+ // * we don't get enough information from bindgen to distinguish
+ // typedef struct { .. } A // unnamed struct
+ // from
+ // struct A { .. } // named struct
+ // * we can only do 'using A::B::C' if 'B' is a namespace,
+ // as opposed to a type with an inner type.
+ // * we can always do 'using C = A::B::C' but then SOME C++
+ // compilers complain that it's unused, iff it's a named struct.
+ let destructor_call = format!("{arg_list}->{ty_id}::~{ty_id}()");
+ let destructor_call = if ns.is_empty() {
+ destructor_call
+ } else {
+ let path = self.original_name_map.map(&full_name);
+ if is_a_nested_struct {
+ format!("{{ using {ty_id} = {path}; {destructor_call}; {ty_id}* pointless; (void)pointless; }}")
+ } else {
+ format!("{{ using {path}; {destructor_call}; }}")
+ }
+ };
+ (destructor_call, "".to_string(), false)
}
CppFunctionBody::FunctionCall(ns, id) => match receiver {
Some(receiver) => (
- format!("{}.{}({})", receiver, id, arg_list),
+ format!("{receiver}.{id}({arg_list})"),
"".to_string(),
false,
),
@@ -508,7 +524,7 @@
.chain(std::iter::once(id.to_string()))
.join("::");
(
- format!("{}({})", underlying_function_call, arg_list),
+ format!("{underlying_function_call}({arg_list})"),
"".to_string(),
false,
)
@@ -521,7 +537,7 @@
.chain([ty_id.to_string(), fn_id.to_string()].iter().cloned())
.join("::");
(
- format!("{}({})", underlying_function_call, arg_list),
+ format!("{underlying_function_call}({arg_list})"),
"".to_string(),
false,
)
@@ -530,7 +546,7 @@
CppFunctionBody::AllocUninitialized(ty) => {
let namespaced_ty = self.namespaced_name(ty);
(
- format!("new_appropriately<{}>();", namespaced_ty,),
+ format!("new_appropriately<{namespaced_ty}>();",),
"".to_string(),
true,
)
@@ -559,39 +575,35 @@
underlying_function_call = match placement_param {
Some(placement_param) => {
- let tyname = type_to_cpp(ret.cxxbridge_type(), &self.original_name_map)?;
- format!("new({}) {}({})", placement_param, tyname, call_itself)
+ let tyname = self.original_name_map.type_to_cpp(ret.cxxbridge_type())?;
+ format!("new({placement_param}) {tyname}({call_itself})")
}
- None => format!("return {}", call_itself),
+ None => format!("return {call_itself}"),
};
};
if !underlying_function_call.is_empty() {
- underlying_function_call = format!("{};", underlying_function_call);
+ underlying_function_call = format!("{underlying_function_call};");
}
let field_assignments =
if let CppFunctionBody::ConstructSuperclass(superclass_name) = &details.payload {
let superclass_assignments = if field_assignments.is_empty() {
"".to_string()
} else {
- format!("{}({}), ", superclass_name, field_assignments)
+ format!("{superclass_name}({field_assignments}), ")
};
- format!(": {}obs(std::move(arg0))", superclass_assignments)
+ format!(": {superclass_assignments}obs(std::move(arg0))")
} else {
"".into()
};
- let definition_after_sig =
- format!("{} {{ {} }}", field_assignments, underlying_function_call,);
+ let definition_after_sig = format!("{field_assignments} {{ {underlying_function_call} }}",);
let (declaration, definition) = if requires_rust_declarations {
(
- Some(format!("{};", declaration)),
- Some(format!(
- "{} {}",
- qualified_declaration, definition_after_sig
- )),
+ Some(format!("{declaration};")),
+ Some(format!("{qualified_declaration} {definition_after_sig}")),
)
} else {
(
- Some(format!("inline {} {}", declaration, definition_after_sig)),
+ Some(format!("inline {declaration} {definition_after_sig}")),
None,
)
};
@@ -609,7 +621,7 @@
}
fn namespaced_name(&self, name: &QualifiedName) -> String {
- namespaced_name_using_original_name_map(name, &self.original_name_map)
+ self.original_name_map.map(name)
}
fn generate_ctype_typedef(&mut self, tn: &QualifiedName) {
@@ -620,7 +632,7 @@
fn generate_typedef(&mut self, tn: &QualifiedName, definition: &str) {
let our_name = tn.get_final_item();
self.additional_functions.push(ExtraCpp {
- type_definition: Some(format!("typedef {} {};", definition, our_name)),
+ type_definition: Some(format!("typedef {definition} {our_name};")),
..Default::default()
})
}
@@ -631,10 +643,10 @@
subclass: &SubclassName,
constructors: Vec<&CppFunction>,
methods: Vec<SubclassFunction>,
- ) -> Result<(), ConvertError> {
+ ) -> Result<(), ConvertErrorFromCpp> {
let holder = subclass.holder();
self.additional_functions.push(ExtraCpp {
- type_definition: Some(format!("struct {};", holder)),
+ type_definition: Some(format!("struct {holder};")),
..Default::default()
});
let mut method_decls = Vec::new();
@@ -677,12 +689,10 @@
// In future, for each superclass..
let super_name = superclass.get_final_item();
method_decls.push(format!(
- "const {}& As_{}() const {{ return *this; }}",
- super_name, super_name,
+ "const {super_name}& As_{super_name}() const {{ return *this; }}",
));
method_decls.push(format!(
- "{}& As_{}_mut() {{ return *this; }}",
- super_name, super_name
+ "{super_name}& As_{super_name}_mut() {{ return *this; }}"
));
self.additional_functions.push(ExtraCpp {
declaration: Some(format!(
diff --git a/third_party/autocxx/engine/src/conversion/codegen_cpp/type_to_cpp.rs b/third_party/autocxx/engine/src/conversion/codegen_cpp/type_to_cpp.rs
index 7febb7a..b2da44b 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_cpp/type_to_cpp.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_cpp/type_to_cpp.rs
@@ -7,7 +7,7 @@
// except according to those terms.
use crate::{
- conversion::{apivec::ApiVec, AnalysisPhase, ConvertError},
+ conversion::{apivec::ApiVec, AnalysisPhase, ConvertErrorFromCpp},
types::QualifiedName,
};
use indexmap::map::IndexMap as HashMap;
@@ -19,116 +19,129 @@
/// Map from QualifiedName to original C++ name. Original C++ name does not
/// include the namespace; this can be assumed to be the same as the namespace
/// in the QualifiedName.
-pub(crate) type CppNameMap = HashMap<QualifiedName, String>;
+/// The "original C++ name" is mostly relevant in the case of nested types,
+/// where the typename might be A::B within a namespace C::D.
+pub(crate) struct CppNameMap(HashMap<QualifiedName, String>);
-pub(crate) fn original_name_map_from_apis<T: AnalysisPhase>(apis: &ApiVec<T>) -> CppNameMap {
- apis.iter()
- .filter_map(|api| {
- api.cpp_name()
- .as_ref()
- .map(|cpp_name| (api.name().clone(), cpp_name.clone()))
- })
- .collect()
-}
-
-pub(crate) fn namespaced_name_using_original_name_map(
- qual_name: &QualifiedName,
- original_name_map: &CppNameMap,
-) -> String {
- if let Some(cpp_name) = original_name_map.get(qual_name) {
- qual_name
- .get_namespace()
- .iter()
- .chain(once(cpp_name))
- .join("::")
- } else {
- qual_name.to_cpp_name()
- }
-}
-
-pub(crate) fn final_ident_using_original_name_map(
- qual_name: &QualifiedName,
- original_name_map: &CppNameMap,
-) -> String {
- match original_name_map.get(qual_name) {
- Some(original_name) => {
- // If we have an original name, this may be a nested struct
- // (e.g. A::B). The final ident here is just 'B' so...
- original_name
- .rsplit_once("::")
- .map_or(original_name.clone(), |(_, original_name)| {
- original_name.to_string()
+impl CppNameMap {
+ /// Look through the APIs we've found to assemble the original name
+ /// map.
+ pub(crate) fn new_from_apis<T: AnalysisPhase>(apis: &ApiVec<T>) -> Self {
+ Self(
+ apis.iter()
+ .filter_map(|api| {
+ api.cpp_name()
+ .as_ref()
+ .map(|cpp_name| (api.name().clone(), cpp_name.clone()))
})
- }
- None => qual_name.get_final_cpp_item(),
+ .collect(),
+ )
}
-}
-pub(crate) fn type_to_cpp(ty: &Type, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
- match ty {
- Type::Path(typ) => {
- // If this is a std::unique_ptr we do need to pass
- // its argument through.
- let qual_name = QualifiedName::from_type_path(typ);
- let root = namespaced_name_using_original_name_map(&qual_name, cpp_name_map);
- if root == "Pin" {
- // Strip all Pins from type names when describing them in C++.
- let inner_type = &typ.path.segments.last().unwrap().arguments;
- if let syn::PathArguments::AngleBracketed(ab) = inner_type {
- let inner_type = ab.args.iter().next().unwrap();
- if let syn::GenericArgument::Type(gat) = inner_type {
- return type_to_cpp(gat, cpp_name_map);
- }
- }
- panic!("Pin<...> didn't contain the inner types we expected");
- }
- let suffix = match &typ.path.segments.last().unwrap().arguments {
- syn::PathArguments::AngleBracketed(ab) => {
- let results: Result<Vec<_>, _> = ab
- .args
- .iter()
- .map(|x| match x {
- syn::GenericArgument::Type(gat) => type_to_cpp(gat, cpp_name_map),
- _ => Ok("".to_string()),
- })
- .collect();
- Some(results?.join(", "))
- }
- syn::PathArguments::None | syn::PathArguments::Parenthesized(_) => None,
- };
- match suffix {
- None => Ok(root),
- Some(suffix) => Ok(format!("{}<{}>", root, suffix)),
- }
+ /// Imagine a nested struct in namespace::outer::inner
+ /// This function converts from the bindgen name, namespace::outer_inner,
+ /// to namespace::outer::inner.
+ pub(crate) fn map(&self, qual_name: &QualifiedName) -> String {
+ if let Some(cpp_name) = self.0.get(qual_name) {
+ qual_name
+ .get_namespace()
+ .iter()
+ .chain(once(cpp_name))
+ .join("::")
+ } else {
+ qual_name.to_cpp_name()
}
- Type::Reference(typr) => match &*typr.elem {
- Type::Path(typ) if typ.path.is_ident("str") => Ok("rust::Str".into()),
- _ => Ok(format!(
- "{}{}&",
- get_mut_string(&typr.mutability),
- type_to_cpp(typr.elem.as_ref(), cpp_name_map)?
+ }
+
+ /// Get a stringified version of the last ident in the name.
+ /// e.g. for namespace::outer_inner this will return inner.
+ /// This is useful for doing things such as calling constructors
+ /// such as inner() or destructors such as ~inner()
+ pub(crate) fn get_final_item<'b>(&'b self, qual_name: &'b QualifiedName) -> &'b str {
+ match self.get(qual_name) {
+ Some(n) => match n.rsplit_once("::") {
+ Some((_, suffix)) => suffix,
+ None => qual_name.get_final_item(),
+ },
+ None => qual_name.get_final_item(),
+ }
+ }
+
+ /// Convert a type to its C++ spelling.
+ pub(crate) fn type_to_cpp(&self, ty: &Type) -> Result<String, ConvertErrorFromCpp> {
+ match ty {
+ Type::Path(typ) => {
+ // If this is a std::unique_ptr we do need to pass
+ // its argument through.
+ let qual_name = QualifiedName::from_type_path(typ);
+ let root = self.map(&qual_name);
+ if root == "Pin" {
+ // Strip all Pins from type names when describing them in C++.
+ let inner_type = &typ.path.segments.last().unwrap().arguments;
+ if let syn::PathArguments::AngleBracketed(ab) = inner_type {
+ let inner_type = ab.args.iter().next().unwrap();
+ if let syn::GenericArgument::Type(gat) = inner_type {
+ return self.type_to_cpp(gat);
+ }
+ }
+ panic!("Pin<...> didn't contain the inner types we expected");
+ }
+ let suffix = match &typ.path.segments.last().unwrap().arguments {
+ syn::PathArguments::AngleBracketed(ab) => {
+ let results: Result<Vec<_>, _> = ab
+ .args
+ .iter()
+ .map(|x| match x {
+ syn::GenericArgument::Type(gat) => self.type_to_cpp(gat),
+ _ => Ok("".to_string()),
+ })
+ .collect();
+ Some(results?.join(", "))
+ }
+ syn::PathArguments::None | syn::PathArguments::Parenthesized(_) => None,
+ };
+ match suffix {
+ None => Ok(root),
+ Some(suffix) => Ok(format!("{root}<{suffix}>")),
+ }
+ }
+ Type::Reference(typr) => match &*typr.elem {
+ Type::Path(typ) if typ.path.is_ident("str") => Ok("rust::Str".into()),
+ _ => Ok(format!(
+ "{}{}&",
+ get_mut_string(&typr.mutability),
+ self.type_to_cpp(typr.elem.as_ref())?
+ )),
+ },
+ Type::Ptr(typp) => Ok(format!(
+ "{}{}*",
+ get_mut_string(&typp.mutability),
+ self.type_to_cpp(typp.elem.as_ref())?
)),
- },
- Type::Ptr(typp) => Ok(format!(
- "{}{}*",
- get_mut_string(&typp.mutability),
- type_to_cpp(typp.elem.as_ref(), cpp_name_map)?
- )),
- Type::Array(_)
- | Type::BareFn(_)
- | Type::Group(_)
- | Type::ImplTrait(_)
- | Type::Infer(_)
- | Type::Macro(_)
- | Type::Never(_)
- | Type::Paren(_)
- | Type::Slice(_)
- | Type::TraitObject(_)
- | Type::Tuple(_)
- | Type::Verbatim(_) => Err(ConvertError::UnsupportedType(
- ty.to_token_stream().to_string(),
- )),
- _ => Err(ConvertError::UnknownType(ty.to_token_stream().to_string())),
+ Type::Array(_)
+ | Type::BareFn(_)
+ | Type::Group(_)
+ | Type::ImplTrait(_)
+ | Type::Infer(_)
+ | Type::Macro(_)
+ | Type::Never(_)
+ | Type::Paren(_)
+ | Type::Slice(_)
+ | Type::TraitObject(_)
+ | Type::Tuple(_)
+ | Type::Verbatim(_) => Err(ConvertErrorFromCpp::UnsupportedType(
+ ty.to_token_stream().to_string(),
+ )),
+ _ => Err(ConvertErrorFromCpp::UnknownType(
+ ty.to_token_stream().to_string(),
+ )),
+ }
+ }
+
+ /// Check an individual item in the name map. Returns a thing if
+ /// it's an inner type, otherwise returns none.
+ pub(crate) fn get(&self, name: &QualifiedName) -> Option<&String> {
+ self.0.get(name)
}
}
diff --git a/third_party/autocxx/engine/src/conversion/codegen_rs/fun_codegen.rs b/third_party/autocxx/engine/src/conversion/codegen_rs/fun_codegen.rs
index db222a6..1b68e8c 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_rs/fun_codegen.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_rs/fun_codegen.rs
@@ -34,6 +34,7 @@
},
api::{Pointerness, UnsafetyNeeded},
},
+ minisyn::minisynize_vec,
types::{Namespace, QualifiedName},
};
use crate::{
@@ -104,7 +105,7 @@
let params = analysis.params;
let vis = analysis.vis;
let kind = analysis.kind;
- let doc_attrs = fun.doc_attrs;
+ let doc_attrs = minisynize_vec(fun.doc_attrs);
let mut cpp_name_attr = Vec::new();
let mut impl_entry = None;
@@ -132,7 +133,6 @@
params,
Cow::Borrowed(&ret_type),
non_pod_types,
- true,
);
if analysis.rust_wrapper_needed {
@@ -170,10 +170,10 @@
FnKind::Method { .. } | FnKind::TraitMethod { .. } => None,
FnKind::Function => match analysis.rust_rename_strategy {
_ if analysis.rust_wrapper_needed => {
- Some(Use::SpecificNameFromBindgen(make_ident(rust_name)))
+ Some(Use::SpecificNameFromBindgen(make_ident(rust_name).into()))
}
RustRenameStrategy::RenameInOutputMod(ref alias) => {
- Some(Use::UsedFromCxxBridgeWithAlias(alias.clone()))
+ Some(Use::UsedFromCxxBridgeWithAlias(alias.clone().into()))
}
_ => Some(Use::UsedFromCxxBridge),
},
@@ -259,14 +259,14 @@
let mut ptr_arg_name = None;
let mut ret_type: Cow<'a, _> = ret_type
.map(Cow::Owned)
- .unwrap_or(Cow::Borrowed(self.ret_type));
+ .unwrap_or_else(|| Cow::Borrowed(self.ret_type));
let mut any_conversion_requires_unsafe = false;
let mut variable_counter = 0usize;
for pd in self.param_details {
- let wrapper_arg_name = if pd.self_type.is_some() && !avoid_self {
+ let wrapper_arg_name: syn::Pat = if pd.self_type.is_some() && !avoid_self {
parse_quote!(self)
} else {
- pd.name.clone()
+ pd.name.clone().into()
};
let rust_for_param = pd
.conversion
@@ -308,7 +308,6 @@
wrapper_params,
ret_type,
self.non_pod_types,
- false,
);
let cxxbridge_name = self.cxxbridge_name;
@@ -322,6 +321,17 @@
|| self.always_unsafe_due_to_trait_definition;
let (call_body, ret_type) = match self.ret_conversion {
Some(ret_conversion) if ret_conversion.rust_work_needed() => {
+ // There's a potential lurking bug below. If the return type conversion requires
+ // unsafe, then we'll end up doing something like
+ // unsafe { do_return_conversion( unsafe { call_body() })}
+ // and the generated code will get warnings about nested unsafe blocks.
+ // That's because we convert the call body to tokens in the following
+ // line without considering the fact it's embedded in another expression.
+ // At the moment this is OK because no return type conversions require
+ // unsafe, but if this happens in future, we should do:
+ // let temp_ret_val = unsafe { call_body() };
+ // do_return_conversion(temp_ret_val)
+ // by returning a vector of MaybeUnsafes within call_body.
let expr = maybe_unsafes_to_tokens(vec![call_body], context_is_unsafe);
let conv =
ret_conversion.rust_conversion(parse_quote! { #expr }, &mut variable_counter);
@@ -391,33 +401,26 @@
.map(|pd| pd.conversion.is_a_pointer())
.unwrap_or(Pointerness::Not);
let ty = impl_block_type_name.get_final_ident();
- let ty = if self.reference_wrappers {
- match receiver_pointerness {
- Pointerness::MutPtr => ImplBlockKey {
- ty: parse_quote! {
- CppMutRef< 'a, #ty>
- },
- lifetime: Some(parse_quote! { 'a }),
+ let ty = match receiver_pointerness {
+ Pointerness::MutPtr if self.reference_wrappers => ImplBlockKey {
+ ty: parse_quote! {
+ #ty
},
- Pointerness::ConstPtr => ImplBlockKey {
- ty: parse_quote! {
- CppRef< 'a, #ty>
- },
- lifetime: Some(parse_quote! { 'a }),
+ lifetime: Some(parse_quote! { 'a }),
+ },
+ Pointerness::ConstPtr if self.reference_wrappers => ImplBlockKey {
+ ty: parse_quote! {
+ #ty
},
- Pointerness::Not => ImplBlockKey {
- ty: parse_quote! { # ty },
- lifetime: None,
- },
- }
- } else {
- ImplBlockKey {
+ lifetime: Some(parse_quote! { 'a }),
+ },
+ _ => ImplBlockKey {
ty: parse_quote! { # ty },
lifetime: None,
- }
+ },
};
Box::new(ImplBlockDetails {
- item: ImplItem::Method(parse_quote! {
+ item: ImplItem::Fn(parse_quote! {
#(#doc_attrs)*
pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
#call_body
@@ -453,7 +456,7 @@
let ret_type: ReturnType = parse_quote! { -> impl autocxx::moveit::new::New<Output=Self> };
let (lifetime_tokens, wrapper_params, ret_type, call_body) =
self.common_parts(true, &None, Some(ret_type));
- let rust_name = make_ident(&self.rust_name);
+ let rust_name = make_ident(self.rust_name);
let doc_attrs = self.doc_attrs;
let unsafety = self.unsafety.wrapper_token();
let ty = impl_block_type_name.get_final_ident();
@@ -465,7 +468,7 @@
}
};
Box::new(ImplBlockDetails {
- item: ImplItem::Method(parse_quote! { #stuff }),
+ item: ImplItem::Fn(parse_quote! { #stuff }),
ty: ImplBlockKey { ty, lifetime: None },
})
}
diff --git a/third_party/autocxx/engine/src/conversion/codegen_rs/function_wrapper_rs.rs b/third_party/autocxx/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
index 708d41c..4afe3c7 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
@@ -63,11 +63,11 @@
}
RustConversionType::FromPinMaybeUninitToPtr => {
let ty = match self.cxxbridge_type() {
- Type::Ptr(TypePtr { elem, .. }) => &*elem,
+ Type::Ptr(TypePtr { elem, .. }) => elem,
_ => panic!("Not a ptr"),
};
let ty = parse_quote! {
- ::std::pin::Pin<&mut ::std::mem::MaybeUninit< #ty >>
+ ::core::pin::Pin<&mut ::core::mem::MaybeUninit< #ty >>
};
RustParamConversion::Param {
ty,
@@ -80,17 +80,17 @@
}
RustConversionType::FromPinMoveRefToPtr => {
let ty = match self.cxxbridge_type() {
- Type::Ptr(TypePtr { elem, .. }) => &*elem,
+ Type::Ptr(TypePtr { elem, .. }) => elem,
_ => panic!("Not a ptr"),
};
let ty = parse_quote! {
- ::std::pin::Pin<autocxx::moveit::MoveRef< '_, #ty >>
+ ::core::pin::Pin<autocxx::moveit::MoveRef< '_, #ty >>
};
RustParamConversion::Param {
ty,
local_variables: Vec::new(),
conversion: quote! {
- { let r: &mut _ = ::std::pin::Pin::into_inner_unchecked(#var.as_mut());
+ { let r: &mut _ = ::core::pin::Pin::into_inner_unchecked(#var.as_mut());
r
}
},
@@ -99,7 +99,7 @@
}
RustConversionType::FromTypeToPtr => {
let ty = match self.cxxbridge_type() {
- Type::Ptr(TypePtr { elem, .. }) => &*elem,
+ Type::Ptr(TypePtr { elem, .. }) => elem,
_ => panic!("Not a ptr"),
};
let ty = parse_quote! { &mut #ty };
@@ -124,7 +124,7 @@
let param_trait = make_ident(param_trait);
let var_counter = *counter;
*counter += 1;
- let space_var_name = format!("space{}", var_counter);
+ let space_var_name = format!("space{var_counter}");
let space_var_name = make_ident(space_var_name);
let ty = self.cxxbridge_type();
let ty = parse_quote! { impl autocxx::#param_trait<#ty> };
@@ -138,10 +138,10 @@
),
MaybeUnsafeStmt::binary(
quote! { let mut #space_var_name =
- unsafe { ::std::pin::Pin::new_unchecked(&mut #space_var_name) };
+ unsafe { ::core::pin::Pin::new_unchecked(&mut #space_var_name) };
},
quote! { let mut #space_var_name =
- ::std::pin::Pin::new_unchecked(&mut #space_var_name);
+ ::core::pin::Pin::new_unchecked(&mut #space_var_name);
},
),
MaybeUnsafeStmt::needs_unsafe(
@@ -172,16 +172,16 @@
_ => panic!("Not a pointer"),
};
let (ty, wrapper_name) = if is_mut {
- (parse_quote! { CppMutRef<'a, #ty> }, "CppMutRef")
+ (parse_quote! { autocxx::CppMutRef<'a, #ty> }, "CppMutRef")
} else {
- (parse_quote! { CppRef<'a, #ty> }, "CppRef")
+ (parse_quote! { autocxx::CppRef<'a, #ty> }, "CppRef")
};
let wrapper_name = make_ident(wrapper_name);
RustParamConversion::Param {
ty,
local_variables: Vec::new(),
conversion: quote! {
- #wrapper_name (#var, std::marker::PhantomData)
+ autocxx::#wrapper_name::from_ptr (#var)
},
conversion_requires_unsafe: false,
}
@@ -194,15 +194,21 @@
_ => panic!("Not a pointer"),
};
let ty = if is_mut {
- parse_quote! { &mut CppMutRef<'a, #ty> }
+ parse_quote! { &mut autocxx::CppMutRef<'a, #ty> }
} else {
- parse_quote! { &CppRef<'a, #ty> }
+ parse_quote! { &autocxx::CppRef<'a, #ty> }
};
RustParamConversion::Param {
ty,
local_variables: Vec::new(),
- conversion: quote! {
- #var .0
+ conversion: if is_mut {
+ quote! {
+ #var .as_mut_ptr()
+ }
+ } else {
+ quote! {
+ #var .as_ptr()
+ }
},
conversion_requires_unsafe: false,
}
diff --git a/third_party/autocxx/engine/src/conversion/codegen_rs/lifetime.rs b/third_party/autocxx/engine/src/conversion/codegen_rs/lifetime.rs
index ea2c782..5560158 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_rs/lifetime.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_rs/lifetime.rs
@@ -36,7 +36,6 @@
mut params: Punctuated<FnArg, Comma>,
ret_type: Cow<'r, ReturnType>,
non_pod_types: &HashSet<QualifiedName>,
- assert_all_parameters_are_references: bool,
) -> (
Option<TokenStream>,
Punctuated<FnArg, Comma>,
@@ -92,25 +91,16 @@
match new_return_type {
None => (None, params, ret_type),
Some(new_return_type) => {
- for mut param in params.iter_mut() {
- match &mut param {
- FnArg::Typed(PatType { ty, .. }) => match ty.as_mut() {
- Type::Path(TypePath {
- path: Path { segments, .. },
- ..
- }) => add_lifetime_to_pinned_reference(segments).unwrap_or_else(|e| {
- if assert_all_parameters_are_references {
- panic!("Expected a pinned reference: {:?}", e)
- }
- }),
- Type::Reference(tyr) => add_lifetime_to_reference(tyr),
- Type::ImplTrait(tyit) => add_lifetime_to_impl_trait(tyit),
- _ if assert_all_parameters_are_references => {
- panic!("Expected Pin<&mut T> or &T")
- }
- _ => {}
- },
- _ if assert_all_parameters_are_references => panic!("Unexpected fnarg"),
+ for FnArg::Typed(PatType { ty, .. }) | FnArg::Receiver(syn::Receiver { ty, .. }) in
+ params.iter_mut()
+ {
+ match ty.as_mut() {
+ Type::Path(TypePath {
+ path: Path { segments, .. },
+ ..
+ }) => add_lifetime_to_pinned_reference(segments).unwrap_or(()),
+ Type::Reference(tyr) => add_lifetime_to_reference(tyr),
+ Type::ImplTrait(tyit) => add_lifetime_to_impl_trait(tyit),
_ => {}
}
}
@@ -168,16 +158,19 @@
}
fn add_lifetime_to_pinned_reference(
- segments: &mut Punctuated<PathSegment, syn::token::Colon2>,
+ segments: &mut Punctuated<PathSegment, syn::token::PathSep>,
) -> Result<(), AddLifetimeError> {
- static EXPECTED_SEGMENTS: &[(&str, bool)] = &[
- ("std", false),
- ("pin", false),
- ("Pin", true), // true = act on the arguments of this segment
+ static EXPECTED_SEGMENTS: &[(&[&str], bool)] = &[
+ (&["std", "core"], false),
+ (&["pin"], false),
+ (&["Pin"], true), // true = act on the arguments of this segment
];
for (seg, (expected_name, act)) in segments.iter_mut().zip(EXPECTED_SEGMENTS.iter()) {
- if seg.ident != expected_name {
+ if !expected_name
+ .iter()
+ .any(|expected_name| seg.ident == expected_name)
+ {
return Err(AddLifetimeError::WasNotPin);
}
if *act {
diff --git a/third_party/autocxx/engine/src/conversion/codegen_rs/mod.rs b/third_party/autocxx/engine/src/conversion/codegen_rs/mod.rs
index d1219d2..abab612 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_rs/mod.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_rs/mod.rs
@@ -28,13 +28,11 @@
};
use crate::{
- conversion::{
- codegen_rs::{
- non_pod_struct::{make_non_pod, new_non_pod_struct},
- unqualify::{unqualify_params, unqualify_ret_type},
- },
- doc_attr::get_doc_attrs,
+ conversion::codegen_rs::{
+ non_pod_struct::{make_non_pod, new_non_pod_struct},
+ unqualify::{unqualify_params, unqualify_ret_type},
},
+ minisyn::minisynize_punctuated,
types::{make_ident, Namespace, QualifiedName},
};
use impl_item_creator::create_impl_items;
@@ -51,15 +49,14 @@
},
api::{AnalysisPhase, Api, SubclassName, TypeKind, TypedefKind},
convert_error::ErrorContextType,
+ doc_attr::get_doc_attrs,
};
use super::{
api::{Layout, Provenance, RustSubclassFnDetails, SuperclassMethod, TraitImplSignature},
apivec::ApiVec,
- codegen_cpp::type_to_cpp::{
- namespaced_name_using_original_name_map, original_name_map_from_apis, CppNameMap,
- },
+ codegen_cpp::type_to_cpp::CppNameMap,
};
-use super::{convert_error::ErrorContext, ConvertError};
+use super::{convert_error::ErrorContext, ConvertErrorFromCpp};
use quote::quote;
#[derive(Clone, Hash, PartialEq, Eq)]
@@ -137,91 +134,6 @@
.to_vec()
}
-fn get_cppref_items() -> Vec<Item> {
- [
- Item::Struct(parse_quote! {
- #[repr(transparent)]
- pub struct CppRef<'a, T>(pub *const T, pub ::std::marker::PhantomData<&'a T>);
- }),
- Item::Impl(parse_quote! {
- impl<'a, T> autocxx::CppRef<'a, T> for CppRef<'a, T> {
- fn as_ptr(&self) -> *const T {
- self.0
- }
- }
- }),
- Item::Struct(parse_quote! {
- #[repr(transparent)]
- pub struct CppMutRef<'a, T>(pub *mut T, pub ::std::marker::PhantomData<&'a T>);
- }),
- Item::Impl(parse_quote! {
- impl<'a, T> autocxx::CppRef<'a, T> for CppMutRef<'a, T> {
- fn as_ptr(&self) -> *const T {
- self.0
- }
- }
- }),
- Item::Impl(parse_quote! {
- impl<'a, T> autocxx::CppMutRef<'a, T> for CppMutRef<'a, T> {
- fn as_mut_ptr(&self) -> *mut T {
- self.0
- }
- }
- }),
- Item::Impl(parse_quote! {
- impl<'a, T: ::cxx::private::UniquePtrTarget> CppMutRef<'a, T> {
- /// Create a const C++ reference from this mutable C++ reference.
- pub fn as_cpp_ref(&self) -> CppRef<'a, T> {
- use autocxx::CppRef;
- CppRef(self.as_ptr(), ::std::marker::PhantomData)
- }
- }
- }),
- Item::Struct(parse_quote! {
- /// "Pins" a `UniquePtr` to an object, so that C++-compatible references can be created.
- /// See [`::autocxx::CppPin`]
- #[repr(transparent)]
- pub struct CppUniquePtrPin<T: ::cxx::private::UniquePtrTarget>(::cxx::UniquePtr<T>);
- }),
- Item::Impl(parse_quote! {
- impl<'a, T: 'a + ::cxx::private::UniquePtrTarget> autocxx::CppPin<'a, T> for CppUniquePtrPin<T>
- {
- type CppRef = CppRef<'a, T>;
- type CppMutRef = CppMutRef<'a, T>;
- fn as_ptr(&self) -> *const T {
- // TODO add as_ptr to cxx to avoid the ephemeral reference
- self.0.as_ref().unwrap() as *const T
- }
- fn as_mut_ptr(&mut self) -> *mut T {
- unsafe { ::std::pin::Pin::into_inner_unchecked(self.0.as_mut().unwrap()) as *mut T }
- }
- fn as_cpp_ref(&self) -> Self::CppRef {
- CppRef(self.as_ptr(), ::std::marker::PhantomData)
- }
- fn as_cpp_mut_ref(&mut self) -> Self::CppMutRef {
- CppMutRef(self.as_mut_ptr(), ::std::marker::PhantomData)
- }
- }
- }),
- Item::Impl(parse_quote! {
- impl<T: ::cxx::private::UniquePtrTarget> CppUniquePtrPin<T> {
- pub fn new(item: ::cxx::UniquePtr<T>) -> Self {
- Self(item)
- }
- }
- }),
- Item::Fn(parse_quote! {
- /// Pin this item so that we can create C++ references to it.
- /// This makes it impossible to hold Rust references because Rust
- /// references are fundamentally incompatible with C++ references.
- pub fn cpp_pin_uniqueptr<T: ::cxx::private::UniquePtrTarget> (item: ::cxx::UniquePtr<T>) -> CppUniquePtrPin<T> {
- CppUniquePtrPin::new(item)
- }
- })
- ]
- .to_vec()
-}
-
/// Type which handles generation of Rust code.
/// In practice, much of the "generation" involves connecting together
/// existing lumps of code within the Api structures.
@@ -248,7 +160,7 @@
unsafe_policy,
include_list,
bindgen_mod,
- original_name_map: original_name_map_from_apis(&all_apis),
+ original_name_map: CppNameMap::new_from_apis(&all_apis),
config,
header_name,
};
@@ -314,9 +226,6 @@
let mut extern_rust_mod_items = extern_rust_mod_items.into_iter().flatten().collect();
// And a list of global items to include at the top level.
let mut all_items: Vec<Item> = all_items.into_iter().flatten().collect();
- if self.config.unsafe_policy.requires_cpprefs() {
- all_items.append(&mut get_cppref_items())
- }
// And finally any C++ we need to generate. And by "we" I mean autocxx not cxx.
let has_additional_cpp_needs = additional_cpp_needs.into_iter().any(std::convert::identity);
extern_c_mod_items.extend(self.build_include_foreign_items(has_additional_cpp_needs));
@@ -430,7 +339,7 @@
Use::UsedFromCxxBridge => Self::generate_cxx_use_stmt(name, None),
Use::UsedFromBindgen => Self::generate_bindgen_use_stmt(name),
Use::SpecificNameFromBindgen(id) => {
- let name = QualifiedName::new(name.get_namespace(), id.clone());
+ let name = QualifiedName::new(name.get_namespace(), id.clone().into());
Self::generate_bindgen_use_stmt(&name)
}
Use::Custom(item) => *item.clone(),
@@ -459,9 +368,6 @@
if !self.config.exclude_utilities() {
imports_from_super.push("ToCppString");
}
- if self.config.unsafe_policy.requires_cpprefs() {
- imports_from_super.extend(["CppRef", "CppMutRef"]);
- }
let imports_from_super = imports_from_super.into_iter().map(make_ident);
let super_duper = std::iter::repeat(make_ident("super")); // I'll get my coat
let supers = super_duper.clone().take(ns.depth() + 2);
@@ -576,9 +482,9 @@
fn #make_string_name(str_: &str) -> UniquePtr<CxxString>;
))],
global_items: get_string_items(),
- materializations: vec![Use::UsedFromCxxBridgeWithAlias(make_ident(
- "make_string",
- ))],
+ materializations: vec![Use::UsedFromCxxBridgeWithAlias(
+ make_ident("make_string").into(),
+ )],
..Default::default()
}
}
@@ -591,14 +497,14 @@
self.config,
),
Api::Const { const_item, .. } => RsCodegenResult {
- bindgen_mod_items: vec![Item::Const(const_item)],
+ bindgen_mod_items: vec![Item::Const(const_item.into())],
materializations: vec![Use::UsedFromBindgen],
..Default::default()
},
Api::Typedef { analysis, .. } => RsCodegenResult {
bindgen_mod_items: vec![match analysis.kind {
- TypedefKind::Type(type_item) => Item::Type(type_item),
- TypedefKind::Use(use_item, _) => Item::Use(use_item),
+ TypedefKind::Type(type_item) => Item::Type(type_item.into()),
+ TypedefKind::Use(use_item, _) => Item::Use(use_item.into()),
}],
materializations: vec![Use::UsedFromBindgen],
..Default::default()
@@ -624,7 +530,7 @@
kind,
constructors.move_constructor,
constructors.destructor,
- || Some((Item::Struct(details.item), doc_attrs)),
+ || Some((Item::Struct(details.item.into()), doc_attrs)),
associated_methods,
layout,
is_generic,
@@ -638,15 +544,13 @@
TypeKind::Pod,
true,
true,
- || Some((Item::Enum(item), doc_attrs)),
+ || Some((Item::Enum(item.into()), doc_attrs)),
associated_methods,
None,
false,
)
}
- Api::ForwardDeclaration { .. }
- | Api::ConcreteType { .. }
- | Api::OpaqueTypedef { .. } => self.generate_type(
+ Api::ConcreteType { .. } => self.generate_type(
&name,
id,
TypeKind::Abstract,
@@ -657,56 +561,68 @@
None,
false,
),
+ Api::ForwardDeclaration { .. } | Api::OpaqueTypedef { .. } => self.generate_type(
+ &name,
+ id,
+ TypeKind::Abstract,
+ false, // these types can't be kept in a Vector
+ false, // these types can't be put in a smart pointer
+ || None,
+ associated_methods,
+ None,
+ false,
+ ),
Api::CType { .. } => RsCodegenResult {
extern_c_mod_items: vec![ForeignItem::Verbatim(quote! {
type #id = autocxx::#id;
})],
..Default::default()
},
- Api::RustType { path, .. } => RsCodegenResult {
- global_items: vec![parse_quote! {
- use super::#path;
- }],
- extern_rust_mod_items: vec![parse_quote! {
- type #id;
- }],
- ..Default::default()
- },
+ Api::RustType { path, .. } => {
+ let id = path.get_final_ident();
+ RsCodegenResult {
+ global_items: vec![parse_quote! {
+ use super::#path;
+ }],
+ extern_rust_mod_items: vec![parse_quote! {
+ type #id;
+ }],
+ bindgen_mod_items: vec![parse_quote! {
+ #[allow(unused_imports)]
+ use super::super::#id;
+ }],
+ ..Default::default()
+ }
+ }
Api::RustFn {
details:
RustFun {
path,
- sig,
- receiver: None,
+ mut sig,
+ has_receiver,
..
},
..
- } => RsCodegenResult {
- global_items: vec![parse_quote! {
- use super::#path;
- }],
- extern_rust_mod_items: vec![parse_quote! {
- #sig;
- }],
- ..Default::default()
- },
- Api::RustFn {
- details:
- RustFun {
- sig,
- receiver: Some(_),
- ..
+ } => {
+ sig.inputs = unqualify_params(sig.inputs);
+ sig.output = unqualify_ret_type(sig.output);
+ RsCodegenResult {
+ global_items: if !has_receiver {
+ vec![parse_quote! {
+ use super::#path;
+ }]
+ } else {
+ Vec::new()
},
- ..
- } => RsCodegenResult {
- extern_rust_mod_items: vec![parse_quote! {
- #sig;
- }],
- ..Default::default()
- },
+ extern_rust_mod_items: vec![parse_quote! {
+ #sig;
+ }],
+ ..Default::default()
+ }
+ }
Api::RustSubclassFn {
details, subclass, ..
- } => Self::generate_subclass_fn(id, *details, subclass),
+ } => Self::generate_subclass_fn(id.into(), *details, subclass),
Api::Subclass {
name, superclass, ..
} => {
@@ -812,7 +728,7 @@
bindgen_mod_items.push(parse_quote! {
impl autocxx::subclass::CppPeerConstructor<#cpp_id> for super::super::super::#id {
fn make_peer(&mut self, peer_holder: autocxx::subclass::CppSubclassRustPeerHolder<Self>) -> cxx::UniquePtr<#cpp_path> {
- use autocxx::moveit::EmplaceUnpinned;
+ use autocxx::moveit::Emplace;
cxx::UniquePtr::emplace(#cpp_id :: new(peer_holder))
}
}
@@ -820,15 +736,15 @@
};
// Once for each superclass, in future...
- let as_id = make_ident(format!("As_{}", super_name));
+ let as_id = make_ident(format!("As_{super_name}"));
extern_c_mod_items.push(parse_quote! {
fn #as_id(self: &#cpp_id) -> &#super_cxxxbridge_id;
});
- let as_mut_id = make_ident(format!("As_{}_mut", super_name));
+ let as_mut_id = make_ident(format!("As_{super_name}_mut"));
extern_c_mod_items.push(parse_quote! {
fn #as_mut_id(self: Pin<&mut #cpp_id>) -> Pin<&mut #super_cxxxbridge_id>;
});
- let as_unique_ptr_id = make_ident(format!("{}_As_{}_UniquePtr", cpp_id, super_name));
+ let as_unique_ptr_id = make_ident(format!("{cpp_id}_As_{super_name}_UniquePtr"));
extern_c_mod_items.push(parse_quote! {
fn #as_unique_ptr_id(u: UniquePtr<#cpp_id>) -> UniquePtr<#super_cxxxbridge_id>;
});
@@ -843,13 +759,13 @@
// TODO it would be nice to impl AsMut here but pin prevents us
bindgen_mod_items.push(parse_quote! {
impl super::super::super::#id {
- pub fn pin_mut(&mut self) -> ::std::pin::Pin<&mut cxxbridge::#super_cxxxbridge_id> {
+ pub fn pin_mut(&mut self) -> ::core::pin::Pin<&mut cxxbridge::#super_cxxxbridge_id> {
use autocxx::subclass::CppSubclass;
self.peer_mut().#as_mut_id()
}
}
});
- let rs_as_unique_ptr_id = make_ident(format!("as_{}_unique_ptr", super_name));
+ let rs_as_unique_ptr_id = make_ident(format!("as_{super_name}_unique_ptr"));
bindgen_mod_items.push(parse_quote! {
impl super::super::super::#id {
pub fn #rs_as_unique_ptr_id(u: cxx::UniquePtr<#cpp_id>) -> cxx::UniquePtr<cxxbridge::#super_cxxxbridge_id> {
@@ -896,8 +812,8 @@
let ret = details.ret;
let unsafe_token = details.requires_unsafe.wrapper_token();
let global_def = quote! { #unsafe_token fn #api_name(#params) #ret };
- let params = unqualify_params(params);
- let ret = unqualify_ret_type(ret);
+ let params = unqualify_params(minisynize_punctuated(params));
+ let ret = unqualify_ret_type(ret.into());
let method_name = details.method_name;
let cxxbridge_decl: ForeignItemFn =
parse_quote! { #unsafe_token fn #api_name(#params) #ret; };
@@ -930,7 +846,7 @@
.as_ref()
.#borrow()
.expect(#reentrancy_panic_msg);
- let r = ::std::ops::#deref_ty::#deref_call(& #mut_token b);
+ let r = ::core::ops::#deref_ty::#deref_call(& #mut_token b);
#methods_trait :: #method_name
(r,
#args)
@@ -955,7 +871,7 @@
fn generate_type<F>(
&self,
name: &QualifiedName,
- id: Ident,
+ id: crate::minisyn::Ident,
type_kind: TypeKind,
movable: bool,
destroyable: bool,
@@ -1004,7 +920,7 @@
make_non_pod(s, layout);
} else {
// enum
- item = Item::Struct(new_non_pod_struct(id.clone()));
+ item = Item::Struct(new_non_pod_struct(id.clone().into()));
}
}
bindgen_mod_items.push(item);
@@ -1066,8 +982,9 @@
let super_id =
SubclassName::get_super_fn_name(&Namespace::new(), &id.to_string())
.get_final_ident();
+ let params = minisynize_punctuated(method.params.clone());
let param_names: Punctuated<Expr, Comma> =
- Self::args_from_sig(&method.params).collect();
+ Self::args_from_sig(¶ms).collect();
let mut params = method.params.clone();
*(params.iter_mut().next().unwrap()) = match method.receiver_mutability {
ReceiverMutability::Const => parse_quote!(&self),
@@ -1111,7 +1028,7 @@
#(#mains)*
}
});
- materializations.push(Use::SpecificNameFromBindgen(supers_name));
+ materializations.push(Use::SpecificNameFromBindgen(supers_name.into()));
} else {
bindgen_mod_items.push(parse_quote! {
#[allow(non_snake_case)]
@@ -1120,7 +1037,7 @@
}
});
}
- materializations.push(Use::SpecificNameFromBindgen(methods_name));
+ materializations.push(Use::SpecificNameFromBindgen(methods_name.into()));
}
}
@@ -1150,8 +1067,8 @@
/// Generates something in the output mod that will carry a docstring
/// explaining why a given type or function couldn't have bindings
/// generated.
- fn generate_error_entry(err: ConvertError, ctx: ErrorContext) -> RsCodegenResult {
- let err = format!("autocxx bindings couldn't be generated: {}", err);
+ fn generate_error_entry(err: ConvertErrorFromCpp, ctx: ErrorContext) -> RsCodegenResult {
+ let err = format!("autocxx bindings couldn't be generated: {err}");
let (impl_entry, bindgen_mod_item, materialization) = match ctx.into_type() {
ErrorContextType::Item(id) => (
// Populate within bindgen mod because impl blocks may attach.
@@ -1160,7 +1077,7 @@
#[doc = #err]
pub struct #id;
}),
- Some(Use::SpecificNameFromBindgen(id)),
+ Some(Use::SpecificNameFromBindgen(id.into())),
),
ErrorContextType::SanitizedItem(id) => (
// Guaranteed to be no impl blocks - populate directly in output mod.
@@ -1218,7 +1135,7 @@
}
fn generate_extern_type_impl(&self, type_kind: TypeKind, tyname: &QualifiedName) -> Vec<Item> {
- let tynamestring = namespaced_name_using_original_name_map(tyname, &self.original_name_map);
+ let tynamestring = self.original_name_map.map(tyname);
let fulltypath = tyname.get_bindgen_path_idents();
let kind_item = match type_kind {
TypeKind::Pod => "Trivial",
@@ -1292,7 +1209,7 @@
ForeignItem::Verbatim(for_extern_c_ts)
}
- fn find_output_mod_root(ns: &Namespace) -> impl Iterator<Item = Ident> {
+ fn find_output_mod_root(ns: &Namespace) -> impl Iterator<Item = crate::minisyn::Ident> {
std::iter::repeat(make_ident("super")).take(ns.depth())
}
}
diff --git a/third_party/autocxx/engine/src/conversion/codegen_rs/non_pod_struct.rs b/third_party/autocxx/engine/src/conversion/codegen_rs/non_pod_struct.rs
index e4bec2f..d9a75c8 100644
--- a/third_party/autocxx/engine/src/conversion/codegen_rs/non_pod_struct.rs
+++ b/third_party/autocxx/engine/src/conversion/codegen_rs/non_pod_struct.rs
@@ -55,7 +55,7 @@
let doc_attr = s
.attrs
.iter()
- .filter(|a| a.path.get_ident().iter().any(|p| *p == "doc"))
+ .filter(|a| a.path().get_ident().iter().any(|p| *p == "doc"))
.cloned();
let repr_attr = if let Some(layout) = &layout {
let align = make_lit_int(layout.align);
@@ -85,9 +85,9 @@
.filter_map(|(counter, gp)| match gp {
GenericParam::Type(gpt) => {
let id = &gpt.ident;
- let field_name = make_ident(&format!("_phantom_{}", counter));
+ let field_name = make_ident(format!("_phantom_{counter}"));
let toks = quote! {
- #field_name: ::std::marker::PhantomData<::std::cell::UnsafeCell< #id >>
+ #field_name: ::core::marker::PhantomData<::core::cell::UnsafeCell< #id >>
};
Some(Field::parse_named.parse2(toks).unwrap())
}
diff --git a/third_party/autocxx/engine/src/conversion/conversion_tests.rs b/third_party/autocxx/engine/src/conversion/conversion_tests.rs
index b0474d6..e74888e 100644
--- a/third_party/autocxx/engine/src/conversion/conversion_tests.rs
+++ b/third_party/autocxx/engine/src/conversion/conversion_tests.rs
@@ -11,7 +11,7 @@
use syn::parse_quote;
use syn::ItemMod;
-use crate::CppCodegenOptions;
+use crate::CodegenOptions;
use super::BridgeConverter;
@@ -33,7 +33,8 @@
input,
UnsafePolicy::AllFunctionsSafe,
inclusions,
- &CppCodegenOptions::default(),
+ &CodegenOptions::default(),
+ "",
)
.unwrap();
}
diff --git a/third_party/autocxx/engine/src/conversion/convert_error.rs b/third_party/autocxx/engine/src/conversion/convert_error.rs
index ba8344d..855b235 100644
--- a/third_party/autocxx/engine/src/conversion/convert_error.rs
+++ b/third_party/autocxx/engine/src/conversion/convert_error.rs
@@ -8,19 +8,35 @@
use indexmap::set::IndexSet as HashSet;
+use crate::minisyn::Ident;
use itertools::Itertools;
-use syn::Ident;
+use miette::{Diagnostic, SourceSpan};
+use proc_macro2::Span;
use thiserror::Error;
use crate::{
- known_types,
- types::{make_ident, Namespace, QualifiedName},
+ known_types, proc_macro_span_to_miette_span,
+ types::{make_ident, InvalidIdentError, Namespace, QualifiedName},
};
-#[derive(Debug, Clone, Error)]
+/// Errors which can occur during conversion
+#[derive(Debug, Clone, Error, Diagnostic)]
pub enum ConvertError {
#[error("The initial run of 'bindgen' did not generate any content. This might be because none of the requested items for generation could be converted.")]
NoContent,
+ #[error(transparent)]
+ Cpp(ConvertErrorFromCpp),
+ #[error(transparent)]
+ #[diagnostic(transparent)]
+ Rust(LocatedConvertErrorFromRust),
+}
+
+/// Errors that can occur during conversion which are detected from some C++
+/// source code. Currently, we do not gain span information from bindgen
+/// so these errors are presented without useful source code snippets.
+/// We hope to change this in future.
+#[derive(Debug, Clone, Error)]
+pub enum ConvertErrorFromCpp {
#[error("An item was requested using 'generate_pod' which was not safe to hold by value in Rust. {0}")]
UnsafePodType(String),
#[error("Bindgen generated some unexpected code in a foreign mod section. You may have specified something in a 'generate' directive which is not currently compatible with autocxx.")]
@@ -39,8 +55,14 @@
ConflictingTemplatedArgsWithTypedef(QualifiedName),
#[error("Function {0} has a parameter or return type which is either on the blocklist or a forward declaration")]
UnacceptableParam(String),
- #[error("Function {0} has a return reference parameter, but 0 or >1 input reference parameters, so the lifetime of the output reference cannot be deduced.")]
- NotOneInputReference(String),
+ #[error("Function {0} has a reference return value, but no reference parameters, so the lifetime of the output reference cannot be deduced.")]
+ NoInputReference(String),
+ #[error("Function {0} has a reference return value, but >1 input reference parameters, so the lifetime of the output reference cannot be deduced.")]
+ MultipleInputReferences(String),
+ #[error("Function {0} has a mutable reference return value, but no mutable reference parameters, so the lifetime of the output reference cannot be deduced.")]
+ NoMutableInputReference(String),
+ #[error("Function {0} has a mutable reference return value, but >1 input mutable reference parameters, so the lifetime of the output reference cannot be deduced.")]
+ MultipleMutableInputReferences(String),
#[error("Encountered type not yet supported by autocxx: {0}")]
UnsupportedType(String),
#[error("Encountered type not yet known by autocxx: {0}")]
@@ -53,8 +75,12 @@
UnexpectedUseStatement(Option<String>),
#[error("Type {} was parameterized over something complex which we don't yet support", .0.to_cpp_name())]
TemplatedTypeContainingNonPathArg(QualifiedName),
- #[error("Pointer pointed to something unsupported")]
- InvalidPointee,
+ #[error("Pointer pointed to an array, which is not yet supported")]
+ InvalidArrayPointee,
+ #[error("Pointer pointed to another pointer, which is not yet supported")]
+ InvalidPointerPointee,
+ #[error("Pointer pointed to something unsupported (autocxx only supports pointers to named types): {0}")]
+ InvalidPointee(String),
#[error("The 'generate' or 'generate_pod' directive for '{0}' did not result in any code being generated. Perhaps this was mis-spelled or you didn't qualify the name with any namespaces? Otherwise please report a bug.")]
DidNotGenerateAnything(String),
#[error("Found an attempt at using a forward declaration ({}) inside a templated cxx type such as UniquePtr or CxxVector. If the forward declaration is a typedef, perhaps autocxx wasn't sure whether or not it involved a forward declaration. If you're sure it didn't, then you may be able to solve this by using instantiable!.", .0.to_cpp_name())]
@@ -63,14 +89,12 @@
Blocked(QualifiedName),
#[error("This function or method uses a type where one of the template parameters was incomprehensible to bindgen/autocxx - probably because it uses template specialization.")]
UnusedTemplateParam,
- #[error("Names containing __ are reserved by C++ so not acceptable to cxx")]
- TooManyUnderscores,
#[error("This item relies on a type not known to autocxx ({})", .0.to_cpp_name())]
UnknownDependentType(QualifiedName),
#[error("This item depends on some other type(s) which autocxx could not generate, some of them are: {}", .0.iter().join(", "))]
IgnoredDependent(HashSet<QualifiedName>),
- #[error("The item name '{0}' is a reserved word in Rust.")]
- ReservedName(String),
+ #[error(transparent)]
+ InvalidIdent(InvalidIdentError),
#[error("This item name is used in multiple namespaces. At present, autocxx and cxx allow only one type of a given name. This limitation will be fixed in future. (Items found with this name: {})", .0.iter().join(", "))]
DuplicateCxxBridgeName(Vec<String>),
#[error("This is a method on a type which can't be used as the receiver in Rust (i.e. self/this). This is probably because some type involves template specialization.")]
@@ -123,29 +147,71 @@
MethodInAnonymousNamespace,
#[error("We're unable to make a concrete version of this template, because we found an error handling the template.")]
ConcreteVersionOfIgnoredTemplate,
- #[error("bindgen decided to call this type _bindgen_ty_N because it couldn't deduce the correct name for it. That means we can't generate C++ bindings to it.")]
- BindgenTy,
#[error("This is a typedef to a type in an anonymous namespace, not currently supported.")]
TypedefToTypeInAnonymousNamespace,
#[error("This type refers to a generic type parameter of an outer type, which is not yet supported.")]
ReferringToGenericTypeParam,
#[error("This forward declaration was nested within another struct/class. autocxx is unable to represent inner types if they are forward declarations.")]
ForwardDeclaredNestedType,
+ #[error("Problem handling function argument {arg}: {err}")]
+ Argument {
+ arg: String,
+ #[source]
+ err: Box<ConvertErrorFromCpp>,
+ },
+}
+
+/// Error types derived from Rust code. This is separate from [`ConvertError`] because these
+/// may have spans attached for better diagnostics.
+#[derive(Debug, Clone, Error)]
+pub enum ConvertErrorFromRust {
+ #[error("extern_rust_function only supports limited parameter and return types. This is not such a supported type")]
+ UnsupportedTypeForExternFun,
+ #[error("extern_rust_function requires a fully qualified receiver, that is: fn a(self: &SomeType) as opposed to fn a(&self)")]
+ ExternRustFunRequiresFullyQualifiedReceiver,
+ #[error("extern_rust_function cannot support &mut T references; instead use Pin<&mut T> (see cxx documentation for more details")]
+ PinnedReferencesRequiredForExternFun,
+ #[error("extern_rust_function cannot currently support qualified type paths (that is, foo::bar::Baz). All type paths must be within the current module, imported using 'use'. This restriction may be lifted in future.")]
+ NamespacesNotSupportedForExternFun,
+ #[error("extern_rust_function signatures must never reference Self: instead, spell out the type explicitly.")]
+ ExplicitSelf,
+}
+
+/// A [`ConvertErrorFromRust`] which also implements [`miette::Diagnostic`] so can be pretty-printed
+/// to show the affected span of code.
+#[derive(Error, Debug, Diagnostic, Clone)]
+#[error("{err}")]
+pub struct LocatedConvertErrorFromRust {
+ err: ConvertErrorFromRust,
+ #[source_code]
+ file: String,
+ #[label("error here")]
+ span: SourceSpan,
+}
+
+impl LocatedConvertErrorFromRust {
+ pub(crate) fn new(err: ConvertErrorFromRust, span: &Span, file: &str) -> Self {
+ Self {
+ err,
+ span: proc_macro_span_to_miette_span(span),
+ file: file.to_string(),
+ }
+ }
}
/// Ensures that error contexts are always created using the constructors in this
/// mod, therefore undergoing identifier sanitation.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
struct PhantomSanitized;
/// The context of an error, e.g. whether it applies to a function or a method.
/// This is used to generate suitable rustdoc in the output codegen so that
/// the errors can be revealed in rust-analyzer-based IDEs, etc.
-#[derive(Clone)]
-pub(crate) struct ErrorContext(ErrorContextType, PhantomSanitized);
+#[derive(Clone, Debug)]
+pub(crate) struct ErrorContext(Box<ErrorContextType>, PhantomSanitized);
/// All idents in this structure are guaranteed to be something we can safely codegen for.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub(crate) enum ErrorContextType {
Item(Ident),
SanitizedItem(Ident),
@@ -155,8 +221,11 @@
impl ErrorContext {
pub(crate) fn new_for_item(id: Ident) -> Self {
match Self::sanitize_error_ident(&id) {
- None => Self(ErrorContextType::Item(id), PhantomSanitized),
- Some(sanitized) => Self(ErrorContextType::SanitizedItem(sanitized), PhantomSanitized),
+ None => Self(Box::new(ErrorContextType::Item(id)), PhantomSanitized),
+ Some(sanitized) => Self(
+ Box::new(ErrorContextType::SanitizedItem(sanitized)),
+ PhantomSanitized,
+ ),
}
}
@@ -166,14 +235,16 @@
// an impl block.
match Self::sanitize_error_ident(&self_ty) {
None => Self(
- ErrorContextType::Method {
+ Box::new(ErrorContextType::Method {
self_ty,
method: Self::sanitize_error_ident(&method).unwrap_or(method),
- },
+ }),
PhantomSanitized,
),
Some(_) => Self(
- ErrorContextType::SanitizedItem(make_ident(format!("{}_{}", self_ty, method))),
+ Box::new(ErrorContextType::SanitizedItem(make_ident(format!(
+ "{self_ty}_{method}"
+ )))),
PhantomSanitized,
),
}
@@ -195,21 +266,24 @@
}
pub(crate) fn into_type(self) -> ErrorContextType {
- self.0
+ *self.0
}
}
impl std::fmt::Display for ErrorContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match &self.0 {
- ErrorContextType::Item(id) | ErrorContextType::SanitizedItem(id) => write!(f, "{}", id),
- ErrorContextType::Method { self_ty, method } => write!(f, "{}::{}", self_ty, method),
+ match &*self.0 {
+ ErrorContextType::Item(id) | ErrorContextType::SanitizedItem(id) => write!(f, "{id}"),
+ ErrorContextType::Method { self_ty, method } => write!(f, "{self_ty}::{method}"),
}
}
}
#[derive(Clone)]
-pub(crate) struct ConvertErrorWithContext(pub(crate) ConvertError, pub(crate) Option<ErrorContext>);
+pub(crate) struct ConvertErrorWithContext(
+ pub(crate) ConvertErrorFromCpp,
+ pub(crate) Option<ErrorContext>,
+);
impl std::fmt::Debug for ConvertErrorWithContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
diff --git a/third_party/autocxx/engine/src/conversion/doc_attr.rs b/third_party/autocxx/engine/src/conversion/doc_attr.rs
index 8fe9d0b..7a44f9b 100644
--- a/third_party/autocxx/engine/src/conversion/doc_attr.rs
+++ b/third_party/autocxx/engine/src/conversion/doc_attr.rs
@@ -12,7 +12,7 @@
pub(super) fn get_doc_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
attrs
.iter()
- .filter(|a| a.path.get_ident().iter().any(|p| *p == "doc"))
+ .filter(|a| a.path().get_ident().iter().any(|p| *p == "doc"))
.cloned()
.collect()
}
diff --git a/third_party/autocxx/engine/src/conversion/error_reporter.rs b/third_party/autocxx/engine/src/conversion/error_reporter.rs
index 7942a32..adea153 100644
--- a/third_party/autocxx/engine/src/conversion/error_reporter.rs
+++ b/third_party/autocxx/engine/src/conversion/error_reporter.rs
@@ -6,13 +6,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use syn::ItemEnum;
+use crate::minisyn::ItemEnum;
use super::{
api::{AnalysisPhase, Api, ApiName, FuncToConvert, StructDetails, TypedefKind},
apivec::ApiVec,
convert_error::{ConvertErrorWithContext, ErrorContext},
- ConvertError,
+ ConvertErrorFromCpp,
};
use crate::{
conversion::convert_error::ErrorContextType,
@@ -33,7 +33,7 @@
match fun() {
Ok(result) => Some(result),
Err(ConvertErrorWithContext(err, None)) => {
- eprintln!("Ignored item: {}", err);
+ eprintln!("Ignored item: {err}");
None
}
Err(ConvertErrorWithContext(err, Some(ctx))) => {
@@ -127,11 +127,11 @@
Api::RustFn {
name,
details,
- receiver,
+ deps,
} => Ok(Box::new(std::iter::once(Api::RustFn {
name,
details,
- receiver,
+ deps,
}))),
Api::RustSubclassFn {
name,
@@ -210,7 +210,7 @@
out_apis: &mut ApiVec<B>,
mut fun: F,
) where
- F: FnMut(Api<A>) -> Result<Box<dyn Iterator<Item = Api<B>>>, ConvertError>,
+ F: FnMut(Api<A>) -> Result<Box<dyn Iterator<Item = Api<B>>>, ConvertErrorFromCpp>,
A: AnalysisPhase,
B: AnalysisPhase,
{
diff --git a/third_party/autocxx/engine/src/conversion/mod.rs b/third_party/autocxx/engine/src/conversion/mod.rs
index aa639a2..61d7d6d 100644
--- a/third_party/autocxx/engine/src/conversion/mod.rs
+++ b/third_party/autocxx/engine/src/conversion/mod.rs
@@ -17,18 +17,18 @@
mod doc_attr;
mod error_reporter;
mod parse;
+mod type_helpers;
mod utilities;
use analysis::fun::FnAnalyzer;
use autocxx_parser::IncludeCppConfig;
pub(crate) use codegen_cpp::CppCodeGenerator;
pub(crate) use convert_error::ConvertError;
+use convert_error::ConvertErrorFromCpp;
use itertools::Itertools;
use syn::{Item, ItemMod};
-use crate::{
- conversion::analysis::deps::HasDependencies, CppCodegenOptions, CppFilePair, UnsafePolicy,
-};
+use crate::{CodegenOptions, CppFilePair, UnsafePolicy};
use self::{
analysis::{
@@ -37,7 +37,6 @@
casts::add_casts,
check_names,
constructor_deps::decorate_types_with_constructor_deps,
- fun::FnPhase,
gc::filter_apis_by_following_edges_from_allowlist,
pod::analyze_pod_apis,
remove_ignored::filter_apis_by_ignored_dependents,
@@ -87,23 +86,10 @@
fn dump_apis<T: AnalysisPhase>(label: &str, apis: &ApiVec<T>) {
if LOG_APIS {
log::info!(
- "APIs after {}:\n{}",
+ "##### APIs after {}:\n{}",
label,
apis.iter()
- .map(|api| { format!(" {:?}", api) })
- .sorted()
- .join("\n")
- )
- }
- }
-
- fn dump_apis_with_deps(label: &str, apis: &ApiVec<FnPhase>) {
- if LOG_APIS {
- log::info!(
- "APIs after {}:\n{}",
- label,
- apis.iter()
- .map(|api| { format!(" {:?}, deps={}", api, api.format_deps()) })
+ .map(|api| { format!(" {api:?}") })
.sorted()
.join("\n")
)
@@ -121,7 +107,8 @@
mut bindgen_mod: ItemMod,
unsafe_policy: UnsafePolicy,
inclusions: String,
- cpp_codegen_options: &CppCodegenOptions,
+ codegen_options: &CodegenOptions,
+ source_file_contents: &str,
) -> Result<CodegenResults, ConvertError> {
match &mut bindgen_mod.content {
None => Err(ConvertError::NoContent),
@@ -129,7 +116,7 @@
// Parse the bindgen mod.
let items_to_process = items.drain(..).collect();
let parser = ParseBindgen::new(self.config);
- let apis = parser.parse_items(items_to_process)?;
+ let apis = parser.parse_items(items_to_process, source_file_contents)?;
Self::dump_apis("parsing", &apis);
// Inside parse_results, we now have a list of APIs.
// We now enter various analysis phases.
@@ -143,9 +130,9 @@
// Specifically, let's confirm that the items requested by the user to be
// POD really are POD, and duly mark any dependent types.
// This returns a new list of `Api`s, which will be parameterized with
- // the analysis results. It also returns an object which can be used
- // by subsequent phases to work out which objects are POD.
- let analyzed_apis = analyze_pod_apis(apis, self.config)?;
+ // the analysis results.
+ let analyzed_apis =
+ analyze_pod_apis(apis, self.config).map_err(ConvertError::Cpp)?;
Self::dump_apis("pod analysis", &analyzed_apis);
let analyzed_apis = replace_hopeless_typedef_targets(self.config, analyzed_apis);
let analyzed_apis = add_casts(analyzed_apis);
@@ -156,8 +143,12 @@
// part of `autocxx`. Again, this returns a new set of `Api`s, but
// parameterized by a richer set of metadata.
Self::dump_apis("adding casts", &analyzed_apis);
- let analyzed_apis =
- FnAnalyzer::analyze_functions(analyzed_apis, &unsafe_policy, self.config);
+ let analyzed_apis = FnAnalyzer::analyze_functions(
+ analyzed_apis,
+ &unsafe_policy,
+ self.config,
+ codegen_options.force_wrapper_gen,
+ );
// If any of those functions turned out to be pure virtual, don't attempt
// to generate UniquePtr implementations for the type, since it can't
// be instantiated.
@@ -167,9 +158,9 @@
// Annotate structs with a note of any copy/move constructors which
// we may want to retain to avoid garbage collecting them later.
let analyzed_apis = decorate_types_with_constructor_deps(analyzed_apis);
- Self::dump_apis_with_deps("adding constructor deps", &analyzed_apis);
+ Self::dump_apis("adding constructor deps", &analyzed_apis);
let analyzed_apis = discard_ignored_functions(analyzed_apis);
- Self::dump_apis_with_deps("ignoring ignorable fns", &analyzed_apis);
+ Self::dump_apis("ignoring ignorable fns", &analyzed_apis);
// Remove any APIs whose names are not compatible with cxx.
let analyzed_apis = check_names(analyzed_apis);
// During parsing or subsequent processing we might have encountered
@@ -177,24 +168,28 @@
// There might be other items depending on such things. Let's remove them
// too.
let analyzed_apis = filter_apis_by_ignored_dependents(analyzed_apis);
- Self::dump_apis_with_deps("removing ignored dependents", &analyzed_apis);
+ Self::dump_apis("removing ignored dependents", &analyzed_apis);
// We now garbage collect the ones we don't need...
let mut analyzed_apis =
filter_apis_by_following_edges_from_allowlist(analyzed_apis, self.config);
// Determine what variably-sized C types (e.g. int) we need to include
analysis::ctypes::append_ctype_information(&mut analyzed_apis);
- Self::dump_apis_with_deps("GC", &analyzed_apis);
+ Self::dump_apis("GC", &analyzed_apis);
// And finally pass them to the code gen phases, which outputs
// code suitable for cxx to consume.
- let cxxgen_header_name = cpp_codegen_options.cxxgen_header_namer.name_header();
+ let cxxgen_header_name = codegen_options
+ .cpp_codegen_options
+ .cxxgen_header_namer
+ .name_header();
let cpp = CppCodeGenerator::generate_cpp_code(
inclusions,
&analyzed_apis,
self.config,
- cpp_codegen_options,
+ &codegen_options.cpp_codegen_options,
&cxxgen_header_name,
- )?;
+ )
+ .map_err(ConvertError::Cpp)?;
let rs = RsCodeGenerator::generate_rs_code(
analyzed_apis,
&unsafe_policy,
diff --git a/third_party/autocxx/engine/src/conversion/parse/bindgen_semantic_attributes.rs b/third_party/autocxx/engine/src/conversion/parse/bindgen_semantic_attributes.rs
index a8de9ce..f2dd7d7 100644
--- a/third_party/autocxx/engine/src/conversion/parse/bindgen_semantic_attributes.rs
+++ b/third_party/autocxx/engine/src/conversion/parse/bindgen_semantic_attributes.rs
@@ -14,9 +14,9 @@
};
use crate::conversion::{
- api::{CppVisibility, Layout, References, SpecialMemberKind, Virtualness},
+ api::{CppVisibility, DeletedOrDefaulted, Layout, References, SpecialMemberKind, Virtualness},
convert_error::{ConvertErrorWithContext, ErrorContext},
- ConvertError,
+ ConvertErrorFromCpp,
};
/// The set of all annotations that autocxx_bindgen has added
@@ -31,7 +31,7 @@
// item can't be processed.
pub(crate) fn new_retaining_others(attrs: &mut Vec<Attribute>) -> Self {
let metadata = Self::new(attrs);
- attrs.retain(|a| a.path.segments.last().unwrap().ident != "cpp_semantics");
+ attrs.retain(|a| a.path().segments.last().unwrap().ident != "cpp_semantics");
metadata
}
@@ -40,7 +40,7 @@
attrs
.iter()
.filter_map(|attr| {
- if attr.path.segments.last().unwrap().ident == "cpp_semantics" {
+ if attr.path().segments.last().unwrap().ident == "cpp_semantics" {
let r: Result<BindgenSemanticAttribute, syn::Error> = attr.parse_args();
r.ok()
} else {
@@ -58,13 +58,13 @@
) -> Result<(), ConvertErrorWithContext> {
if self.has_attr("unused_template_param") {
Err(ConvertErrorWithContext(
- ConvertError::UnusedTemplateParam,
- Some(ErrorContext::new_for_item(id_for_context.clone())),
+ ConvertErrorFromCpp::UnusedTemplateParam,
+ Some(ErrorContext::new_for_item(id_for_context.clone().into())),
))
} else if self.get_cpp_visibility() != CppVisibility::Public {
Err(ConvertErrorWithContext(
- ConvertError::NonPublicNestedType,
- Some(ErrorContext::new_for_item(id_for_context.clone())),
+ ConvertErrorFromCpp::NonPublicNestedType,
+ Some(ErrorContext::new_for_item(id_for_context.clone().into())),
))
} else {
Ok(())
@@ -98,6 +98,16 @@
}
}
+ pub(super) fn get_deleted_or_defaulted(&self) -> DeletedOrDefaulted {
+ if self.has_attr("deleted") {
+ DeletedOrDefaulted::Deleted
+ } else if self.has_attr("defaulted") {
+ DeletedOrDefaulted::Defaulted
+ } else {
+ DeletedOrDefaulted::Neither
+ }
+ }
+
fn parse_if_present<T: Parse>(&self, annotation: &str) -> Option<T> {
self.0
.iter()
@@ -144,12 +154,12 @@
} else if a.is_ident("arg_type_reference") {
let r: Result<Ident, syn::Error> = a.parse_args();
if let Ok(ls) = r {
- results.ref_params.insert(ls);
+ results.ref_params.insert(ls.into());
}
} else if a.is_ident("arg_type_rvalue_reference") {
let r: Result<Ident, syn::Error> = a.parse_args();
if let Ok(ls) = r {
- results.rvalue_ref_params.insert(ls);
+ results.rvalue_ref_params.insert(ls.into());
}
}
}
diff --git a/third_party/autocxx/engine/src/conversion/parse/extern_fun_signatures.rs b/third_party/autocxx/engine/src/conversion/parse/extern_fun_signatures.rs
new file mode 100644
index 0000000..cb002b5
--- /dev/null
+++ b/third_party/autocxx/engine/src/conversion/parse/extern_fun_signatures.rs
@@ -0,0 +1,253 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use indexmap::IndexSet as HashSet;
+
+use syn::{
+ spanned::Spanned, AngleBracketedGenericArguments, GenericArgument, PatType, PathArguments,
+ PathSegment, ReturnType, Signature, Type, TypePath, TypeReference,
+};
+
+use crate::{
+ conversion::convert_error::{ConvertErrorFromRust, LocatedConvertErrorFromRust},
+ types::QualifiedName,
+};
+
+pub(super) fn assemble_extern_fun_deps(
+ sig: &Signature,
+ file: &str,
+) -> Result<Vec<QualifiedName>, LocatedConvertErrorFromRust> {
+ let mut deps = HashSet::new();
+ // It's possible that this will need to be implemented using TypeConverter
+ // and the encountered_types field on its annotated results.
+ // But the design of that code is intended to convert from C++ types
+ // (via bindgen) to cxx types, and instead here we're starting with pure
+ // Rust types as written by a Rustacean human. It may therefore not
+ // be quite right to go via TypeConverter.
+ // Also, by doing it ourselves here, we're in a better place to emit
+ // meaningful errors about types which can't be supported within
+ // extern_rust_fun.
+ if let ReturnType::Type(_, ty) = &sig.output {
+ add_type_to_deps(ty, &mut deps, file)?;
+ }
+ for input in &sig.inputs {
+ match input {
+ syn::FnArg::Receiver(_) => {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::ExternRustFunRequiresFullyQualifiedReceiver,
+ &input.span(),
+ file,
+ ))
+ }
+ syn::FnArg::Typed(PatType { ty, .. }) => add_type_to_deps(ty, &mut deps, file)?,
+ }
+ }
+ Ok(deps.into_iter().collect())
+}
+
+/// For all types within an extern_rust_function signature, add them to the deps
+/// hash, or raise an appropriate error.
+fn add_type_to_deps(
+ ty: &Type,
+ deps: &mut HashSet<QualifiedName>,
+ file: &str,
+) -> Result<(), LocatedConvertErrorFromRust> {
+ match ty {
+ Type::Reference(TypeReference {
+ mutability: Some(_),
+ ..
+ }) => {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::PinnedReferencesRequiredForExternFun,
+ &ty.span(),
+ file,
+ ))
+ }
+ Type::Reference(TypeReference { elem, .. }) => match &**elem {
+ Type::Path(tp) => add_path_to_deps(tp, deps, file)?,
+ _ => {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &ty.span(),
+ file,
+ ))
+ }
+ },
+ Type::Path(tp) => {
+ if tp.path.segments.len() != 1 {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::NamespacesNotSupportedForExternFun,
+ &tp.span(),
+ file,
+ ));
+ }
+ if let Some(PathSegment {
+ ident,
+ arguments:
+ PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }),
+ }) = tp.path.segments.last()
+ {
+ if ident == "Pin" {
+ if args.len() != 1 {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &tp.span(),
+ file,
+ ));
+ }
+
+ if let Some(GenericArgument::Type(Type::Reference(TypeReference {
+ mutability: Some(_),
+ elem,
+ ..
+ }))) = args.first()
+ {
+ if let Type::Path(tp) = &**elem {
+ add_path_to_deps(tp, deps, file)?
+ } else {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &elem.span(),
+ file,
+ ));
+ }
+ } else {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &ty.span(),
+ file,
+ ));
+ }
+ } else if ident == "Box" || ident == "Vec" {
+ if args.len() != 1 {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &tp.span(),
+ file,
+ ));
+ }
+ if let Some(GenericArgument::Type(Type::Path(tp))) = args.first() {
+ add_path_to_deps(tp, deps, file)?
+ } else {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &ty.span(),
+ file,
+ ));
+ }
+ } else {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &ident.span(),
+ file,
+ ));
+ }
+ } else {
+ add_path_to_deps(tp, deps, file)?
+ }
+ }
+ _ => {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &ty.span(),
+ file,
+ ))
+ }
+ };
+ Ok(())
+}
+
+fn add_path_to_deps(
+ type_path: &TypePath,
+ deps: &mut HashSet<QualifiedName>,
+ file: &str,
+) -> Result<(), LocatedConvertErrorFromRust> {
+ if let Some(PathSegment {
+ arguments: PathArguments::AngleBracketed(..) | PathArguments::Parenthesized(..),
+ ..
+ }) = type_path.path.segments.last()
+ {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::UnsupportedTypeForExternFun,
+ &type_path.span(),
+ file,
+ ));
+ }
+ let qn = QualifiedName::from_type_path(type_path);
+ if !qn.get_namespace().is_empty() {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::NamespacesNotSupportedForExternFun,
+ &type_path.span(),
+ file,
+ ));
+ }
+ if qn.get_final_item() == "Self" {
+ return Err(LocatedConvertErrorFromRust::new(
+ ConvertErrorFromRust::ExplicitSelf,
+ &type_path.span(),
+ file,
+ ));
+ }
+ deps.insert(qn);
+ Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+ use syn::parse_quote;
+
+ use super::*;
+
+ fn run_test_expect_ok(sig: Signature, expected_deps: &[&str]) {
+ let expected_as_set: HashSet<QualifiedName> = expected_deps
+ .iter()
+ .cloned()
+ .map(QualifiedName::new_from_cpp_name)
+ .collect();
+ let result = assemble_extern_fun_deps(&sig, "").unwrap();
+ let actual_as_set: HashSet<QualifiedName> = result.into_iter().collect();
+ assert_eq!(expected_as_set, actual_as_set);
+ }
+
+ fn run_test_expect_fail(sig: Signature) {
+ assert!(assemble_extern_fun_deps(&sig, "").is_err())
+ }
+
+ #[test]
+ fn test_assemble_extern_fun_deps() {
+ run_test_expect_fail(parse_quote! { fn function(self: A::B)});
+ run_test_expect_fail(parse_quote! { fn function(self: Self)});
+ run_test_expect_fail(parse_quote! { fn function(self: Self)});
+ run_test_expect_fail(parse_quote! { fn function(self)});
+ run_test_expect_fail(parse_quote! { fn function(&self)});
+ run_test_expect_fail(parse_quote! { fn function(&mut self)});
+ run_test_expect_fail(parse_quote! { fn function(self: Pin<&mut Self>)});
+ run_test_expect_fail(parse_quote! { fn function(self: Pin<&mut A::B>)});
+ run_test_expect_fail(parse_quote! { fn function(a: Pin<A>)});
+ run_test_expect_fail(parse_quote! { fn function(a: Pin<A::B>)});
+ run_test_expect_fail(parse_quote! { fn function(a: A::B)});
+ run_test_expect_fail(parse_quote! { fn function(a: &mut A)});
+ run_test_expect_fail(parse_quote! { fn function() -> A::B});
+ run_test_expect_fail(parse_quote! { fn function() -> &A::B});
+ run_test_expect_fail(parse_quote! { fn function(a: ())});
+ run_test_expect_fail(parse_quote! { fn function(a: &[A])});
+ run_test_expect_fail(parse_quote! { fn function(a: Bob<A>)});
+ run_test_expect_fail(parse_quote! { fn function(a: Box<A, B>)});
+ run_test_expect_fail(parse_quote! { fn function(a: a::Pin<&mut A>)});
+ run_test_expect_fail(parse_quote! { fn function(a: Pin<&A>)});
+ run_test_expect_ok(parse_quote! { fn function(a: A, b: B)}, &["A", "B"]);
+ run_test_expect_ok(parse_quote! { fn function(a: Box<A>)}, &["A"]);
+ run_test_expect_ok(parse_quote! { fn function(a: Vec<A>)}, &["A"]);
+ run_test_expect_ok(parse_quote! { fn function(a: &A)}, &["A"]);
+ run_test_expect_ok(parse_quote! { fn function(a: Pin<&mut A>)}, &["A"]);
+ run_test_expect_ok(
+ parse_quote! { fn function(a: A, b: B) -> Box<C>},
+ &["A", "B", "C"],
+ );
+ }
+}
diff --git a/third_party/autocxx/engine/src/conversion/parse/mod.rs b/third_party/autocxx/engine/src/conversion/parse/mod.rs
index 3f42ce4..b4f2e07 100644
--- a/third_party/autocxx/engine/src/conversion/parse/mod.rs
+++ b/third_party/autocxx/engine/src/conversion/parse/mod.rs
@@ -7,6 +7,7 @@
// except according to those terms.
mod bindgen_semantic_attributes;
+mod extern_fun_signatures;
mod parse_bindgen;
mod parse_foreign_mod;
diff --git a/third_party/autocxx/engine/src/conversion/parse/parse_bindgen.rs b/third_party/autocxx/engine/src/conversion/parse/parse_bindgen.rs
index 2d4e3de..f499145 100644
--- a/third_party/autocxx/engine/src/conversion/parse/parse_bindgen.rs
+++ b/third_party/autocxx/engine/src/conversion/parse/parse_bindgen.rs
@@ -13,7 +13,8 @@
conversion::{
api::{Api, ApiName, NullPhase, StructDetails, SubclassName, TypedefKind, UnanalyzedApi},
apivec::ApiVec,
- ConvertError,
+ convert_error::LocatedConvertErrorFromRust,
+ ConvertError, ConvertErrorFromCpp,
},
types::Namespace,
types::QualifiedName,
@@ -41,7 +42,7 @@
}
fn api_name(ns: &Namespace, id: Ident, attrs: &BindgenSemanticAttributes) -> ApiName {
- ApiName::new_with_cpp_name(ns, id, attrs.get_original_name())
+ ApiName::new_with_cpp_name(ns, id.into(), attrs.get_original_name())
}
pub(crate) fn api_name_qualified(
@@ -51,8 +52,11 @@
) -> Result<ApiName, ConvertErrorWithContext> {
match validate_ident_ok_for_cxx(&id.to_string()) {
Err(e) => {
- let ctx = ErrorContext::new_for_item(id);
- Err(ConvertErrorWithContext(e, Some(ctx)))
+ let ctx = ErrorContext::new_for_item(id.into());
+ Err(ConvertErrorWithContext(
+ ConvertErrorFromCpp::InvalidIdent(e),
+ Some(ctx),
+ ))
}
Ok(..) => Ok(api_name(ns, id, attrs)),
}
@@ -71,43 +75,49 @@
pub(crate) fn parse_items(
mut self,
items: Vec<Item>,
+ source_file_contents: &str,
) -> Result<ApiVec<NullPhase>, ConvertError> {
- let items = Self::find_items_in_root(items)?;
+ let items = Self::find_items_in_root(items).map_err(ConvertError::Cpp)?;
if !self.config.exclude_utilities() {
generate_utilities(&mut self.apis, self.config);
}
- self.add_apis_from_config();
+ self.add_apis_from_config(source_file_contents)
+ .map_err(ConvertError::Rust)?;
let root_ns = Namespace::new();
self.parse_mod_items(items, root_ns);
- self.confirm_all_generate_directives_obeyed()?;
+ self.confirm_all_generate_directives_obeyed()
+ .map_err(ConvertError::Cpp)?;
self.replace_extern_cpp_types();
Ok(self.apis)
}
/// Some API items are not populated from bindgen output, but instead
/// directly from items in the config.
- fn add_apis_from_config(&mut self) {
+ fn add_apis_from_config(
+ &mut self,
+ source_file_contents: &str,
+ ) -> Result<(), LocatedConvertErrorFromRust> {
self.apis
.extend(self.config.subclasses.iter().map(|sc| Api::Subclass {
- name: SubclassName::new(sc.subclass.clone()),
+ name: SubclassName::new(sc.subclass.clone().into()),
superclass: QualifiedName::new_from_cpp_name(&sc.superclass),
}));
- self.apis
- .extend(self.config.extern_rust_funs.iter().map(|fun| {
- let id = fun.sig.ident.clone();
- Api::RustFn {
- name: ApiName::new_in_root_namespace(id),
- details: fun.clone(),
- receiver: fun.receiver.as_ref().map(|receiver_id| {
- QualifiedName::new(&Namespace::new(), receiver_id.clone())
- }),
- }
- }));
+ for fun in &self.config.extern_rust_funs {
+ let id = fun.sig.ident.clone();
+ self.apis.push(Api::RustFn {
+ name: ApiName::new_in_root_namespace(id.into()),
+ details: fun.clone(),
+ deps: super::extern_fun_signatures::assemble_extern_fun_deps(
+ &fun.sig,
+ source_file_contents,
+ )?,
+ })
+ }
let unique_rust_types: HashSet<&RustPath> = self.config.rust_types.iter().collect();
self.apis.extend(unique_rust_types.into_iter().map(|path| {
let id = path.get_final_ident();
Api::RustType {
- name: ApiName::new_in_root_namespace(id.clone()),
+ name: ApiName::new_in_root_namespace(id.clone().into()),
path: path.clone(),
}
}));
@@ -117,7 +127,7 @@
.0
.iter()
.map(|(cpp_definition, rust_id)| {
- let name = ApiName::new_in_root_namespace(rust_id.clone());
+ let name = ApiName::new_in_root_namespace(rust_id.clone().into());
Api::ConcreteType {
name,
cpp_definition: cpp_definition.clone(),
@@ -125,6 +135,7 @@
}
}),
);
+ Ok(())
}
/// We do this last, _after_ we've parsed all the APIs, because we might want to actually
@@ -154,7 +165,7 @@
self.apis.extend(replacements.into_iter().map(|(_, v)| v));
}
- fn find_items_in_root(items: Vec<Item>) -> Result<Vec<Item>, ConvertError> {
+ fn find_items_in_root(items: Vec<Item>) -> Result<Vec<Item>, ConvertErrorFromCpp> {
for item in items {
match item {
Item::Mod(root_mod) => {
@@ -166,7 +177,7 @@
return Ok(items);
}
}
- _ => return Err(ConvertError::UnexpectedOuterItem),
+ _ => return Err(ConvertErrorFromCpp::UnexpectedOuterItem),
}
}
Ok(Vec::new())
@@ -224,8 +235,8 @@
// forward declarations.
if err.is_none() && name.cpp_name().contains("::") {
err = Some(ConvertErrorWithContext(
- ConvertError::ForwardDeclaredNestedType,
- Some(ErrorContext::new_for_item(s.ident)),
+ ConvertErrorFromCpp::ForwardDeclaredNestedType,
+ Some(ErrorContext::new_for_item(s.ident.into())),
));
}
Some(UnanalyzedApi::ForwardDeclaration { name, err })
@@ -237,7 +248,7 @@
name,
details: Box::new(StructDetails {
layout: annotations.get_layout(),
- item: s,
+ item: s.into(),
has_rvalue_reference_fields,
}),
analysis: (),
@@ -254,7 +265,7 @@
let annotations = BindgenSemanticAttributes::new(&e.attrs);
let api = UnanalyzedApi::Enum {
name: api_name_qualified(ns, e.ident.clone(), &annotations)?,
- item: e,
+ item: e.into(),
};
if !self.config.is_on_blocklist(&api.name().to_cpp_name()) {
self.apis.push(api);
@@ -293,7 +304,7 @@
UseTree::Rename(urn) => {
let old_id = &urn.ident;
let new_id = &urn.rename;
- let new_tyname = QualifiedName::new(ns, new_id.clone());
+ let new_tyname = QualifiedName::new(ns, new_id.clone().into());
assert!(segs.remove(0) == "self", "Path didn't start with self");
assert!(
segs.remove(0) == "super",
@@ -309,8 +320,8 @@
let old_tyname = QualifiedName::from_type_path(&old_path);
if new_tyname == old_tyname {
return Err(ConvertErrorWithContext(
- ConvertError::InfinitelyRecursiveTypedef(new_tyname),
- Some(ErrorContext::new_for_item(new_id.clone())),
+ ConvertErrorFromCpp::InfinitelyRecursiveTypedef(new_tyname),
+ Some(ErrorContext::new_for_item(new_id.clone().into())),
));
}
let annotations = BindgenSemanticAttributes::new(&use_item.attrs);
@@ -320,7 +331,7 @@
parse_quote! {
pub use #old_path as #new_id;
},
- Box::new(Type::Path(old_path)),
+ Box::new(Type::Path(old_path).into()),
),
old_tyname: Some(old_tyname),
analysis: (),
@@ -329,7 +340,7 @@
}
_ => {
return Err(ConvertErrorWithContext(
- ConvertError::UnexpectedUseStatement(
+ ConvertErrorFromCpp::UnexpectedUseStatement(
segs.into_iter().last().map(|i| i.to_string()),
),
None,
@@ -341,10 +352,23 @@
}
Item::Const(const_item) => {
let annotations = BindgenSemanticAttributes::new(&const_item.attrs);
- self.apis.push(UnanalyzedApi::Const {
- name: api_name(ns, const_item.ident.clone(), &annotations),
- const_item,
- });
+ // Bindgen generates const expressions for nested unnamed enums,
+ // but autcxx will refuse to expand those enums, making these consts
+ // invalid.
+ let mut enum_type_name_valid = true;
+ if let Type::Path(p) = &*const_item.ty {
+ if let Some(p) = &p.path.segments.last() {
+ if validate_ident_ok_for_cxx(&p.ident.to_string()).is_err() {
+ enum_type_name_valid = false;
+ }
+ }
+ }
+ if enum_type_name_valid {
+ self.apis.push(UnanalyzedApi::Const {
+ name: api_name(ns, const_item.ident.clone(), &annotations),
+ const_item: const_item.into(),
+ });
+ }
Ok(())
}
Item::Type(ity) => {
@@ -353,14 +377,14 @@
// same name - see test_issue_264.
self.apis.push(UnanalyzedApi::Typedef {
name: api_name(ns, ity.ident.clone(), &annotations),
- item: TypedefKind::Type(ity),
+ item: TypedefKind::Type(ity.into()),
old_tyname: None,
analysis: (),
});
Ok(())
}
_ => Err(ConvertErrorWithContext(
- ConvertError::UnexpectedItemInMod,
+ ConvertErrorFromCpp::UnexpectedItemInMod,
None,
)),
}
@@ -380,7 +404,7 @@
.any(|id| id == desired_id)
}
- fn confirm_all_generate_directives_obeyed(&self) -> Result<(), ConvertError> {
+ fn confirm_all_generate_directives_obeyed(&self) -> Result<(), ConvertErrorFromCpp> {
let api_names: HashSet<_> = self
.apis
.iter()
@@ -388,7 +412,9 @@
.collect();
for generate_directive in self.config.must_generate_list() {
if !api_names.contains(&generate_directive) {
- return Err(ConvertError::DidNotGenerateAnything(generate_directive));
+ return Err(ConvertErrorFromCpp::DidNotGenerateAnything(
+ generate_directive,
+ ));
}
}
Ok(())
diff --git a/third_party/autocxx/engine/src/conversion/parse/parse_foreign_mod.rs b/third_party/autocxx/engine/src/conversion/parse/parse_foreign_mod.rs
index 08c1fd8..ea82ff8 100644
--- a/third_party/autocxx/engine/src/conversion/parse/parse_foreign_mod.rs
+++ b/third_party/autocxx/engine/src/conversion/parse/parse_foreign_mod.rs
@@ -15,8 +15,9 @@
convert_error::ConvertErrorWithContext,
convert_error::ErrorContext,
};
+use crate::minisyn::{minisynize_punctuated, minisynize_vec};
use crate::{
- conversion::ConvertError,
+ conversion::ConvertErrorFromCpp,
types::{Namespace, QualifiedName},
};
use std::collections::HashMap;
@@ -72,11 +73,11 @@
self.funcs_to_convert.push(FuncToConvert {
provenance: Provenance::Bindgen,
self_ty: None,
- ident: item.sig.ident,
- doc_attrs,
- inputs: item.sig.inputs,
- output: item.sig.output,
- vis: item.vis,
+ ident: item.sig.ident.into(),
+ doc_attrs: minisynize_vec(doc_attrs),
+ inputs: minisynize_punctuated(item.sig.inputs),
+ output: item.sig.output.into(),
+ vis: item.vis.into(),
virtualness: annotations.get_virtualness(),
cpp_vis: annotations.get_cpp_visibility(),
special_member: annotations.special_member_kind(),
@@ -86,18 +87,18 @@
original_name: annotations.get_original_name(),
synthesized_this_type: None,
add_to_trait: None,
- is_deleted: annotations.has_attr("deleted"),
+ is_deleted: annotations.get_deleted_or_defaulted(),
synthetic_cpp: None,
variadic: item.sig.variadic.is_some(),
});
Ok(())
}
ForeignItem::Static(item) => Err(ConvertErrorWithContext(
- ConvertError::StaticData(item.ident.to_string()),
- Some(ErrorContext::new_for_item(item.ident)),
+ ConvertErrorFromCpp::StaticData(item.ident.to_string()),
+ Some(ErrorContext::new_for_item(item.ident.into())),
)),
_ => Err(ConvertErrorWithContext(
- ConvertError::UnexpectedForeignItem,
+ ConvertErrorFromCpp::UnexpectedForeignItem,
None,
)),
}
@@ -111,14 +112,14 @@
_ => return,
};
for i in imp.items {
- if let ImplItem::Method(itm) = i {
+ if let ImplItem::Fn(itm) = i {
let effective_fun_name = match get_called_function(&itm.block) {
Some(id) => id.clone(),
None => itm.sig.ident,
};
self.method_receivers.insert(
effective_fun_name,
- QualifiedName::new(&self.ns, ty_id.clone()),
+ QualifiedName::new(&self.ns, ty_id.clone().into()),
);
}
}
@@ -151,7 +152,7 @@
/// name of the actual function call inside the block's body.
fn get_called_function(block: &Block) -> Option<&Ident> {
match block.stmts.first() {
- Some(Stmt::Expr(Expr::Call(ExprCall { func, .. }))) => match **func {
+ Some(Stmt::Expr(Expr::Call(ExprCall { func, .. }), _)) => match **func {
Expr::Path(ref exp) => exp.path.segments.first().map(|ps| &ps.ident),
_ => None,
},
diff --git a/third_party/autocxx/engine/src/conversion/type_helpers.rs b/third_party/autocxx/engine/src/conversion/type_helpers.rs
new file mode 100644
index 0000000..8eb3a3a
--- /dev/null
+++ b/third_party/autocxx/engine/src/conversion/type_helpers.rs
@@ -0,0 +1,58 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syn::{
+ AngleBracketedGenericArguments, GenericArgument, PathArguments, PathSegment, Type, TypePath,
+ TypeReference,
+};
+
+/// Looks in a `core::pin::Pin<&mut Something>` and returns the `Something`
+/// if it's found.
+/// This code could _almost_ be used from various other places around autocxx
+/// but they each have slightly different requirements. Over time we should
+/// try to migrate other instances to use this, though.
+pub(crate) fn extract_pinned_mutable_reference_type(tp: &TypePath) -> Option<&Type> {
+ if !is_pin(tp) {
+ return None;
+ }
+ if let Some(PathSegment {
+ arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }),
+ ..
+ }) = tp.path.segments.last()
+ {
+ if args.len() == 1 {
+ if let Some(GenericArgument::Type(Type::Reference(TypeReference {
+ mutability: Some(_),
+ elem,
+ ..
+ }))) = args.first()
+ {
+ return Some(elem);
+ }
+ }
+ }
+ None
+}
+
+/// Whether this type path is a `Pin`
+fn is_pin(tp: &TypePath) -> bool {
+ if tp.path.segments.len() != 3 {
+ return false;
+ }
+ static EXPECTED_SEGMENTS: &[&[&str]] = &[&["std", "core"], &["pin"], &["Pin"]];
+
+ for (seg, expected_name) in tp.path.segments.iter().zip(EXPECTED_SEGMENTS.iter()) {
+ if !expected_name
+ .iter()
+ .any(|expected_name| seg.ident == expected_name)
+ {
+ return false;
+ }
+ }
+ true
+}
diff --git a/third_party/autocxx/engine/src/known_types.rs b/third_party/autocxx/engine/src/known_types.rs
index 377101a..10199fb 100644
--- a/third_party/autocxx/engine/src/known_types.rs
+++ b/third_party/autocxx/engine/src/known_types.rs
@@ -6,14 +6,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use crate::{
- conversion::ConvertError,
- types::{make_ident, QualifiedName},
-};
+use crate::types::{make_ident, QualifiedName};
use indexmap::map::IndexMap as HashMap;
use indoc::indoc;
use once_cell::sync::OnceCell;
-use syn::{parse_quote, Type, TypePath, TypePtr};
+use syn::{parse_quote, TypePath};
//// The behavior of the type.
#[derive(Debug)]
@@ -103,12 +100,12 @@
let mut segs = self.rs_name.split("::").peekable();
if segs.peek().map(|seg| seg.is_empty()).unwrap_or_default() {
segs.next();
- let segs = segs.into_iter().map(make_ident);
+ let segs = segs.map(make_ident);
parse_quote! {
::#(#segs)::*
}
} else {
- let segs = segs.into_iter().map(make_ident);
+ let segs = segs.map(make_ident);
parse_quote! {
#(#segs)::*
}
@@ -143,7 +140,7 @@
}
/// The type of payload that a cxx generic can contain.
-#[derive(PartialEq, Clone, Copy)]
+#[derive(PartialEq, Eq, Clone, Copy)]
pub enum CxxGenericType {
/// Not a generic at all
Not,
@@ -247,7 +244,9 @@
.map(|td| {
matches!(
td.behavior,
- Behavior::CxxContainerPtr | Behavior::CxxContainerVector
+ Behavior::CxxContainerPtr
+ | Behavior::CxxContainerVector
+ | Behavior::RustContainerByValueSafe
)
})
.unwrap_or(false)
@@ -447,8 +446,8 @@
));
for (cpp_type, rust_type) in (4..7).map(|x| 2i32.pow(x)).flat_map(|x| {
vec![
- (format!("uint{}_t", x), format!("u{}", x)),
- (format!("int{}_t", x), format!("i{}", x)),
+ (format!("uint{x}_t"), format!("u{x}")),
+ (format!("int{x}_t"), format!("i{x}")),
]
}) {
db.insert(TypeDetails::new(
@@ -470,10 +469,10 @@
));
db.insert(TypeDetails::new(
- "std::pin::Pin",
+ "core::pin::Pin",
"Pin",
Behavior::RustByValue, // because this is actually Pin<&something>
- None,
+ Some("std::pin::Pin".to_string()),
true,
false,
));
@@ -481,18 +480,18 @@
let mut insert_ctype = |cname: &str| {
let concatenated_name = cname.replace(' ', "");
db.insert(TypeDetails::new(
- format!("autocxx::c_{}", concatenated_name),
+ format!("autocxx::c_{concatenated_name}"),
cname,
Behavior::CVariableLengthByValue,
- Some(format!("std::os::raw::c_{}", concatenated_name)),
+ Some(format!("std::os::raw::c_{concatenated_name}")),
true,
true,
));
db.insert(TypeDetails::new(
- format!("autocxx::c_u{}", concatenated_name),
- format!("unsigned {}", cname),
+ format!("autocxx::c_u{concatenated_name}"),
+ format!("unsigned {cname}"),
Behavior::CVariableLengthByValue,
- Some(format!("std::os::raw::c_u{}", concatenated_name)),
+ Some(format!("std::os::raw::c_u{concatenated_name}")),
true,
true,
));
@@ -553,10 +552,3 @@
));
db
}
-
-pub(crate) fn ensure_pointee_is_valid(ptr: &TypePtr) -> Result<(), ConvertError> {
- match *ptr.elem {
- Type::Path(..) => Ok(()),
- _ => Err(ConvertError::InvalidPointee),
- }
-}
diff --git a/third_party/autocxx/engine/src/lib.rs b/third_party/autocxx/engine/src/lib.rs
index 86a31ea..3988ab2 100644
--- a/third_party/autocxx/engine/src/lib.rs
+++ b/third_party/autocxx/engine/src/lib.rs
@@ -10,15 +10,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// This feature=nightly could be set by build.rs, but since we only care
-// about it for docs, we ask docs.rs to set it in the Cargo.toml.
-#![cfg_attr(feature = "nightly", feature(doc_cfg))]
#![forbid(unsafe_code)]
+#![cfg_attr(feature = "nightly", feature(doc_cfg))]
mod ast_discoverer;
mod conversion;
mod cxxbridge;
mod known_types;
+mod minisyn;
mod output_generators;
mod parse_callbacks;
mod parse_file;
@@ -28,6 +27,7 @@
#[cfg(any(test, feature = "build"))]
mod builder;
+use autocxx_bindgen::BindgenError;
use autocxx_parser::{IncludeCppConfig, UnsafePolicy};
use conversion::BridgeConverter;
use miette::{SourceOffset, SourceSpan};
@@ -35,7 +35,9 @@
use parse_file::CppBuildable;
use proc_macro2::TokenStream as TokenStream2;
use regex::Regex;
+use std::cell::RefCell;
use std::path::PathBuf;
+use std::rc::Rc;
use std::{
fs::File,
io::prelude::*,
@@ -113,7 +115,7 @@
#[derive(Debug, Error, Diagnostic)]
pub enum Error {
#[error("Bindgen was unable to generate the initial .rs bindings for this file. This may indicate a parsing problem with the C++ headers.")]
- Bindgen(()),
+ Bindgen(BindgenError),
#[error(transparent)]
#[diagnostic(transparent)]
MacroParsing(LocatedSynError),
@@ -123,7 +125,10 @@
#[error("no C++ include directory was provided.")]
NoAutoCxxInc,
#[error(transparent)]
+ #[diagnostic(transparent)]
Conversion(conversion::ConvertError),
+ #[error("Using `unsafe_references_wrapped` requires the Rust nightly `arbitrary_self_types` feature")]
+ WrappedReferencesButNoArbitrarySelfTypes,
}
/// Result type.
@@ -142,6 +147,16 @@
Generated(Box<GenerationResults>),
}
+/// Code generation options.
+#[derive(Default)]
+pub struct CodegenOptions<'a> {
+ // An option used by the test suite to force a more convoluted
+ // route through our code, to uncover bugs.
+ pub force_wrapper_gen: bool,
+ /// Options about the C++ code generation.
+ pub cpp_codegen_options: CppCodegenOptions<'a>,
+}
+
const AUTOCXX_CLANG_ARGS: &[&str; 4] = &["-x", "c++", "-std=c++14", "-DBINDGEN"];
/// Implement to learn of header files which get included
@@ -254,6 +269,7 @@
pub struct IncludeCppEngine {
config: IncludeCppConfig,
state: State,
+ source_code: Option<Rc<String>>, // so we can create diagnostics
}
impl Parse for IncludeCppEngine {
@@ -264,14 +280,31 @@
} else {
State::NotGenerated
};
- Ok(Self { config, state })
+ Ok(Self {
+ config,
+ state,
+ source_code: None,
+ })
}
}
impl IncludeCppEngine {
- pub fn new_from_syn(mac: Macro, file_contents: &str) -> Result<Self> {
- mac.parse_body::<IncludeCppEngine>()
- .map_err(|e| Error::MacroParsing(LocatedSynError::new(e, file_contents)))
+ pub fn new_from_syn(mac: Macro, file_contents: Rc<String>) -> Result<Self> {
+ let mut this = mac
+ .parse_body::<IncludeCppEngine>()
+ .map_err(|e| Error::MacroParsing(LocatedSynError::new(e, &file_contents)))?;
+ this.source_code = Some(file_contents);
+ Ok(this)
+ }
+
+ /// Used if we find that we're asked to auto-discover extern_rust_type and similar
+ /// but didn't have any include_cpp macro at all.
+ pub fn new_for_autodiscover() -> Self {
+ Self {
+ config: IncludeCppConfig::default(),
+ state: State::NotGenerated,
+ source_code: None,
+ }
}
pub fn config_mut(&mut self) -> &mut IncludeCppConfig {
@@ -287,7 +320,7 @@
self.config
.inclusions
.iter()
- .map(|path| format!("#include \"{}\"\n", path)),
+ .map(|path| format!("#include \"{path}\"\n")),
"",
)
}
@@ -304,7 +337,11 @@
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
})
- .rustfmt_bindings(log::log_enabled!(log::Level::Info))
+ .formatter(if log::log_enabled!(log::Level::Info) {
+ bindgen::Formatter::Rustfmt
+ } else {
+ bindgen::Formatter::None
+ })
.size_t_is_usize(true)
.enable_cxx_namespaces()
.generate_inline_functions(true)
@@ -335,7 +372,7 @@
builder
.command_line_flags()
.into_iter()
- .map(|f| format!("\"{}\"", f))
+ .map(|f| format!("\"{f}\""))
.join(" ")
);
builder
@@ -370,7 +407,7 @@
let bindings = bindings.to_string();
// Manually add the mod ffi {} so that we can ask syn to parse
// into a single construct.
- let bindings = format!("mod bindgen {{ {} }}", bindings);
+ let bindings = format!("mod bindgen {{ {bindings} }}");
info!("Bindings: {}", bindings);
syn::parse_str::<ItemMod>(&bindings)
.map_err(|e| Error::BindingsParsing(LocatedSynError::new(e, &bindings)))
@@ -386,7 +423,7 @@
inc_dirs: Vec<PathBuf>,
extra_clang_args: &[&str],
dep_recorder: Option<Box<dyn RebuildDependencyRecorder>>,
- cpp_codegen_options: &CppCodegenOptions,
+ codegen_options: &CodegenOptions,
) -> Result<()> {
// If we are in parse only mode, do nothing. This is used for
// doc tests to ensure the parsing is valid, but we can't expect
@@ -397,6 +434,14 @@
State::Generated(_) => panic!("Only call generate once"),
}
+ if matches!(
+ self.config.unsafe_policy,
+ UnsafePolicy::ReferencesWrappedAllFunctionsSafe
+ ) && !rustversion::cfg!(nightly)
+ {
+ return Err(Error::WrappedReferencesButNoArbitrarySelfTypes);
+ }
+
let mod_name = self.config.get_mod_name();
let mut builder = self.make_bindgen_builder(&inc_dirs, extra_clang_args);
if let Some(dep_recorder) = dep_recorder {
@@ -411,6 +456,14 @@
let bindings = builder.generate().map_err(Error::Bindgen)?;
let bindings = self.parse_bindings(bindings)?;
+ // Source code contents just used for diagnostics - if we don't have it,
+ // use a blank string and miette will not attempt to annotate it nicely.
+ let source_file_contents = self
+ .source_code
+ .as_ref()
+ .cloned()
+ .unwrap_or_else(|| Rc::new("".to_string()));
+
let converter = BridgeConverter::new(&self.config.inclusions, &self.config);
let conversion = converter
@@ -418,7 +471,8 @@
bindings,
self.config.unsafe_policy.clone(),
header_contents,
- cpp_codegen_options,
+ codegen_options,
+ &source_file_contents,
)
.map_err(Error::Conversion)?;
let mut items = conversion.rs;
@@ -433,7 +487,7 @@
new_bindings.content.as_mut().unwrap().1.append(&mut items);
info!(
"New bindings:\n{}",
- rust_pretty_printer::pretty_print(&new_bindings.to_token_stream())
+ rust_pretty_printer::pretty_print(&new_bindings)
);
self.state = State::Generated(Box::new(GenerationResults {
item_mod: new_bindings,
@@ -484,7 +538,7 @@
"header": header,
"config": config
});
- let f = File::create(&output_path).unwrap();
+ let f = File::create(output_path).unwrap();
serde_json::to_writer(f, &json).unwrap();
}
}
@@ -505,12 +559,12 @@
// to refer to local headers on the reduction machine too.
let suffix = ALL_KNOWN_SYSTEM_HEADERS
.iter()
- .map(|hdr| format!("#include <{}>\n", hdr))
+ .map(|hdr| format!("#include <{hdr}>\n"))
.join("\n");
let input = format!("/*\nautocxx config:\n\n{:?}\n\nend autocxx config.\nautocxx preprocessed input:\n*/\n\n{}\n\n/* autocxx: extra headers added below for completeness. */\n\n{}\n{}\n",
self.config, header, suffix, cxx_gen::HEADER);
let mut tf = NamedTempFile::new().unwrap();
- write!(tf, "{}", input).unwrap();
+ write!(tf, "{input}").unwrap();
let tp = tf.into_temp_path();
preprocess(&tp, &PathBuf::from(output_path), inc_dirs, extra_clang_args).unwrap();
}
@@ -565,7 +619,11 @@
})
}
-pub(crate) fn strip_system_headers(input: Vec<u8>, suppress_system_headers: bool) -> Vec<u8> {
+pub fn get_cxx_header_bytes(suppress_system_headers: bool) -> Vec<u8> {
+ strip_system_headers(cxx_gen::HEADER.as_bytes().to_vec(), suppress_system_headers)
+}
+
+fn strip_system_headers(input: Vec<u8>, suppress_system_headers: bool) -> Vec<u8> {
if suppress_system_headers {
std::str::from_utf8(&input)
.unwrap()
@@ -660,7 +718,7 @@
impl Default for AutocxxgenHeaderNamer<'static> {
fn default() -> Self {
- Self(Box::new(|mod_name| format!("autocxxgen_{}.h", mod_name)))
+ Self(Box::new(|mod_name| format!("autocxxgen_{mod_name}.h")))
}
}
@@ -677,7 +735,27 @@
impl Default for CxxgenHeaderNamer<'static> {
fn default() -> Self {
- Self(Box::new(|| "cxxgen.h".into()))
+ // The default implementation here is to name these headers
+ // cxxgen.h, cxxgen1.h, cxxgen2.h etc.
+ // These names are not especially predictable by callers and this
+ // behavior is not tested anywhere - so this is considered semi-
+ // supported, at best. This only comes into play in the rare case
+ // that you're generating bindings to multiple include_cpp!
+ // or a mix of include_cpp! and #[cxx::bridge] bindings.
+ let header_counter = Rc::new(RefCell::new(0));
+ Self(Box::new(move || {
+ let header_counter = header_counter.clone();
+ let header_counter_cell = header_counter.as_ref();
+ let mut header_counter = header_counter_cell.borrow_mut();
+ if *header_counter == 0 {
+ *header_counter += 1;
+ "cxxgen.h".into()
+ } else {
+ let count = *header_counter;
+ *header_counter += 1;
+ format!("cxxgen{count}.h")
+ }
+ }))
}
}
@@ -694,10 +772,10 @@
/// You may wish to do this to make a hermetic test case with no
/// external dependencies.
pub suppress_system_headers: bool,
- /// Optionally, a prefix to go at `#include "<here>cxx.h". This is a header file from the `cxx`
+ /// Optionally, a prefix to go at `#include "*here*cxx.h". This is a header file from the `cxx`
/// crate.
pub path_to_cxx_h: Option<String>,
- /// Optionally, a prefix to go at `#include "<here>cxxgen.h". This is a header file which we
+ /// Optionally, a prefix to go at `#include "*here*cxxgen.h". This is a header file which we
/// generate.
pub path_to_cxxgen_h: Option<String>,
/// Optionally, a function called to determine the name that will be used
@@ -720,7 +798,7 @@
// miette.
struct Err;
let r: Result<(usize, usize), Err> = (|| {
- let span_desc = format!("{:?}", span);
+ let span_desc = format!("{span:?}");
let re = Regex::new(r"(\d+)..(\d+)").unwrap();
let captures = re.captures(&span_desc).ok_or(Err)?;
let start = captures.get(1).ok_or(Err)?;
diff --git a/third_party/autocxx/engine/src/minisyn.rs b/third_party/autocxx/engine/src/minisyn.rs
new file mode 100644
index 0000000..e675baa
--- /dev/null
+++ b/third_party/autocxx/engine/src/minisyn.rs
@@ -0,0 +1,187 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Newtype wrappers for `syn` types implementing a different
+//! `Debug` implementation that results in more concise output.
+
+use std::fmt::Display;
+
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::punctuated::{Pair, Punctuated};
+
+macro_rules! minisyn_no_parse {
+ ($syntype:ident) => {
+ /// Equivalent to the identically-named `syn` type except
+ /// that its `Debug` implementation is more concise.
+ #[derive(Clone, Hash, Eq, PartialEq)]
+ pub struct $syntype(pub ::syn::$syntype);
+ impl std::fmt::Debug for $syntype {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ write!(f, "{}", self.0.to_token_stream().to_string())
+ }
+ }
+ impl ToTokens for $syntype
+ where
+ ::syn::$syntype: ToTokens,
+ {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.0.to_tokens(tokens)
+ }
+
+ fn to_token_stream(&self) -> TokenStream {
+ self.0.to_token_stream()
+ }
+ fn into_token_stream(self) -> TokenStream
+ where
+ Self: Sized,
+ {
+ self.0.into_token_stream()
+ }
+ }
+ impl std::ops::Deref for $syntype {
+ type Target = ::syn::$syntype;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ impl std::ops::DerefMut for $syntype {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+ }
+ impl std::convert::From<::syn::$syntype> for $syntype {
+ fn from(inner: ::syn::$syntype) -> Self {
+ Self(inner)
+ }
+ }
+ impl std::convert::From<$syntype> for syn::$syntype {
+ fn from(inner: $syntype) -> Self {
+ inner.0
+ }
+ }
+ };
+}
+
+macro_rules! minisyn {
+ ($syntype:ident) => {
+ minisyn_no_parse!($syntype);
+
+ impl syn::parse::Parse for $syntype {
+ fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<Self> {
+ syn::parse::Parse::parse(input).map(Self)
+ }
+ }
+ };
+}
+
+minisyn!(ItemMod);
+minisyn_no_parse!(Attribute);
+minisyn_no_parse!(AssocConst);
+minisyn_no_parse!(AssocType);
+minisyn!(Expr);
+minisyn!(ExprAssign);
+minisyn!(ExprAwait);
+minisyn!(ExprBinary);
+minisyn!(ExprBlock);
+minisyn!(ExprBreak);
+minisyn!(ExprConst);
+minisyn!(ExprCast);
+minisyn!(ExprField);
+minisyn_no_parse!(ExprGroup);
+minisyn!(ExprLet);
+minisyn!(ExprParen);
+minisyn!(ExprReference);
+minisyn!(ExprTry);
+minisyn!(ExprUnary);
+minisyn_no_parse!(Field);
+minisyn_no_parse!(Fields);
+minisyn!(ForeignItem);
+minisyn!(FnArg);
+minisyn!(GenericArgument);
+minisyn!(GenericParam);
+minisyn!(Ident);
+minisyn!(ImplItem);
+minisyn!(Item);
+minisyn!(ItemConst);
+minisyn!(ItemEnum);
+minisyn!(ItemForeignMod);
+minisyn!(ItemStruct);
+minisyn!(ItemType);
+minisyn!(ItemUse);
+minisyn!(LitBool);
+minisyn!(LitInt);
+minisyn!(Macro);
+minisyn_no_parse!(Pat);
+minisyn_no_parse!(PatType);
+minisyn_no_parse!(PatReference);
+minisyn_no_parse!(PatSlice);
+minisyn_no_parse!(PatTuple);
+minisyn!(Path);
+minisyn_no_parse!(PathArguments);
+minisyn!(PathSegment);
+minisyn!(Receiver);
+minisyn!(ReturnType);
+minisyn!(Signature);
+minisyn!(Stmt);
+minisyn!(TraitItem);
+minisyn!(Type);
+minisyn!(TypeArray);
+minisyn!(TypeGroup);
+minisyn!(TypeParamBound);
+minisyn!(TypeParen);
+minisyn!(TypePath);
+minisyn!(TypePtr);
+minisyn!(TypeReference);
+minisyn!(TypeSlice);
+minisyn!(Visibility);
+
+/// Converts a `syn::Punctuated` from being full of `syn` types to being
+/// full of `minisyn` types or vice-versa.
+pub(crate) fn minisynize_punctuated<T1, T2, S>(input: Punctuated<T1, S>) -> Punctuated<T2, S>
+where
+ T1: Into<T2>,
+{
+ input
+ .into_pairs()
+ .map(|p| match p {
+ Pair::Punctuated(t, p) => Pair::Punctuated(t.into(), p),
+ Pair::End(t) => Pair::End(t.into()),
+ })
+ .collect()
+}
+
+/// Converts a `Vec` from being full of `syn` types to being
+/// full of `minisyn` types or vice-versa.
+pub(crate) fn minisynize_vec<T1, T2>(input: Vec<T1>) -> Vec<T2>
+where
+ T1: Into<T2>,
+{
+ input.into_iter().map(Into::into).collect()
+}
+
+impl Ident {
+ pub(crate) fn new(string: &str, span: proc_macro2::Span) -> Self {
+ Self(syn::Ident::new(string, span))
+ }
+}
+
+impl Display for Ident {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.0.to_string())
+ }
+}
+
+impl<T> PartialEq<T> for Ident
+where
+ T: AsRef<str> + ?Sized,
+{
+ fn eq(&self, rhs: &T) -> bool {
+ self.0.eq(rhs)
+ }
+}
diff --git a/third_party/autocxx/engine/src/output_generators.rs b/third_party/autocxx/engine/src/output_generators.rs
index a862558..09c143a 100644
--- a/third_party/autocxx/engine/src/output_generators.rs
+++ b/third_party/autocxx/engine/src/output_generators.rs
@@ -19,7 +19,7 @@
/// Creates an on-disk archive (actually a JSON file) of the Rust side of the bindings
/// for multiple `include_cpp` macros. If you use this, you will want to tell
-/// `autocxx_macro` how to find this file using the `AUTOCXX_RS_ARCHIVE`
+/// `autocxx_macro` how to find this file using the `AUTOCXX_RS_JSON_ARCHIVE`
/// environment variable.
pub fn generate_rs_archive<'a>(rs_outputs: impl Iterator<Item = RsOutput<'a>>) -> String {
let mut multi_bindings = MultiBindings::default();
diff --git a/third_party/autocxx/engine/src/parse_file.rs b/third_party/autocxx/engine/src/parse_file.rs
index 3571d19..16ea625 100644
--- a/third_party/autocxx/engine/src/parse_file.rs
+++ b/third_party/autocxx/engine/src/parse_file.rs
@@ -12,14 +12,15 @@
cxxbridge::CxxBridge, Error as EngineError, GeneratedCpp, IncludeCppEngine,
RebuildDependencyRecorder,
};
-use crate::{CppCodegenOptions, LocatedSynError};
+use crate::{proc_macro_span_to_miette_span, CodegenOptions, CppCodegenOptions, LocatedSynError};
use autocxx_parser::directive_names::SUBCLASS;
use autocxx_parser::{AllowlistEntry, RustPath, Subclass, SubclassAttrs};
use indexmap::set::IndexSet as HashSet;
-use miette::Diagnostic;
+use miette::{Diagnostic, SourceSpan};
use quote::ToTokens;
use std::{io::Read, path::PathBuf};
use std::{panic::UnwindSafe, path::Path, rc::Rc};
+use syn::spanned::Spanned;
use syn::{token::Brace, Item, ItemMod};
use thiserror::Error;
@@ -27,7 +28,7 @@
/// and interpret include_cxx macros.
#[derive(Error, Diagnostic, Debug)]
pub enum ParseError {
- #[error("unable to open the source file: {0}")]
+ #[error("unable to open the source file containing your autocxx bindings. (This filename is usually specified within your build.rs file.): {0}")]
FileOpen(std::io::Error),
#[error("the .rs file couldn't be read: {0}")]
FileRead(std::io::Error),
@@ -39,6 +40,8 @@
#[error("the subclass attribute couldn't be parsed: {0}")]
#[diagnostic(transparent)]
SubclassSyntax(LocatedSynError),
+ #[error("the subclass attribute macro with a superclass attribute requires the Builder::auto_allowlist option to be specified (probably in your build script). This is not recommended - instead you can specify subclass! within your include_cpp!.")]
+ SubclassSuperclassWithoutAutoAllowlist(#[source_code] String, #[label("here")] SourceSpan),
/// The include CPP macro could not be expanded into
/// Rust bindings to C++, because of some problem during the conversion
/// process. This could be anything from a C++ parsing error to some
@@ -52,8 +55,6 @@
/// mod name.
#[error("there are two or more include_cpp! mods with the same mod name")]
ConflictingModNames,
- #[error("dynamic discovery was enabled but no mod was found")]
- ZeroModsForDynamicDiscovery,
#[error("dynamic discovery was enabled but multiple mods were found")]
MultipleModsForDynamicDiscovery,
#[error("a problem occurred while discovering C++ APIs used within the Rust: {0}")]
@@ -87,12 +88,13 @@
extra_superclasses: Vec<Subclass>,
discoveries: Discoveries,
}
+ let file_contents = Rc::new(file_contents.to_string());
impl State {
fn parse_item(
&mut self,
item: Item,
mod_path: Option<RustPath>,
- file_contents: &str,
+ file_contents: Rc<String>,
) -> Result<(), ParseError> {
let result = match item {
Item::Macro(mac)
@@ -110,10 +112,9 @@
)
}
Item::Mod(itm)
- if itm
- .attrs
- .iter()
- .any(|attr| attr.path.to_token_stream().to_string() == "cxx :: bridge") =>
+ if itm.attrs.iter().any(|attr| {
+ attr.path().to_token_stream().to_string() == "cxx :: bridge"
+ }) =>
{
Segment::Cxx(CxxBridge::from(itm))
}
@@ -128,7 +129,11 @@
Some(mod_path) => mod_path.append(itm.ident.clone()),
};
for item in items {
- mod_state.parse_item(item, Some(mod_path.clone()), file_contents)?
+ mod_state.parse_item(
+ item,
+ Some(mod_path.clone()),
+ file_contents.clone(),
+ )?
}
self.extra_superclasses.extend(mod_state.extra_superclasses);
self.discoveries.extend(mod_state.discoveries);
@@ -146,26 +151,34 @@
Segment::Other(Item::Mod(itm))
}
}
- Item::Struct(ref its) if self.auto_allowlist => {
+ Item::Struct(ref its) => {
let attrs = &its.attrs;
let is_superclass_attr = attrs.iter().find(|attr| {
- attr.path
+ attr.path()
.segments
.last()
.map(|seg| seg.ident == "is_subclass" || seg.ident == SUBCLASS)
.unwrap_or(false)
});
if let Some(is_superclass_attr) = is_superclass_attr {
- if !is_superclass_attr.tokens.is_empty() {
+ if is_superclass_attr.meta.require_path_only().is_err() {
let subclass = its.ident.clone();
let args: SubclassAttrs =
is_superclass_attr.parse_args().map_err(|e| {
ParseError::SubclassSyntax(LocatedSynError::new(
e,
- file_contents,
+ &file_contents,
))
})?;
if let Some(superclass) = args.superclass {
+ if !self.auto_allowlist {
+ return Err(
+ ParseError::SubclassSuperclassWithoutAutoAllowlist(
+ file_contents.to_string(),
+ proc_macro_span_to_miette_span(&its.span()),
+ ),
+ );
+ }
self.extra_superclasses.push(Subclass {
superclass,
subclass,
@@ -194,7 +207,7 @@
..Default::default()
};
for item in source.items {
- state.parse_item(item, None, file_contents)?
+ state.parse_item(item, None, file_contents.clone())?
}
let State {
auto_allowlist,
@@ -210,13 +223,18 @@
// We do not want to enter this 'if' block unless the above conditions are true,
// since we may emit errors.
if must_handle_discovered_things {
+ // If we have to handle discovered things but there was no include_cpp! macro,
+ // fake one.
+ if !results.iter().any(|seg| matches!(seg, Segment::Autocxx(_))) {
+ results.push(Segment::Autocxx(IncludeCppEngine::new_for_autodiscover()));
+ }
let mut autocxx_seg_iterator = results.iter_mut().filter_map(|seg| match seg {
Segment::Autocxx(engine) => Some(engine),
_ => None,
});
let our_seg = autocxx_seg_iterator.next();
match our_seg {
- None => return Err(ParseError::ZeroModsForDynamicDiscovery),
+ None => panic!("We should have just added a fake mod but apparently didn't"),
Some(engine) => {
engine
.config_mut()
@@ -364,7 +382,7 @@
autocxx_inc: Vec<PathBuf>,
extra_clang_args: &[&str],
dep_recorder: Option<Box<dyn RebuildDependencyRecorder>>,
- cpp_codegen_options: &CppCodegenOptions,
+ codegen_options: &CodegenOptions,
) -> Result<(), ParseError> {
let mut mods_found = HashSet::new();
let inner_dep_recorder: Option<Rc<dyn RebuildDependencyRecorder>> =
@@ -386,7 +404,7 @@
autocxx_inc.clone(),
extra_clang_args,
dep_recorder,
- cpp_codegen_options,
+ codegen_options,
)
.map_err(ParseError::AutocxxCodegenError)?
}
diff --git a/third_party/autocxx/engine/src/rust_pretty_printer.rs b/third_party/autocxx/engine/src/rust_pretty_printer.rs
index 9c23cbc..7c9d36c 100644
--- a/third_party/autocxx/engine/src/rust_pretty_printer.rs
+++ b/third_party/autocxx/engine/src/rust_pretty_printer.rs
@@ -6,35 +6,12 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use proc_macro2::TokenStream;
-use std::io::Write;
-use std::process::{Command, Stdio};
+use syn::{Item, ItemMod};
-enum Error {
- Run(std::io::Error),
- Write(std::io::Error),
- Utf8(std::string::FromUtf8Error),
- Wait(std::io::Error),
-}
-
-pub(crate) fn pretty_print(ts: &TokenStream) -> String {
- reformat_or_else(ts.to_string())
-}
-
-fn reformat_or_else(text: impl std::fmt::Display) -> String {
- match reformat(&text) {
- Ok(s) => s,
- Err(_) => text.to_string(),
- }
-}
-
-fn reformat(text: impl std::fmt::Display) -> Result<String, Error> {
- let mut rustfmt = Command::new("rustfmt")
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .spawn()
- .map_err(Error::Run)?;
- write!(rustfmt.stdin.take().unwrap(), "{}", text).map_err(Error::Write)?;
- let output = rustfmt.wait_with_output().map_err(Error::Wait)?;
- String::from_utf8(output.stdout).map_err(Error::Utf8)
+pub(crate) fn pretty_print(itm: &ItemMod) -> String {
+ prettyplease::unparse(&syn::File {
+ shebang: None,
+ attrs: Vec::new(),
+ items: vec![Item::Mod(itm.clone())],
+ })
}
diff --git a/third_party/autocxx/engine/src/types.rs b/third_party/autocxx/engine/src/types.rs
index 337da14..f7eaae0 100644
--- a/third_party/autocxx/engine/src/types.rs
+++ b/third_party/autocxx/engine/src/types.rs
@@ -6,14 +6,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use crate::minisyn::Ident;
use itertools::Itertools;
use proc_macro2::Span;
use quote::ToTokens;
use std::iter::Peekable;
use std::{fmt::Display, sync::Arc};
-use syn::{parse_quote, Ident, PathSegment, TypePath};
+use syn::{parse_quote, PathSegment, TypePath};
+use thiserror::Error;
-use crate::{conversion::ConvertError, known_types::known_types};
+use crate::known_types::known_types;
pub(crate) fn make_ident<S: AsRef<str>>(id: S) -> Ident {
Ident::new(id.as_ref(), Span::call_site())
@@ -52,11 +54,15 @@
pub(crate) fn depth(&self) -> usize {
self.0.len()
}
+
+ pub(crate) fn to_cpp_path(&self) -> String {
+ self.0.join("::")
+ }
}
impl Display for Namespace {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(&self.0.join("::"))
+ f.write_str(&self.to_cpp_path())
}
}
@@ -80,7 +86,7 @@
/// either. It doesn't directly have functionality to convert
/// from one to the other; `replace_type_path_without_arguments`
/// does that.
-#[derive(Debug, PartialEq, PartialOrd, Eq, Hash, Clone)]
+#[derive(PartialEq, PartialOrd, Eq, Hash, Clone)]
pub struct QualifiedName(Namespace, String);
impl QualifiedName {
@@ -140,7 +146,7 @@
/// cxx doesn't accept names containing double underscores,
/// but these are OK elsewhere in our output mod.
- pub(crate) fn validate_ok_for_cxx(&self) -> Result<(), ConvertError> {
+ pub(crate) fn validate_ok_for_cxx(&self) -> Result<(), InvalidIdentError> {
validate_ident_ok_for_cxx(self.get_final_item())
}
@@ -172,14 +178,6 @@
}
}
- pub(crate) fn get_final_cpp_item(&self) -> String {
- let special_cpp_name = known_types().special_cpp_name(self);
- match special_cpp_name {
- Some(name) => name,
- None => self.1.to_string(),
- }
- }
-
pub(crate) fn to_type_path(&self) -> TypePath {
if let Some(known_type_path) = known_types().known_type_type_path(self) {
known_type_path
@@ -228,26 +226,44 @@
}
}
+impl std::fmt::Debug for QualifiedName {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ Display::fmt(self, f)
+ }
+}
+
+/// Problems representing C++ identifiers in a way which is compatible with
+/// cxx.
+#[derive(Error, Clone, Debug)]
+pub enum InvalidIdentError {
+ #[error("Names containing __ are reserved by C++ so not acceptable to cxx")]
+ TooManyUnderscores,
+ #[error("bindgen decided to call this type _bindgen_ty_N because it couldn't deduce the correct name for it. That means we can't generate C++ bindings to it.")]
+ BindgenTy,
+ #[error("The item name '{0}' is a reserved word in Rust.")]
+ ReservedName(String),
+}
+
/// cxx doesn't allow identifiers containing __. These are OK elsewhere
/// in our output mod. It would be nice in future to think of a way we
/// can enforce this using the Rust type system, e.g. a newtype
/// wrapper for a CxxCompatibleIdent which is used in any context
/// where code will be output as part of the `#[cxx::bridge]` mod.
-pub fn validate_ident_ok_for_cxx(id: &str) -> Result<(), ConvertError> {
+pub fn validate_ident_ok_for_cxx(id: &str) -> Result<(), InvalidIdentError> {
validate_ident_ok_for_rust(id)?;
if id.contains("__") {
- Err(ConvertError::TooManyUnderscores)
+ Err(InvalidIdentError::TooManyUnderscores)
} else if id.starts_with("_bindgen_ty_") {
- Err(ConvertError::BindgenTy)
+ Err(InvalidIdentError::BindgenTy)
} else {
Ok(())
}
}
-pub fn validate_ident_ok_for_rust(label: &str) -> Result<(), ConvertError> {
+pub fn validate_ident_ok_for_rust(label: &str) -> Result<(), InvalidIdentError> {
let id = make_ident(label);
syn::parse2::<syn::Ident>(id.into_token_stream())
- .map_err(|_| ConvertError::ReservedName(label.to_string()))
+ .map_err(|_| InvalidIdentError::ReservedName(label.to_string()))
.map(|_| ())
}
diff --git a/third_party/autocxx/examples/chromium-fake-render-frame-host/Cargo.toml b/third_party/autocxx/examples/chromium-fake-render-frame-host/Cargo.toml
index 3862f2c..9cc05cd 100644
--- a/third_party/autocxx/examples/chromium-fake-render-frame-host/Cargo.toml
+++ b/third_party/autocxx/examples/chromium-fake-render-frame-host/Cargo.toml
@@ -13,9 +13,9 @@
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features = [ "fancy" ] }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/chromium-fake-render-frame-host/src/render_frame_host.rs b/third_party/autocxx/examples/chromium-fake-render-frame-host/src/render_frame_host.rs
index 9c2bf51..761c8a8 100644
--- a/third_party/autocxx/examples/chromium-fake-render-frame-host/src/render_frame_host.rs
+++ b/third_party/autocxx/examples/chromium-fake-render-frame-host/src/render_frame_host.rs
@@ -209,7 +209,7 @@
}
}
-#[is_subclass(superclass("content::WebContentsObserver"))]
+#[subclass(superclass("content::WebContentsObserver"))]
#[doc(hidden)]
pub struct RenderFrameHostForWebContents {
rfh: *mut ffi::content::RenderFrameHost,
diff --git a/third_party/autocxx/examples/cpp_calling_rust/Cargo.toml b/third_party/autocxx/examples/cpp_calling_rust/Cargo.toml
new file mode 100644
index 0000000..2814194
--- /dev/null
+++ b/third_party/autocxx/examples/cpp_calling_rust/Cargo.toml
@@ -0,0 +1,26 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "cpp_calling_rust"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cxx = "1.0.78"
+autocxx = { path = "../..", version="0.26.0" }
+uwuify = "0.2.2"
+textwrap = "0.14"
+fastrand = "1.5.0"
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.26.0" }
+regex = "1.5.4"
+miette = { version="5", features = [ "fancy" ] }
diff --git a/third_party/autocxx/examples/cpp_calling_rust/build.rs b/third_party/autocxx/examples/cpp_calling_rust/build.rs
new file mode 100644
index 0000000..60cc460
--- /dev/null
+++ b/third_party/autocxx/examples/cpp_calling_rust/build.rs
@@ -0,0 +1,21 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+ let path = std::path::PathBuf::from("src");
+ let mut b = autocxx_build::Builder::new("src/main.rs", &[&path])
+ .auto_allowlist(true)
+ .build()?;
+ b.flag_if_supported("-std=c++17")
+ .file("src/input.cc")
+ .compile("autocxx-cpp-calling-rust-example");
+ println!("cargo:rerun-if-changed=src/main.rs");
+ println!("cargo:rerun-if-changed=src/input.cc");
+ println!("cargo:rerun-if-changed=src/input.h");
+ Ok(())
+}
diff --git a/third_party/autocxx/examples/cpp_calling_rust/src/input.cc b/third_party/autocxx/examples/cpp_calling_rust/src/input.cc
new file mode 100644
index 0000000..64c446a
--- /dev/null
+++ b/third_party/autocxx/examples/cpp_calling_rust/src/input.cc
@@ -0,0 +1,19 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include "cxxgen.h"
+#include "input.h"
+
+void jurassic() {
+ rust::Box<Dinosaur> prey = new_dinosaur(false);
+ rust::Box<Dinosaur> predator = new_dinosaur(true);
+ prey->roar();
+ predator->roar();
+ predator->eat(std::move(prey));
+ go_extinct();
+}
\ No newline at end of file
diff --git a/third_party/autocxx/examples/cpp_calling_rust/src/input.h b/third_party/autocxx/examples/cpp_calling_rust/src/input.h
new file mode 100644
index 0000000..206adc6
--- /dev/null
+++ b/third_party/autocxx/examples/cpp_calling_rust/src/input.h
@@ -0,0 +1,16 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#pragma once
+
+#include <cstdint>
+#include <sstream>
+#include <stdint.h>
+#include <string>
+
+void jurassic();
\ No newline at end of file
diff --git a/third_party/autocxx/examples/cpp_calling_rust/src/main.rs b/third_party/autocxx/examples/cpp_calling_rust/src/main.rs
new file mode 100644
index 0000000..3fe6404
--- /dev/null
+++ b/third_party/autocxx/examples/cpp_calling_rust/src/main.rs
@@ -0,0 +1,58 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This example shows calls from C++ back into Rust. That's really not
+// the main purpose of autocxx, and this support is immature. If you're
+// primarily doing this sort of thing, look into other tools such as
+// cbindgen or cxx.
+
+use autocxx::prelude::*;
+use std::pin::Pin;
+
+include_cpp! {
+ #include "input.h"
+ safety!(unsafe_ffi)
+ generate!("jurassic")
+}
+
+fn main() {
+ ffi::jurassic();
+}
+
+#[autocxx::extern_rust::extern_rust_type]
+pub struct Dinosaur {
+ carnivore: bool,
+}
+
+#[autocxx::extern_rust::extern_rust_function]
+pub fn new_dinosaur(carnivore: bool) -> Box<Dinosaur> {
+ Box::new(Dinosaur { carnivore })
+}
+
+impl Dinosaur {
+ #[autocxx::extern_rust::extern_rust_function]
+ fn roar(&self) {
+ println!("Roar");
+ }
+
+ #[autocxx::extern_rust::extern_rust_function]
+ fn eat(self: Pin<&mut Dinosaur>, other_dinosaur: Box<Dinosaur>) {
+ assert!(self.carnivore);
+ other_dinosaur.get_eaten();
+ println!("Nom nom");
+ }
+
+ fn get_eaten(&self) {
+ println!("Uh-oh");
+ }
+}
+
+#[autocxx::extern_rust::extern_rust_function]
+pub fn go_extinct() {
+ println!("Boom")
+}
diff --git a/third_party/autocxx/examples/llvm/Cargo.toml b/third_party/autocxx/examples/llvm/Cargo.toml
index 4c03db7..3c274ac 100644
--- a/third_party/autocxx/examples/llvm/Cargo.toml
+++ b/third_party/autocxx/examples/llvm/Cargo.toml
@@ -13,9 +13,9 @@
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.17.2" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.17.2" }
-miette = { version="4.3", features = [ "fancy" ] }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/non-trivial-type-on-stack/Cargo.toml b/third_party/autocxx/examples/non-trivial-type-on-stack/Cargo.toml
index 110bd1b..7af139e 100644
--- a/third_party/autocxx/examples/non-trivial-type-on-stack/Cargo.toml
+++ b/third_party/autocxx/examples/non-trivial-type-on-stack/Cargo.toml
@@ -13,9 +13,9 @@
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features = [ "fancy" ] }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/pod/Cargo.toml b/third_party/autocxx/examples/pod/Cargo.toml
index 9f4ee5a..e05d261 100644
--- a/third_party/autocxx/examples/pod/Cargo.toml
+++ b/third_party/autocxx/examples/pod/Cargo.toml
@@ -13,9 +13,9 @@
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features = [ "fancy" ] }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/reference-wrappers/Cargo.toml b/third_party/autocxx/examples/reference-wrappers/Cargo.toml
index cb85e80..93c68ba 100644
--- a/third_party/autocxx/examples/reference-wrappers/Cargo.toml
+++ b/third_party/autocxx/examples/reference-wrappers/Cargo.toml
@@ -13,9 +13,9 @@
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features=["fancy"]}
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/reference-wrappers/build.rs b/third_party/autocxx/examples/reference-wrappers/build.rs
index 64c573d..8e15dd0 100644
--- a/third_party/autocxx/examples/reference-wrappers/build.rs
+++ b/third_party/autocxx/examples/reference-wrappers/build.rs
@@ -10,9 +10,11 @@
let path = std::path::PathBuf::from("src");
let mut b = autocxx_build::Builder::new("src/main.rs", &[&path]).build()?;
b.flag_if_supported("-std=c++14")
- .file("src/input.cc").compile("autocxx-reference-wrapper-example");
+ .file("src/input.cc")
+ .compile("autocxx-reference-wrapper-example");
println!("cargo:rerun-if-changed=src/main.rs");
println!("cargo:rerun-if-changed=src/input.h");
+
Ok(())
}
diff --git a/third_party/autocxx/examples/reference-wrappers/src/input.h b/third_party/autocxx/examples/reference-wrappers/src/input.h
index 5e3c6e9..dd37dfa 100644
--- a/third_party/autocxx/examples/reference-wrappers/src/input.h
+++ b/third_party/autocxx/examples/reference-wrappers/src/input.h
@@ -18,6 +18,7 @@
Goat() : horns(0) {}
void add_a_horn();
std::string describe() const;
+ uint32_t& get_horns() { return horns; }
private:
uint32_t horns;
};
diff --git a/third_party/autocxx/examples/reference-wrappers/src/main.rs b/third_party/autocxx/examples/reference-wrappers/src/main.rs
index 6bea2ff..ca3e0cd 100644
--- a/third_party/autocxx/examples/reference-wrappers/src/main.rs
+++ b/third_party/autocxx/examples/reference-wrappers/src/main.rs
@@ -23,16 +23,52 @@
// especially in the absence of the Rust "arbitrary self types"
// feature.
+// Necessary to be able to call methods on reference wrappers.
+// For that reason, this example only builds on nightly Rust.
+#![feature(arbitrary_self_types)]
+
use autocxx::prelude::*;
+use std::pin::Pin;
include_cpp! {
#include "input.h"
// This next line enables C++ reference wrappers
+ // This is what requires the 'arbitrary_self_types' feature.
safety!(unsafe_references_wrapped)
generate!("Goat")
generate!("Field")
}
+impl ffi::Goat {
+ // Methods can be called on a CppRef<T> or &CppRef<T>
+ fn bleat(self: CppRef<Self>) {
+ println!("Bleat");
+ }
+}
+
+trait FarmProduce {
+ // Traits can be defined on a CppRef<T> so long as Self: Sized
+ fn sell(self: &CppRef<Self>)
+ where
+ Self: Sized;
+}
+
+impl FarmProduce for ffi::Goat {
+ fn sell(self: &CppRef<Self>) {
+ println!("Selling goat");
+ }
+}
+
+trait FarmArea {
+ fn maintain(self: CppRef<Self>);
+}
+
+impl FarmArea for ffi::Field {
+ fn maintain(self: CppRef<Self>) {
+ println!("Maintaining");
+ }
+}
+
fn main() {
// Create a cxx::UniquePtr as normal for a Field object.
let field = ffi::Field::new().within_unique_ptr();
@@ -47,21 +83,36 @@
// However, as soon as we want to pass a reference to the field
// back to C++, we have to ensure we have no Rust references
// in existence. So: we imprison the object in a "CppPin":
- let field = ffi::cpp_pin_uniqueptr(field);
+ let field = CppUniquePtrPin::new(field);
// We can no longer take Rust references to the field...
// let _field_rust_ref = field.as_ref();
// However, we can take C++ references. And use such references
- // to call methods...
+ // to call methods in C++. Quite often those methods will
+ // return other references, like this.
let another_goat = field.as_cpp_ref().get_goat();
// The 'get_goat' method in C++ returns a reference, so this is
// another CppRef, not a Rust reference.
+
+ // We can still use these C++ references to call Rust methods,
+ // so long as those methods have a "self" type of a
+ // C++ reference not a Rust reference.
+ another_goat.clone().bleat();
+ another_goat.sell();
+
+ // But most commonly, C++ references are simply used as the 'this'
+ // type when calling other C++ methods, like this.
assert_eq!(
another_goat
.describe() // returns a UniquePtr<CxxString>, there
- // are no Rust or C++ references involved at this point.
+ // are no Rust or C++ references involved at this point.
.as_ref()
.unwrap()
.to_string_lossy(),
"This goat has 0 horns."
);
+
+ // We can even use trait objects, though it's a bit of a fiddle.
+ let farm_area: Pin<Box<dyn FarmArea>> = ffi::Field::new().within_box();
+ let farm_area = CppPin::from_pinned_box(farm_area);
+ farm_area.as_cpp_ref().maintain();
}
diff --git a/third_party/autocxx/examples/s2/Cargo.toml b/third_party/autocxx/examples/s2/Cargo.toml
index 04524b1..c93706b 100644
--- a/third_party/autocxx/examples/s2/Cargo.toml
+++ b/third_party/autocxx/examples/s2/Cargo.toml
@@ -15,9 +15,9 @@
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features = [ "fancy" ] }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/steam-mini/Cargo.toml b/third_party/autocxx/examples/steam-mini/Cargo.toml
index ceb81ff..5162f96 100644
--- a/third_party/autocxx/examples/steam-mini/Cargo.toml
+++ b/third_party/autocxx/examples/steam-mini/Cargo.toml
@@ -15,9 +15,9 @@
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features = [ "fancy" ] }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/subclass/Cargo.toml b/third_party/autocxx/examples/subclass/Cargo.toml
index dc93f53..a19ea27 100644
--- a/third_party/autocxx/examples/subclass/Cargo.toml
+++ b/third_party/autocxx/examples/subclass/Cargo.toml
@@ -15,13 +15,13 @@
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
uwuify = "0.2.2"
-textwrap = "0.14"
+textwrap = "0.15"
fastrand = "1.5.0"
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
regex = "1.5.4"
-miette = { version="4.3", features = [ "fancy" ] }
+miette = { version = "5", features = ["fancy"] }
diff --git a/third_party/autocxx/examples/subclass/src/main.rs b/third_party/autocxx/examples/subclass/src/main.rs
index 2841598..095abd4 100644
--- a/third_party/autocxx/examples/subclass/src/main.rs
+++ b/third_party/autocxx/examples/subclass/src/main.rs
@@ -34,7 +34,7 @@
// See the main function at the bottom for how this subclass
// is instantiated.
-#[is_subclass(superclass("MessageDisplayer"))]
+#[subclass(superclass("MessageDisplayer"))]
#[derive(Default)]
pub struct UwuDisplayer {}
@@ -60,7 +60,7 @@
// for now, at least, we can't hold non-trivial C++ objects on the Rust stack.)
// All the boxing and unboxing is done automatically by autocxx layers.
-#[is_subclass(superclass("MessageProducer"))]
+#[subclass(superclass("MessageProducer"))]
#[derive(Default)]
pub struct QuoteProducer;
@@ -93,7 +93,7 @@
// doing stuff. In C++ you'd probably need a const_cast. Here we use
// interior mutability.
-#[is_subclass(superclass("MessageDisplayer"))]
+#[subclass(superclass("MessageDisplayer"))]
pub struct BoxDisplayer {
message_count: RefCell<usize>,
}
@@ -103,7 +103,7 @@
Self::new_rust_owned(Self {
// As we're allocating this class ourselves instead of using [`Default`]
// we need to initialize the `cpp_peer` member ourselves. This member is
- // inserted by the `#[is_subclass]` annotation. autocxx will
+ // inserted by the `#[subclass]` annotation. autocxx will
// later use this to store a pointer back to the C++ peer.
cpp_peer: Default::default(),
message_count: RefCell::new(1usize),
diff --git a/third_party/autocxx/examples/subclass/src/messages.h b/third_party/autocxx/examples/subclass/src/messages.h
index 02ff248..bbf6118 100644
--- a/third_party/autocxx/examples/subclass/src/messages.h
+++ b/third_party/autocxx/examples/subclass/src/messages.h
@@ -12,7 +12,6 @@
#pragma once
#include <string>
-#include <memory>
class MessageProducer {
public:
diff --git a/third_party/autocxx/gen/build/Cargo.toml b/third_party/autocxx/gen/build/Cargo.toml
index 678a844..d101f91 100644
--- a/third_party/autocxx/gen/build/Cargo.toml
+++ b/third_party/autocxx/gen/build/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx-build"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
edition = "2021"
license = "MIT OR Apache-2.0"
@@ -18,14 +18,16 @@
categories = ["development-tools::ffi", "api-bindings"]
[features]
-runtime = [ "autocxx-engine/runtime" ]
-static = [ "autocxx-engine/static" ]
+runtime = ["autocxx-engine/runtime"]
+static = ["autocxx-engine/static"]
[dependencies]
-autocxx-engine = { version="=0.22.3", path="../../engine", features = ["build"] }
+autocxx-engine = { version = "=0.26.0", path = "../../engine", features = [
+ "build",
+] }
env_logger = "0.9.0"
indexmap = "1.8"
[dependencies.syn]
-version = "1.0"
-features = [ "full" ]
+version = "2.0"
+features = ["full"]
diff --git a/third_party/autocxx/gen/build/src/lib.rs b/third_party/autocxx/gen/build/src/lib.rs
index c1df580..ccef184 100644
--- a/third_party/autocxx/gen/build/src/lib.rs
+++ b/third_party/autocxx/gen/build/src/lib.rs
@@ -45,7 +45,7 @@
fn record_header_file_dependency(&self, filename: &str) {
let mut already = self.printed_already.lock().unwrap();
if already.insert(filename.into()) {
- println!("cargo:rerun-if-changed={}", filename);
+ println!("cargo:rerun-if-changed={filename}");
}
}
}
diff --git a/third_party/autocxx/gen/cmd/Cargo.toml b/third_party/autocxx/gen/cmd/Cargo.toml
index 51eb56c..7a78ba3 100644
--- a/third_party/autocxx/gen/cmd/Cargo.toml
+++ b/third_party/autocxx/gen/cmd/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx-gen"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
edition = "2021"
license = "MIT OR Apache-2.0"
@@ -18,24 +18,24 @@
categories = ["development-tools::ffi", "api-bindings"]
[features]
-runtime = [ "autocxx-engine/runtime" ]
-static = [ "autocxx-engine/static" ]
+runtime = ["autocxx-engine/runtime"]
+static = ["autocxx-engine/static"]
[dependencies]
-autocxx-engine = { version="=0.22.3", path="../../engine" }
+autocxx-engine = { version = "=0.26.0", path = "../../engine" }
clap = { version = "3.1.2", features = ["cargo"] }
proc-macro2 = "1.0"
env_logger = "0.9.0"
-miette = { version="4.3", features=["fancy"]}
+miette = { version = "5", features = ["fancy"] }
pathdiff = "0.2.1"
indexmap = "1.8"
[dev-dependencies]
-assert_cmd = "1.0.3"
+assert_cmd = "2"
tempfile = "3.1"
-autocxx-integration-tests = { path = "../../integration-tests", version="=0.22.3" }
# This is necessary for building the projects created
# by the trybuild test system...
-autocxx = { path="../.." }
-cxx = "1.0.68"
-itertools = "0.10.3"
\ No newline at end of file
+autocxx = { path = "../.." }
+autocxx-integration-tests = { path = "../../integration-tests", version = "=0.26.0" }
+cxx = "1.0.78"
+itertools = "0.10.3"
diff --git a/third_party/autocxx/gen/cmd/src/depfile.rs b/third_party/autocxx/gen/cmd/src/depfile.rs
index d8d3626..315ff89 100644
--- a/third_party/autocxx/gen/cmd/src/depfile.rs
+++ b/third_party/autocxx/gen/cmd/src/depfile.rs
@@ -44,7 +44,7 @@
let dependency_list = self.dependencies.join(" \\\n ");
for output in &self.outputs {
self.file
- .write_all(format!("{}: {}\n\n", output, dependency_list).as_bytes())?
+ .write_all(format!("{output}: {dependency_list}\n\n").as_bytes())?
}
Ok(())
}
diff --git a/third_party/autocxx/gen/cmd/src/main.rs b/third_party/autocxx/gen/cmd/src/main.rs
index f8db241..4d533ff 100644
--- a/third_party/autocxx/gen/cmd/src/main.rs
+++ b/third_party/autocxx/gen/cmd/src/main.rs
@@ -11,8 +11,8 @@
mod depfile;
use autocxx_engine::{
- generate_rs_archive, generate_rs_single, parse_file, AutocxxgenHeaderNamer, CxxgenHeaderNamer,
- RebuildDependencyRecorder,
+ generate_rs_archive, generate_rs_single, get_cxx_header_bytes, parse_file,
+ AutocxxgenHeaderNamer, CxxgenHeaderNamer, RebuildDependencyRecorder,
};
use clap::{crate_authors, crate_version, Arg, ArgGroup, Command};
use depfile::Depfile;
@@ -132,7 +132,7 @@
.arg(
Arg::new("gen-rs-include")
.long("gen-rs-include")
- .help("whether to generate Rust files for inclusion using autocxx_macro (suffix will be .include.rs)")
+ .help("whether to generate Rust files for inclusion using autocxx_macro")
)
.arg(
Arg::new("gen-rs-archive")
@@ -156,7 +156,7 @@
.arg(
Arg::new("fix-rs-include-name")
.long("fix-rs-include-name")
- .help("Make the name of the .rs file predictable. You must set AUTOCXX_RS_FILE during Rust build time to educate autocxx_macro about your choice.")
+ .help("Make the name of the .rs file predictable (suffix will be .include.rs). You must set AUTOCXX_RS_FILE during Rust build time to educate autocxx_macro about your choice.")
.requires("gen-rs-include")
)
.arg(
@@ -177,6 +177,11 @@
.takes_value(true),
)
.arg(
+ Arg::new("generate-cxx-h")
+ .long("generate-cxx-h")
+ .help("whether to generate cxx.h header file. If you already knew where to find cxx.h, consider using --cxx-h-path")
+ )
+ .arg(
Arg::new("cxx-h-path")
.long("cxx-h-path")
.value_name("PREFIX")
@@ -247,6 +252,10 @@
autocxxgen_header_namer,
cxxgen_header_namer,
};
+ let codegen_options = autocxx_engine::CodegenOptions {
+ cpp_codegen_options,
+ ..Default::default()
+ };
let depfile = match matches.value_of("depfile") {
None => None,
Some(depfile_path) => {
@@ -277,12 +286,20 @@
incs.clone(),
&extra_clang_args,
dep_recorder,
- &cpp_codegen_options,
+ &codegen_options,
)?;
}
// Finally start to write the C++ and Rust out.
let outdir: PathBuf = matches.value_of_os("outdir").unwrap().into();
+
+ if !outdir.exists() {
+ use miette::WrapErr as _;
+ std::fs::create_dir_all(&outdir)
+ .into_diagnostic()
+ .wrap_err_with(|| format!("Failed to create `outdir` '{}'", outdir.display()))?;
+ }
+
let mut writer = FileWriter {
depfile: &depfile,
outdir: &outdir,
@@ -290,14 +307,14 @@
};
if matches.is_present("gen-cpp") {
let cpp = matches.value_of("cpp-extension").unwrap();
- let name_cc_file = |counter| format!("gen{}.{}", counter, cpp);
+ let name_cc_file = |counter| format!("gen{counter}.{cpp}");
let mut counter = 0usize;
for include_cxx in parsed_files
.iter()
.flat_map(|file| file.get_cpp_buildables())
{
let generations = include_cxx
- .generate_h_and_cxx(&cpp_codegen_options)
+ .generate_h_and_cxx(&codegen_options.cpp_codegen_options)
.expect("Unable to generate header and C++ code");
for pair in generations.0 {
let cppname = name_cc_file(counter);
@@ -306,7 +323,7 @@
counter += 1;
}
}
- drop(cpp_codegen_options);
+ drop(codegen_options);
// Write placeholders to ensure we always make exactly 'n' of each file type.
writer.write_placeholders(counter, desired_number, name_cc_file)?;
writer.write_placeholders(
@@ -320,6 +337,14 @@
name_autocxxgen_h,
)?;
}
+
+ if matches.is_present("generate-cxx-h") {
+ writer.write_to_file(
+ "cxx.h".to_string(),
+ &get_cxx_header_bytes(suppress_system_headers),
+ )?;
+ }
+
if matches.is_present("gen-rs-include") {
if !matches.is_present("fix-rs-include-name") && desired_number.is_some() {
return Err(miette::Report::msg(
@@ -356,15 +381,15 @@
}
fn name_autocxxgen_h(counter: usize) -> String {
- format!("autocxxgen{}.h", counter)
+ format!("autocxxgen{counter}.h")
}
fn name_cxxgen_h(counter: usize) -> String {
- format!("gen{}.h", counter)
+ format!("gen{counter}.h")
}
fn name_include_rs(counter: usize) -> String {
- format!("gen{}.include.rs", counter)
+ format!("gen{counter}.include.rs")
}
fn get_dependency_recorder(depfile: Rc<RefCell<Depfile>>) -> Box<dyn RebuildDependencyRecorder> {
@@ -391,7 +416,7 @@
) -> miette::Result<()> {
if let Some(desired_number) = desired_number {
if counter > desired_number {
- return Err(miette::Report::msg("More files were generated than expected. Increase the value passed to --generate-exact or reduce the number of include_cpp! sections."));
+ return Err(miette::Report::msg(format!("{counter} files were generated. Increase the value passed to --generate-exact or reduce the number of include_cpp! sections.")));
}
while counter < desired_number {
let fname = filename(counter);
@@ -420,7 +445,7 @@
let mut f = File::create(&path).into_diagnostic()?;
f.write_all(content).into_diagnostic()?;
if self.written.contains(&filename) {
- return Err(miette::Report::msg(format!("autocxx_gen would write two files entitled '{}' which would have conflicting contents. Consider using --generate-exact.", filename)));
+ return Err(miette::Report::msg(format!("autocxx_gen would write two files entitled '{filename}' which would have conflicting contents. Consider using --generate-exact.")));
}
self.written.insert(filename);
Ok(())
diff --git a/third_party/autocxx/gen/cmd/tests/cmd_test.rs b/third_party/autocxx/gen/cmd/tests/cmd_test.rs
index 6fd3382..4ec3942 100644
--- a/third_party/autocxx/gen/cmd/tests/cmd_test.rs
+++ b/third_party/autocxx/gen/cmd/tests/cmd_test.rs
@@ -88,7 +88,8 @@
.arg(demo_code_dir.to_str().unwrap())
.arg("--outdir")
.arg(tmp_dir.path().to_str().unwrap())
- .arg("--gen-cpp");
+ .arg("--gen-cpp")
+ .arg("--generate-cxx-h");
cmd.arg(match rs_gen_mode {
RsGenMode::Single => "--gen-rs-include",
RsGenMode::Archive => "--gen-rs-archive",
@@ -109,8 +110,6 @@
fn test_gen() -> Result<(), Box<dyn std::error::Error>> {
let tmp_dir = tempdir()?;
base_test(&tmp_dir, RsGenMode::Single, |_| {})?;
- File::create(tmp_dir.path().join("cxx.h"))
- .and_then(|mut cxx_h| cxx_h.write_all(autocxx_engine::HEADER.as_bytes()))?;
std::env::set_var("OUT_DIR", tmp_dir.path().to_str().unwrap());
let r = build_from_folder(
tmp_dir.path(),
@@ -130,8 +129,6 @@
fn test_gen_archive() -> Result<(), Box<dyn std::error::Error>> {
let tmp_dir = tempdir()?;
base_test(&tmp_dir, RsGenMode::Archive, |_| {})?;
- File::create(tmp_dir.path().join("cxx.h"))
- .and_then(|mut cxx_h| cxx_h.write_all(autocxx_engine::HEADER.as_bytes()))?;
let r = build_from_folder(
tmp_dir.path(),
&tmp_dir.path().join("demo/main.rs"),
@@ -150,8 +147,6 @@
fn test_gen_archive_first_entry() -> Result<(), Box<dyn std::error::Error>> {
let tmp_dir = tempdir()?;
base_test(&tmp_dir, RsGenMode::Archive, |_| {})?;
- File::create(tmp_dir.path().join("cxx.h"))
- .and_then(|mut cxx_h| cxx_h.write_all(autocxx_engine::HEADER.as_bytes()))?;
let r = build_from_folder(
tmp_dir.path(),
&tmp_dir.path().join("demo/main.rs"),
@@ -176,8 +171,6 @@
fn test_gen_archive_second_entry() -> Result<(), Box<dyn std::error::Error>> {
let tmp_dir = tempdir()?;
base_test(&tmp_dir, RsGenMode::Archive, |_| {})?;
- File::create(tmp_dir.path().join("cxx.h"))
- .and_then(|mut cxx_h| cxx_h.write_all(autocxx_engine::HEADER.as_bytes()))?;
let r = build_from_folder(
tmp_dir.path(),
&tmp_dir.path().join("demo/main.rs"),
@@ -217,10 +210,8 @@
files,
vec!["directive1.rs", "directive2.rs"],
)?;
- File::create(tmp_dir.path().join("cxx.h"))
- .and_then(|mut cxx_h| cxx_h.write_all(autocxx_engine::HEADER.as_bytes()))?;
// We've asked to create 8 C++ files, mostly blank. Build 'em all.
- let cpp_files = (0..7).map(|id| format!("gen{}.cc", id)).collect_vec();
+ let cpp_files = (0..7).map(|id| format!("gen{id}.cc")).collect_vec();
let cpp_files = cpp_files.iter().map(|s| s.as_str()).collect_vec();
let r = build_from_folder(
tmp_dir.path(),
@@ -273,8 +264,6 @@
assert_not_contentful(&tmp_dir, "autocxxgen1.h");
assert_contentful(&tmp_dir, "gen0.include.rs");
assert_contentful(&tmp_dir, "test.d");
- File::create(tmp_dir.path().join("cxx.h"))
- .and_then(|mut cxx_h| cxx_h.write_all(autocxx_engine::HEADER.as_bytes()))?;
let r = build_from_folder(
tmp_dir.path(),
&tmp_dir.path().join("demo/main.rs"),
@@ -319,7 +308,7 @@
fn write_to_file(dir: &Path, filename: &str, content: &[u8]) {
let path = dir.join(filename);
- let mut f = File::create(&path).expect("Unable to create file");
+ let mut f = File::create(path).expect("Unable to create file");
f.write_all(content).expect("Unable to write file");
}
@@ -330,8 +319,7 @@
}
assert!(
p.metadata().unwrap().len() > BLANK.len().try_into().unwrap(),
- "File {} is empty",
- fname
+ "File {fname} is empty"
);
}
@@ -350,7 +338,7 @@
fn assert_contains(outdir: &TempDir, fname: &str, pattern: &str) {
let p = outdir.path().join(fname);
- let content = std::fs::read_to_string(&p).expect(fname);
- eprintln!("content = {}", content);
+ let content = std::fs::read_to_string(p).expect(fname);
+ eprintln!("content = {content}");
assert!(content.contains(pattern));
}
diff --git a/third_party/autocxx/integration-tests/Cargo.toml b/third_party/autocxx/integration-tests/Cargo.toml
index 7791ea5..78384ce 100644
--- a/third_party/autocxx/integration-tests/Cargo.toml
+++ b/third_party/autocxx/integration-tests/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx-integration-tests"
-version = "0.22.3"
+version = "0.26.0"
autotests = false
edition = "2021"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
@@ -27,20 +27,25 @@
cc = "1.0"
quote = "1.0"
once_cell = "1.7"
-autocxx-engine = { version="=0.22.3", path="../engine", features = ["build"] }
# This is necessary for building the projects created
# by the trybuild test system...
-autocxx = { path="..", version="=0.22.3" }
+autocxx = { path = "..", version = "=0.26.0" }
+autocxx-engine = { version = "=0.26.0", path = "../engine", features = [
+ "build",
+] }
+moveit = { version = "0.6", features = [ "cxx" ] }
link-cplusplus = "1.0"
-tempfile = "3.1"
+tempfile = "3.4"
indoc = "1.0"
log = "0.4"
-cxx = "1.0.68"
+cxx = "1.0.78"
itertools = "0.10"
+rustversion = "1.0"
+static_assertions = "1.1.0"
[dependencies.syn]
version = "1.0.39"
-features = [ "full" ]
+features = ["full"]
#features = [ "full", "extra-traits" ]
[[test]]
diff --git a/third_party/autocxx/integration-tests/src/lib.rs b/third_party/autocxx/integration-tests/src/lib.rs
index f4667d5..2335ee5 100644
--- a/third_party/autocxx/integration-tests/src/lib.rs
+++ b/third_party/autocxx/integration-tests/src/lib.rs
@@ -162,7 +162,7 @@
);
}
let temp_path = self.temp_dir.path().to_str().unwrap();
- let mut rustflags = format!("-L {}", temp_path);
+ let mut rustflags = format!("-L {temp_path}");
if std::env::var_os("AUTOCXX_ASAN").is_some() {
rustflags.push_str(" -Z sanitizer=address -Clinker=clang++ -Clink-arg=-fuse-ld=lld");
}
@@ -194,6 +194,7 @@
}
/// A positive test, we expect to pass.
+#[track_caller]
pub fn run_test(
cxx_code: &str,
header_code: &str,
@@ -210,6 +211,7 @@
None,
None,
"unsafe_ffi",
+ None,
)
.unwrap()
}
@@ -265,6 +267,7 @@
code_checker,
extra_rust,
"unsafe_ffi",
+ None,
)
.unwrap()
}
@@ -297,6 +300,7 @@
None,
None,
"unsafe_ffi",
+ None,
)
.expect_err("Unexpected success");
}
@@ -319,6 +323,7 @@
code_checker,
extra_rust,
"unsafe_ffi",
+ None,
)
.expect_err("Unexpected success");
}
@@ -369,10 +374,13 @@
rust_code_checker: Option<CodeChecker>,
extra_rust: Option<TokenStream>,
safety_policy: &str,
+ module_attributes: Option<TokenStream>,
) -> Result<(), TestError> {
let hexathorpe = Token);
let safety_policy = format_ident!("{}", safety_policy);
let unexpanded_rust = quote! {
+ #module_attributes
+
use autocxx::prelude::*;
include_cpp!(
@@ -413,14 +421,12 @@
builder_modifier: Option<BuilderModifier>,
rust_code_checker: Option<CodeChecker>,
) -> Result<(), TestError> {
+ let builder_modifier = consider_forcing_wrapper_generation(builder_modifier);
+
const HEADER_NAME: &str = "input.h";
// Step 2: Write the C++ header snippet to a temp file
let tdir = tempdir().unwrap();
- write_to_file(
- &tdir,
- HEADER_NAME,
- &format!("#pragma once\n{}", header_code),
- );
+ write_to_file(&tdir, HEADER_NAME, &format!("#pragma once\n{header_code}"));
write_to_file(&tdir, "cxx.h", HEADER);
rust_code.append_all(quote! {
@@ -431,7 +437,7 @@
let write_rust_to_file = |ts: &TokenStream| -> PathBuf {
// Step 3: Write the Rust code to a temp file
- let rs_code = format!("{}", ts);
+ let rs_code = format!("{ts}");
write_to_file(&tdir, "input.rs", &rs_code)
};
@@ -441,7 +447,7 @@
let rs_path = write_rust_to_file(&rust_code);
info!("Path is {:?}", tdir.path());
- let builder = Builder::<TestBuilderContext>::new(&rs_path, &[tdir.path()])
+ let builder = Builder::<TestBuilderContext>::new(&rs_path, [tdir.path()])
.custom_gendir(target_dir.clone());
let builder = if let Some(builder_modifier) = &builder_modifier {
builder_modifier.modify_autocxx_builder(builder)
@@ -470,7 +476,7 @@
if !cxx_code.is_empty() {
// Step 4: Write the C++ code snippet to a .cc file, along with a #include
// of the header emitted in step 5.
- let cxx_code = format!("#include \"input.h\"\n#include \"cxxgen.h\"\n{}", cxx_code);
+ let cxx_code = format!("#include \"input.h\"\n#include \"cxxgen.h\"\n{cxx_code}");
let cxx_path = write_to_file(&tdir, "input.cxx", &cxx_code);
b.file(cxx_path);
}
@@ -485,7 +491,7 @@
.try_compile("autocxx-demo")
.map_err(TestError::CppBuild)?;
if KEEP_TEMPDIRS {
- println!("Generated .rs files: {:?}", generated_rs_files);
+ println!("Generated .rs files: {generated_rs_files:?}");
}
// Step 8: use the trybuild crate to build the Rust file.
let r = get_builder().lock().unwrap().build(
@@ -506,3 +512,38 @@
}
Ok(())
}
+
+/// If AUTOCXX_FORCE_WRAPPER_GENERATION is set, always force both C++
+/// and Rust side shims, for extra testing of obscure code paths.
+fn consider_forcing_wrapper_generation(
+ existing_builder_modifier: Option<BuilderModifier>,
+) -> Option<BuilderModifier> {
+ if std::env::var("AUTOCXX_FORCE_WRAPPER_GENERATION").is_err() {
+ existing_builder_modifier
+ } else {
+ Some(Box::new(ForceWrapperGeneration(existing_builder_modifier)))
+ }
+}
+
+struct ForceWrapperGeneration(Option<BuilderModifier>);
+
+impl BuilderModifierFns for ForceWrapperGeneration {
+ fn modify_autocxx_builder<'a>(
+ &self,
+ builder: Builder<'a, TestBuilderContext>,
+ ) -> Builder<'a, TestBuilderContext> {
+ let builder = builder.force_wrapper_generation(true);
+ if let Some(modifier) = &self.0 {
+ modifier.modify_autocxx_builder(builder)
+ } else {
+ builder
+ }
+ }
+ fn modify_cc_builder<'a>(&self, builder: &'a mut cc::Build) -> &'a mut cc::Build {
+ if let Some(modifier) = &self.0 {
+ modifier.modify_cc_builder(builder)
+ } else {
+ builder
+ }
+ }
+}
diff --git a/third_party/autocxx/integration-tests/tests/builder_modifiers.rs b/third_party/autocxx/integration-tests/tests/builder_modifiers.rs
index 0cf763e..5fcc458 100644
--- a/third_party/autocxx/integration-tests/tests/builder_modifiers.rs
+++ b/third_party/autocxx/integration-tests/tests/builder_modifiers.rs
@@ -14,11 +14,19 @@
make_clang_arg_adder(&["-std=c++17"])
}
-struct ClangArgAdder(Vec<String>);
+struct ClangArgAdder(Vec<String>, Vec<String>);
pub(crate) fn make_clang_arg_adder(args: &[&str]) -> Option<BuilderModifier> {
+ make_clang_optional_arg_adder(args, &[])
+}
+
+pub(crate) fn make_clang_optional_arg_adder(
+ args: &[&str],
+ optional_args: &[&str],
+) -> Option<BuilderModifier> {
let args: Vec<_> = args.iter().map(|a| a.to_string()).collect();
- Some(Box::new(ClangArgAdder(args)))
+ let optional_args: Vec<_> = optional_args.iter().map(|a| a.to_string()).collect();
+ Some(Box::new(ClangArgAdder(args, optional_args)))
}
impl BuilderModifierFns for ClangArgAdder {
@@ -34,6 +42,9 @@
for f in &self.0 {
builder = builder.flag(f);
}
+ for f in &self.1 {
+ builder = builder.flag_if_supported(f);
+ }
builder
}
}
diff --git a/third_party/autocxx/integration-tests/tests/code_checkers.rs b/third_party/autocxx/integration-tests/tests/code_checkers.rs
index 619c79c..ae12e3c 100644
--- a/third_party/autocxx/integration-tests/tests/code_checkers.rs
+++ b/third_party/autocxx/integration-tests/tests/code_checkers.rs
@@ -87,8 +87,7 @@
for msg in &self.0 {
if !toks.contains(msg) {
return Err(TestError::RsCodeExaminationFail(format!(
- "Couldn't find string '{}'",
- msg
+ "Couldn't find string '{msg}'"
)));
};
}
@@ -110,8 +109,7 @@
let needle = msg.to_string();
if !haystack.contains(&needle) {
return Err(TestError::RsCodeExaminationFail(format!(
- "Couldn't find tokens '{}'",
- needle
+ "Couldn't find tokens '{needle}'"
)));
};
}
@@ -146,7 +144,7 @@
for filename in cpp {
let file = File::open(filename).unwrap();
let lines = BufReader::new(file).lines();
- for l in lines.filter_map(|l| l.ok()) {
+ for l in lines.map_while(Result::ok) {
if self.negative_matches.iter().any(|neg| l.contains(neg)) {
return Err(TestError::CppCodeExaminationFail);
}
diff --git a/third_party/autocxx/integration-tests/tests/cpprefs_test.rs b/third_party/autocxx/integration-tests/tests/cpprefs_test.rs
index 4241dec..9cc6d39 100644
--- a/third_party/autocxx/integration-tests/tests/cpprefs_test.rs
+++ b/third_party/autocxx/integration-tests/tests/cpprefs_test.rs
@@ -13,6 +13,10 @@
use proc_macro2::TokenStream;
use quote::quote;
+const fn arbitrary_self_types_supported() -> bool {
+ rustversion::cfg!(nightly)
+}
+
/// A positive test, we expect to pass.
fn run_cpprefs_test(
cxx_code: &str,
@@ -21,6 +25,10 @@
generate: &[&str],
generate_pods: &[&str],
) {
+ if !arbitrary_self_types_supported() {
+ // "unsafe_references_wrapped" requires arbitrary_self_types, which requires nightly.
+ return;
+ }
do_run_test(
cxx_code,
header_code,
@@ -30,6 +38,9 @@
None,
None,
"unsafe_references_wrapped",
+ Some(quote! {
+ #![feature(arbitrary_self_types)]
+ }),
)
.unwrap()
}
@@ -54,7 +65,7 @@
"},
quote! {
let goat = ffi::Goat::new().within_unique_ptr();
- let mut goat = ffi::CppUniquePtrPin::new(goat);
+ let mut goat = autocxx::CppUniquePtrPin::new(goat);
goat.as_cpp_mut_ref().add_a_horn();
},
&["Goat"],
@@ -87,7 +98,7 @@
"},
quote! {
let goat = ffi::Goat::new().within_unique_ptr();
- let goat = ffi::cpp_pin_uniqueptr(goat);
+ let goat = autocxx::CppUniquePtrPin::new(goat);
goat.as_cpp_ref().describe();
},
&["Goat"],
diff --git a/third_party/autocxx/integration-tests/tests/integration_test.rs b/third_party/autocxx/integration-tests/tests/integration_test.rs
index 3ccc2d0..ec2b1e7 100644
--- a/third_party/autocxx/integration-tests/tests/integration_test.rs
+++ b/third_party/autocxx/integration-tests/tests/integration_test.rs
@@ -8,7 +8,8 @@
use crate::{
builder_modifiers::{
- make_clang_arg_adder, make_cpp17_adder, EnableAutodiscover, SetSuppressSystemHeaders,
+ make_clang_arg_adder, make_clang_optional_arg_adder, make_cpp17_adder, EnableAutodiscover,
+ SetSuppressSystemHeaders,
},
code_checkers::{
make_error_finder, make_rust_code_finder, make_string_finder, CppMatcher,
@@ -17,7 +18,7 @@
};
use autocxx_integration_tests::{
directives_from_lists, do_run_test, do_run_test_manual, run_generate_all_test, run_test,
- run_test_ex, run_test_expect_fail, run_test_expect_fail_ex, TestError,
+ run_test_ex, run_test_expect_fail, run_test_expect_fail_ex, BuilderModifier, TestError,
};
use indoc::indoc;
use itertools::Itertools;
@@ -501,6 +502,7 @@
run_test_expect_fail(cxx, hdr, rs, &["take_bob"], &["Bob"]);
}
+#[ignore] // https://github.com/google/autocxx/issues/1252
#[test]
fn test_take_as_pod_with_is_relocatable() {
let cxx = indoc! {"
@@ -840,8 +842,7 @@
run_test("", hdr, rs, &["A", "Bob", "C"], &[]);
}
-#[test]
-fn test_take_char_by_ptr_in_wrapped_method() {
+fn run_char_test(builder_modifier: Option<BuilderModifier>) {
let hdr = indoc! {"
#include <cstdint>
#include <memory>
@@ -871,7 +872,25 @@
assert_eq!(unsafe { ch.as_ref()}.unwrap(), &104i8);
assert_eq!(unsafe { a.as_ref().unwrap().take_char(ch, c2) }, 104);
};
- run_test("", hdr, rs, &["A", "C"], &[]);
+ run_test_ex(
+ "",
+ hdr,
+ rs,
+ directives_from_lists(&["A", "C"], &[], None),
+ builder_modifier,
+ None,
+ None,
+ );
+}
+
+#[test]
+fn test_take_char_by_ptr_in_wrapped_method() {
+ run_char_test(None)
+}
+
+#[test]
+fn test_take_char_by_ptr_in_wrapped_method_with_unsigned_chars() {
+ run_char_test(make_clang_arg_adder(&["-funsigned-char"]))
}
#[test]
@@ -1281,7 +1300,7 @@
#define BOB \"foo\"
"};
let rs = quote! {
- assert_eq!(std::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
+ assert_eq!(core::str::from_utf8(ffi::BOB).unwrap().trim_end_matches(char::from(0)), "foo");
};
run_test(cxx, hdr, rs, &["BOB"], &[]);
}
@@ -1428,7 +1447,7 @@
#[test]
fn test_asan_working_as_expected_for_rust_allocations() {
perform_asan_doom_test(
- quote! { Box::into_raw(std::pin::Pin::into_inner_unchecked(a)) },
+ quote! { Box::into_raw(core::pin::Pin::into_inner_unchecked(a)) },
quote! { Box },
)
}
@@ -3042,7 +3061,7 @@
const char* STRING = \"Foo\";
"};
let rs = quote! {
- let a = std::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
+ let a = core::str::from_utf8(ffi::STRING).unwrap().trim_end_matches(char::from(0));
assert_eq!(a, "Foo");
};
run_test("", hdr, rs, &["STRING"], &[]);
@@ -4221,6 +4240,29 @@
}
#[test]
+fn test_nested_unnamed_enum() {
+ let hdr = indoc! {"
+ namespace N {
+ struct A {
+ enum {
+ LOW_VAL = 1,
+ HIGH_VAL = 1000,
+ };
+ };
+ }
+ "};
+ run_test_ex(
+ "",
+ hdr,
+ quote! {},
+ quote! { generate_ns!("N")},
+ None,
+ None,
+ None,
+ );
+}
+
+#[test]
fn test_nested_type_constructor() {
let hdr = indoc! {"
#include <string>
@@ -4420,6 +4462,31 @@
}
#[test]
+fn test_cycle_up_of_vec() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ #include <vector>
+ #include <memory>
+ struct A {
+ uint32_t a;
+ };
+ inline std::unique_ptr<std::vector<A>> take_vec(std::unique_ptr<std::vector<A>> a) {
+ return a;
+ }
+ inline std::unique_ptr<std::vector<A>> get_vec() {
+ std::unique_ptr<std::vector<A>> items = std::make_unique<std::vector<A>>();
+ items->push_back(A { 3 });
+ items->push_back(A { 4 });
+ return items;
+ }
+ "};
+ let rs = quote! {
+ ffi::take_vec(ffi::get_vec());
+ };
+ run_test("", hdr, rs, &["take_vec", "get_vec"], &[]);
+}
+
+#[test]
fn test_typedef_to_std() {
let hdr = indoc! {"
#include <string>
@@ -4955,6 +5022,78 @@
}
#[test]
+fn test_union_nonpod() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ union A {
+ uint32_t a;
+ float b;
+ };
+ "};
+ let rs = quote! {};
+ run_test("", hdr, rs, &["A"], &[]);
+}
+
+#[test]
+fn test_union_pod() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ union A {
+ uint32_t a;
+ float b;
+ };
+ "};
+ let rs = quote! {};
+ run_test_expect_fail("", hdr, rs, &[], &["A"]);
+}
+
+#[test]
+fn test_type_aliased_anonymous_union_ignored() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ namespace test {
+ typedef union {
+ int a;
+ } Union;
+ };
+ "};
+ let rs = quote! {};
+ run_test("", hdr, rs, &["test::Union"], &[]);
+}
+
+#[test]
+fn test_type_aliased_anonymous_struct_ignored() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ namespace test {
+ typedef struct {
+ int a;
+ } Struct;
+ };
+ "};
+ let rs = quote! {};
+ run_test("", hdr, rs, &["test::Struct"], &[]);
+}
+
+#[test]
+fn test_type_aliased_anonymous_nested_struct_ignored() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ namespace test {
+ struct Outer {
+ typedef struct {
+ int a;
+ } Struct;
+ int b;
+ };
+ };
+ "};
+ let rs = quote! {};
+ run_test("", hdr, rs, &["test::Outer_Struct"], &[]);
+}
+
+#[ignore] // https://github.com/google/autocxx/issues/1251
+#[test]
fn test_double_underscores_ignored() {
let hdr = indoc! {"
#include <cstdint>
@@ -5756,7 +5895,17 @@
} // namespace spanner
"};
let rs = quote! {};
- run_test("", hdr, rs, &["spanner::Database", "spanner::Row"], &[]);
+ run_test_ex(
+ "",
+ hdr,
+ rs,
+ directives_from_lists(&["spanner::Database", "spanner::Row"], &[], None),
+ // This is normally a valid warning for generating bindings for this code, but we're doing
+ // it on purpose as a regression test on minimized code so we'll just ignore it.
+ make_clang_optional_arg_adder(&[], &["-Wno-delete-abstract-non-virtual-dtor"]),
+ None,
+ None,
+ );
}
#[test]
@@ -5921,6 +6070,7 @@
None,
None,
"unsafe_ffi",
+ None,
) {
Err(TestError::CppBuild(_)) => {} // be sure this fails due to a static_assert
// rather than some runtime problem
@@ -7025,6 +7175,35 @@
}
#[test]
+fn test_extern_rust_fn_callback() {
+ let hdr = indoc! {"
+ struct a {};
+ "};
+ let hexathorpe = Token);
+ let rs = quote! {
+ autocxx::include_cpp! {
+ #hexathorpe include "input.h"
+ safety!(unsafe_ffi)
+ generate!("a")
+ }
+
+ use ffi::a;
+ use std::pin::Pin;
+
+ #[autocxx::extern_rust::extern_rust_function]
+ pub fn called_from_cpp(_a: Pin<&mut a>) {}
+
+ fn main() {}
+ };
+ do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+// TODO: there are various other tests for extern_rust_fn we should add:
+// 1) taking mutable and immutable references
+// 2) ensuring that types on which the signature depends as receiver,
+// parameters and return are not garbage collected
+
+#[test]
fn test_rust_reference_no_autodiscover() {
let hdr = indoc! {"
#include <cstdint>
@@ -7054,6 +7233,55 @@
}
#[test]
+fn test_rust_box() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ #include <cxx.h>
+
+ struct RustType;
+ inline uint32_t take_rust_box(rust::Box<RustType>) {
+ return 4;
+ }
+ "};
+ let rs = quote! {
+ let foo = Box::new(RustType(3));
+ let result = ffi::take_rust_box(foo);
+ assert_eq!(result, 4);
+ };
+ run_test_ex(
+ "",
+ hdr,
+ rs,
+ directives_from_lists(&["take_rust_box"], &[], None),
+ None,
+ None,
+ Some(quote! {
+ #[autocxx::extern_rust::extern_rust_type]
+ pub struct RustType(i32);
+ }),
+ );
+}
+
+#[test]
+fn test_rust_reference_no_autodiscover_no_usage() {
+ let rs = quote! {
+ let _ = RustType(3);
+ };
+ run_test_ex(
+ "",
+ "",
+ rs,
+ directives_from_lists(&[], &[], None),
+ None,
+ None,
+ Some(quote! {
+ #[autocxx::extern_rust::extern_rust_type]
+ pub struct RustType(i32);
+ }),
+ );
+}
+
+#[test]
#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
// TODO - replace make_clang_arg_adder with something that knows how to add an MSVC-suitable
// directive for the cc build.
@@ -7078,7 +7306,7 @@
}
#[test]
-fn test_box() {
+fn test_box_extern_rust_type() {
let hdr = indoc! {"
#include <cxx.h>
struct Foo;
@@ -7106,6 +7334,47 @@
}
#[test]
+fn test_box_return_placement_new() {
+ let hdr = indoc! {"
+ #include <cxx.h>
+ struct Foo;
+ struct Foo2;
+ struct Ret {};
+ inline Ret take_box(rust::Box<Foo>, rust::Box<Foo2>) {
+ return Ret{};
+ }
+ "};
+ run_test_ex(
+ "",
+ hdr,
+ quote! {
+ let _ = ffi::take_box(
+ Box::new(Foo { a: "Hello".into() }),
+ Box::new(bar::Foo2 { a: "Goodbye".into() })
+ );
+ },
+ quote! {
+ generate!("take_box")
+ extern_rust_type!(Foo)
+ generate!("Ret")
+ },
+ None,
+ None,
+ Some(quote! {
+ pub struct Foo {
+ a: String,
+ }
+ mod bar {
+ #[autocxx::extern_rust::extern_rust_type]
+ pub struct Foo2 {
+ pub a: String,
+ }
+ }
+ }),
+ );
+}
+
+#[test]
fn test_box_via_extern_rust() {
let hdr = indoc! {"
#include <cxx.h>
@@ -7132,6 +7401,32 @@
}
#[test]
+fn test_box_via_extern_rust_no_include_cpp() {
+ let hdr = indoc! {"
+ #include <cxx.h>
+ struct Foo;
+ inline void take_box(rust::Box<Foo>) {
+ }
+ "};
+ do_run_test_manual(
+ "",
+ hdr,
+ quote! {
+ #[autocxx::extern_rust::extern_rust_type]
+ pub struct Foo {
+ a: String,
+ }
+
+ fn main() {
+ }
+ },
+ Some(Box::new(EnableAutodiscover)),
+ None,
+ )
+ .unwrap();
+}
+
+#[test]
fn test_box_via_extern_rust_in_mod() {
let hdr = indoc! {"
#include <cxx.h>
@@ -7220,14 +7515,24 @@
let hdr = indoc! {"
#include <cstdint>
inline void take_int(int&) {}
- inline void take_uin16(uint16_t&) {}
- inline void take_char16(char16_t &) {}
+ inline void take_uint16(uint16_t) {}
+ inline void take_us(unsigned short) {}
+ inline void take_char16(char16_t) {}
+ inline void take_uint16_ref(uint16_t&) {}
+ inline void take_char16_ref(char16_t &) {}
"};
run_test(
"",
hdr,
quote! {},
- &["take_int", "take_uin16", "take_char16"],
+ &[
+ "take_int",
+ "take_uint16",
+ "take_char16",
+ "take_uint16_ref",
+ "take_char16_ref",
+ "take_us",
+ ],
&[],
);
}
@@ -7950,10 +8255,10 @@
assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
let obs_superclass = obs.as_ref().unwrap(); // &subclass
- let obs_superclass = unsafe { std::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
+ let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
ffi::TriggerTestObserverA(obs_superclass);
assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
- std::mem::drop(obs);
+ core::mem::drop(obs);
Lazy::force(&STATUS).lock().unwrap().a_called = false;
assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
@@ -7970,7 +8275,7 @@
ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
Lazy::force(&STATUS).lock().unwrap().a_called = false;
- std::mem::drop(obs);
+ core::mem::drop(obs);
assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
@@ -8085,11 +8390,11 @@
assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
let obs_superclass = obs.as_ref().unwrap(); // &subclass
- let obs_superclass = unsafe { std::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
+ let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
ffi::TriggerTestObserverA(obs_superclass);
assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
- std::mem::drop(obs);
+ core::mem::drop(obs);
Lazy::force(&STATUS).lock().unwrap().a_called = false;
assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
@@ -8106,7 +8411,7 @@
assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
Lazy::force(&STATUS).lock().unwrap().a_called = false;
- std::mem::drop(obs);
+ core::mem::drop(obs);
assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
@@ -8118,7 +8423,7 @@
let obs_superclass_ptr: *const ffi::TestObserver = obs.as_ref().borrow().as_ref();
// Retain just a pointer on the Rust side, so there is no Rust-side
// ownership.
- std::mem::drop(obs);
+ core::mem::drop(obs);
assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
@@ -9182,7 +9487,7 @@
};
"};
let rs = quote! {
- use autocxx::moveit::EmplaceUnpinned;
+ use autocxx::moveit::Emplace;
let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
up_obj.as_mut().unwrap().set(42);
assert_eq!(up_obj.get(), 42);
@@ -9206,7 +9511,6 @@
};
"};
let rs = quote! {
- use autocxx::moveit::EmplaceUnpinned;
use autocxx::moveit::Emplace;
let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
up_obj.pin_mut().set(666);
@@ -9270,7 +9574,7 @@
assert!(ffi::was_delete_called());
ffi::reset_flags();
{
- use autocxx::moveit::EmplaceUnpinned;
+ use autocxx::moveit::Emplace;
let _ = cxx::UniquePtr::emplace(ffi::A::new());
}
assert!(ffi::was_delete_called());
@@ -9638,8 +9942,7 @@
("F", "struct F { uint32_t a; uint8_t b; };"),
];
let type_definitions = TYPES.iter().map(|(_, def)| *def).join("\n");
- let function_definitions = TYPES.iter().map(|(name, _)| format!("inline size_t get_sizeof_{}() {{ return sizeof({}); }}\ninline size_t get_alignof_{}() {{ return alignof({}); }}\n",
- name, name, name, name)).join("\n");
+ let function_definitions = TYPES.iter().map(|(name, _)| format!("inline size_t get_sizeof_{name}() {{ return sizeof({name}); }}\ninline size_t get_alignof_{name}() {{ return alignof({name}); }}\n")).join("\n");
let hdr = format!(
indoc! {"
#include <cstdint>
@@ -9653,12 +9956,9 @@
let allowlist_fns: Vec<String> = TYPES
.iter()
.flat_map(|(name, _)| {
- [
- format!("get_sizeof_{}", name),
- format!("get_alignof_{}", name),
- ]
- .to_vec()
- .into_iter()
+ [format!("get_sizeof_{name}"), format!("get_alignof_{name}")]
+ .to_vec()
+ .into_iter()
})
.collect_vec();
let allowlist_types: Vec<String> = TYPES.iter().map(|(name, _)| name.to_string()).collect_vec();
@@ -9672,15 +9972,15 @@
let allowlist_both: Vec<&str> = allowlist_both.iter().map(AsRef::as_ref).collect_vec();
let rs = TYPES.iter().fold(quote! {}, |mut accumulator, (name, _)| {
let get_align_symbol =
- proc_macro2::Ident::new(&format!("get_alignof_{}", name), Span::call_site());
+ proc_macro2::Ident::new(&format!("get_alignof_{name}"), Span::call_site());
let get_size_symbol =
- proc_macro2::Ident::new(&format!("get_sizeof_{}", name), Span::call_site());
+ proc_macro2::Ident::new(&format!("get_sizeof_{name}"), Span::call_site());
let type_symbol = proc_macro2::Ident::new(name, Span::call_site());
accumulator.extend(quote! {
let c_size = ffi::#get_size_symbol();
let c_align = ffi::#get_align_symbol();
- assert_eq!(std::mem::size_of::<ffi::#type_symbol>(), c_size);
- assert_eq!(std::mem::align_of::<ffi::#type_symbol>(), c_align);
+ assert_eq!(core::mem::size_of::<ffi::#type_symbol>(), c_size);
+ assert_eq!(core::mem::align_of::<ffi::#type_symbol>(), c_align);
});
accumulator
});
@@ -9775,6 +10075,24 @@
}
#[test]
+fn test_issue_1238() {
+ let hdr = indoc! {"
+ class b;
+ class c;
+ class f {
+ b d();
+ };
+ class S2E {
+ public:
+ f e;
+ b &d(c *) const;
+ };
+ "};
+ let rs = quote! {};
+ run_test("", hdr, rs, &["S2E"], &[]);
+}
+
+#[test]
fn test_issue486_multi_types() {
let hdr = indoc! {"
namespace a {
@@ -9849,6 +10167,13 @@
void a() const {}
};
+ struct AllExplicitlyDefaulted {
+ AllExplicitlyDefaulted() = default;
+ AllExplicitlyDefaulted(const AllExplicitlyDefaulted&) = default;
+ AllExplicitlyDefaulted(AllExplicitlyDefaulted&&) = default;
+ void a() const {};
+ };
+
struct PublicDeleted {
PublicDeleted() = delete;
PublicDeleted(const PublicDeleted&) = delete;
@@ -10390,6 +10715,12 @@
test_movable![ffi::AllImplicitlyDefaulted];
test_call_a![ffi::AllImplicitlyDefaulted];
+ test_constructible![ffi::AllExplicitlyDefaulted];
+ test_make_unique![ffi::AllExplicitlyDefaulted];
+ test_copyable![ffi::AllExplicitlyDefaulted];
+ test_movable![ffi::AllExplicitlyDefaulted];
+ test_call_a![ffi::AllExplicitlyDefaulted];
+
test_call_a![ffi::PublicDeleted];
test_copyable![ffi::PublicDeletedDefault];
@@ -10763,6 +11094,7 @@
rs,
&[
"AllImplicitlyDefaulted",
+ "AllExplicitlyDefaulted",
"PublicDeleted",
"PublicDeletedDefault",
"PublicDeletedCopy",
@@ -11097,7 +11429,7 @@
"Function",
]
.into_iter()
- .flat_map(|l| [format!("{} line A", l), format!("{} line B", l)])
+ .flat_map(|l| [format!("{l} line A"), format!("{l} line B")])
.collect_vec();
run_test_ex(
@@ -11171,6 +11503,43 @@
}
#[test]
+fn test_enum_in_ns() {
+ let hdr = indoc! {"
+ namespace a {
+ enum b {};
+ } // namespace
+ "};
+ run_test("", hdr, quote! {}, &["a::b"], &[]);
+}
+
+#[test]
+fn test_recursive_field() {
+ let hdr = indoc! {"
+ #include <memory>
+ struct A {
+ std::unique_ptr<A> a;
+ };
+ "};
+ run_test("", hdr, quote! {}, &["A"], &[]);
+}
+
+#[test]
+fn test_recursive_field_indirect() {
+ let hdr = indoc! {"
+ #include <memory>
+ struct B;
+ struct A {
+ std::unique_ptr<B> a;
+ };
+ struct B {
+ std::unique_ptr<A> a1;
+ A a2;
+ };
+ "};
+ run_test("", hdr, quote! {}, &["A", "B"], &[]);
+}
+
+#[test]
fn test_typedef_unsupported_type_pub() {
let hdr = indoc! {"
#include <set>
@@ -11572,6 +11941,306 @@
);
}
+#[test]
+fn test_issue_1143() {
+ let hdr = indoc! {
+ "namespace mapnik {
+ class Map {
+ public:
+ int &a(long);
+ };
+ }"
+ };
+
+ run_test("", hdr, quote! {}, &["mapnik::Map"], &[]);
+}
+
+#[test]
+fn test_issue_1170() {
+ let hdr = indoc! {
+ "#include <vector>
+ struct a {
+ enum b {} c;
+ } Loc;
+ struct Arch {
+ std::vector<a> d();
+ } DeterministicRNG;"
+ };
+ run_test("", hdr, quote! {}, &["Arch"], &[]);
+}
+
+// https://github.com/google/autocxx/issues/774
+#[test]
+fn test_virtual_methods() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ #include <memory>
+ class Base {
+ public:
+ Base() {}
+ virtual ~Base() {}
+
+ virtual int a() = 0;
+
+ virtual void b(int) = 0;
+ virtual void b(bool) = 0;
+
+ virtual int c() const = 0;
+ virtual int c() = 0;
+ };
+ class FullyDefined : public Base {
+ public:
+ int a() { return 0; }
+
+ void b(int) { }
+ void b(bool) { }
+
+ int c() const { return 1; }
+ int c() { return 2; }
+ };
+ class Partial1 : public Base {
+ public:
+ int a() { return 0; }
+
+ void b(bool) {}
+ };
+
+ class Partial2 : public Base {
+ public:
+ int a() { return 0; }
+
+ void b(int) { }
+ void b(bool) { }
+
+ int c() const { return 1; }
+ };
+
+ class Partial3 : public Base {
+ public:
+ int a() { return 0; }
+
+ void b(int) { }
+
+ int c() const { return 1; }
+ int c() { return 2; }
+ };
+
+ class Partial4 : public Base {
+ public:
+ int a() { return 0; }
+
+ void b(int) { }
+ void b(bool) = 0;
+
+ int c() const { return 1; }
+ int c() { return 2; }
+ };
+
+ // TODO: currently this class cannot be detected as virtual as there
+ // is no metadata captured to show that this destructor is virtual
+ // uncommenting this (as well as corresponding sections below) gives a
+ // 'instantiation of abstract class' error.
+ // class Partial5 : public Base {
+ // public:
+ // ~Partial5() = 0;
+
+ // int a() { return 0; }
+
+ // void b(int) { }
+ // void b(bool) { }
+
+ // int c() const { return 1; }
+ // int c() { return 2; }
+ // };
+
+ "};
+ let rs = quote! {
+ static_assertions::assert_impl_all!(ffi::FullyDefined: moveit::CopyNew);
+ static_assertions::assert_not_impl_any!(ffi::Partial1: moveit::CopyNew);
+ static_assertions::assert_not_impl_any!(ffi::Partial2: moveit::CopyNew);
+ static_assertions::assert_not_impl_any!(ffi::Partial3: moveit::CopyNew);
+ static_assertions::assert_not_impl_any!(ffi::Partial4: moveit::CopyNew);
+ // static_assertions::assert_not_impl_any!(ffi::Partial5: moveit::CopyNew);
+ let _c1 = ffi::FullyDefined::new().within_unique_ptr();
+ };
+ run_test(
+ "",
+ hdr,
+ rs,
+ &[
+ "FullyDefined",
+ "Partial1",
+ "Partial2",
+ "Partial3",
+ "Partial4",
+ // "Partial5"
+ ],
+ &[],
+ );
+}
+
+#[test]
+fn test_issue_1192() {
+ let hdr = indoc! {
+ "#include <vector>
+ #include <cstdint>
+ template <typename B>
+ struct A {
+ B a;
+ };
+ struct VecThingy {
+ A<uint32_t> contents[2];
+ };
+ struct MyStruct {
+ VecThingy vec;
+ };"
+ };
+ run_test_ex(
+ "",
+ hdr,
+ quote! {},
+ quote! {
+
+ extern_cpp_type!("VecThingy", crate::VecThingy)
+ pod!("VecThingy")
+
+ generate_pod!("MyStruct")
+ },
+ None,
+ None,
+ Some(quote! {
+ // VecThingy isn't necessarily 128 bits long.
+ // This test doesn't actually allocate one.
+ #[repr(transparent)]
+ pub struct VecThingy(pub u128);
+
+ unsafe impl cxx::ExternType for VecThingy {
+ type Id = cxx::type_id!("VecThingy");
+ type Kind = cxx::kind::Trivial;
+ }
+ }),
+ );
+}
+
+#[test]
+fn test_issue_1214() {
+ let hdr = indoc! {"
+ #include <cstdint>
+ enum class C: uint16_t {
+ A,
+ B,
+ };
+ "};
+ run_test("", hdr, quote! {}, &["C"], &[]);
+}
+
+#[test]
+fn test_issue_1229() {
+ let hdr = indoc! {"
+ struct Thing {
+ float id;
+
+ Thing(float id) : id(id) {}
+ };
+
+ struct Item {
+ float id;
+
+ Item(float id) : id(id) {}
+ };
+ "};
+ let hexathorpe = Token);
+ let rs = quote! {
+ use autocxx::WithinUniquePtr;
+
+ autocxx::include_cpp! {
+ #hexathorpe include "input.h"
+ name!(thing)
+ safety!(unsafe)
+ generate!("Thing")
+ }
+ autocxx::include_cpp! {
+ #hexathorpe include "input.h"
+ name!(item)
+ safety!(unsafe)
+ generate!("Item")
+ }
+
+ fn main() {
+ let _thing = thing::Thing::new(15.).within_unique_ptr();
+ let _item = item::Item::new(15.).within_unique_ptr();
+ }
+ };
+
+ do_run_test_manual("", hdr, rs, None, None).unwrap();
+}
+
+#[test]
+#[ignore] // https://github.com/google/autocxx/issues/1265
+fn test_issue_1265() {
+ let hdr = indoc! {"
+ #include <string>
+
+ class Test
+ {
+ public:
+ explicit Test(std::string string)
+ : string(std::move(string))
+ {
+ }
+
+ Test() = delete;
+
+ [[nodiscard]] auto get_string() const -> std::string const& { return this->string; }
+
+ private:
+ std::string string;
+ };
+ "};
+ run_test_ex(
+ "",
+ hdr,
+ quote! {
+ run();
+ },
+ directives_from_lists(&["Test"], &[], None),
+ None,
+ None,
+ Some(quote! {
+ fn run() {
+ let str0 = "string";
+ let str1 = "another string";
+ let ptr0 = UniquePtr::emplace(ffi::Test::new(str0));
+ let ptr1 = UniquePtr::emplace(ffi::Test::new(str1));
+ println!("0: {}", ptr0.get_string());
+ println!("1: {}", ptr1.get_string());
+ moveit!(let mut ref0 = &move *ptr0);
+ moveit!(let mut ref1 = &move *ptr1);
+ println!("0: {}", ref0.get_string());
+ println!("1: {}", ref1.get_string());
+ println!("swap");
+ core::mem::swap(&mut *ref0, &mut *ref1);
+ println!("0: {}", ref0.get_string());
+ println!("1: {}", ref1.get_string());
+ }
+ }),
+ )
+}
+
+#[test]
+fn test_ignore_va_list() {
+ let hdr = indoc! {"
+ #include <stdarg.h>
+ class A {
+ public:
+ A() {}
+ void fn(va_list) {}
+ };
+ "};
+ let rs = quote! {};
+ run_test("", hdr, rs, &["A"], &[]);
+}
+
// Yet to test:
// - Ifdef
// - Out param pointers
diff --git a/third_party/autocxx/macro/BUILD b/third_party/autocxx/macro/BUILD
index 4cc658e..a91156e 100644
--- a/third_party/autocxx/macro/BUILD
+++ b/third_party/autocxx/macro/BUILD
@@ -25,6 +25,6 @@
"@crate_index//:proc-macro-error",
"@crate_index//:proc-macro2",
"@crate_index//:quote",
- "@crate_index//:syn",
+ "@crate_index//:syn-2.0.28",
],
)
diff --git a/third_party/autocxx/macro/Cargo.toml b/third_party/autocxx/macro/Cargo.toml
index 1f81ab1..00f7e28 100644
--- a/third_party/autocxx/macro/Cargo.toml
+++ b/third_party/autocxx/macro/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx-macro"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
license = "MIT OR Apache-2.0"
description = "Safe autogenerated interop between Rust and C++"
@@ -21,11 +21,11 @@
proc-macro = true
[dependencies]
-autocxx-parser = { path="../parser", version="=0.22.3" }
+autocxx-parser = { path = "../parser", version = "=0.26.0" }
proc-macro-error = "1.0"
proc-macro2 = "1.0.11"
quote = "1.0"
[dependencies.syn]
-version = "1.0"
-features = [ "full" ]
+version = "2"
+features = ["full"]
diff --git a/third_party/autocxx/macro/src/lib.rs b/third_party/autocxx/macro/src/lib.rs
index 01ccd69..6cdb74a 100644
--- a/third_party/autocxx/macro/src/lib.rs
+++ b/third_party/autocxx/macro/src/lib.rs
@@ -37,7 +37,7 @@
abort!(s.vis.span(), "Rust subclasses of C++ types must by public");
}
let id = &s.ident;
- let cpp_ident = Ident::new(&format!("{}Cpp", id), Span::call_site());
+ let cpp_ident = Ident::new(&format!("{id}Cpp"), Span::call_site());
let input = quote! {
cpp_peer: autocxx::subclass::CppSubclassCppPeerHolder<ffi:: #cpp_ident>
};
diff --git a/third_party/autocxx/parser/BUILD b/third_party/autocxx/parser/BUILD
index 1e1cd3e..8ad9480 100644
--- a/third_party/autocxx/parser/BUILD
+++ b/third_party/autocxx/parser/BUILD
@@ -32,7 +32,7 @@
"@crate_index//:quote",
"@crate_index//:serde",
"@crate_index//:serde_json",
- "@crate_index//:syn",
+ "@crate_index//:syn-2.0.28",
"@crate_index//:thiserror",
],
)
diff --git a/third_party/autocxx/parser/Cargo.toml b/third_party/autocxx/parser/Cargo.toml
index 3668e65..07a1f1e 100644
--- a/third_party/autocxx/parser/Cargo.toml
+++ b/third_party/autocxx/parser/Cargo.toml
@@ -8,7 +8,7 @@
[package]
name = "autocxx-parser"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
license = "MIT OR Apache-2.0"
description = "Safe autogenerated interop between Rust and C++"
@@ -21,16 +21,16 @@
log = "0.4"
proc-macro2 = "1.0"
quote = "1.0"
-serde = { version = "1.0", features = [ "derive" ]}
+serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"
once_cell = "1.10"
itertools = "0.10.3"
-indexmap = { version="1.8", features = ["serde"]}
+indexmap = { version = "1.8", features = ["serde"] }
serde_json = "1.0"
[dependencies.syn]
-version = "1.0.39"
-features = [ "full", "extra-traits" ]
+version = "2"
+features = ["full", "extra-traits"]
[features]
reproduction_case = []
diff --git a/third_party/autocxx/parser/src/config.rs b/third_party/autocxx/parser/src/config.rs
index 8d30249..3634295 100644
--- a/third_party/autocxx/parser/src/config.rs
+++ b/third_party/autocxx/parser/src/config.rs
@@ -29,7 +29,7 @@
use quote::quote;
-#[derive(PartialEq, Clone, Debug, Hash)]
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
pub enum UnsafePolicy {
AllFunctionsSafe,
AllFunctionsUnsafe,
@@ -101,7 +101,7 @@
fn to_bindgen_item(&self) -> String {
match self {
AllowlistEntry::Item(i) => i.clone(),
- AllowlistEntry::Namespace(ns) => format!("{}::.*", ns),
+ AllowlistEntry::Namespace(ns) => format!("{ns}::.*"),
}
}
}
@@ -165,7 +165,7 @@
pub struct RustFun {
pub path: RustPath,
pub sig: Signature,
- pub receiver: Option<Ident>,
+ pub has_receiver: bool,
}
impl std::fmt::Debug for RustFun {
@@ -240,7 +240,7 @@
let (possible_directives, to_parse, parse_completely) = if has_hexathorpe {
(&get_directives().need_hexathorpe, input, false)
} else {
- input.parse::<Option<syn::token::Bang>>()?;
+ input.parse::<Option<syn::token::Not>>()?;
syn::parenthesized!(args in input);
(&get_directives().need_exclamation, &args, true)
};
@@ -250,7 +250,7 @@
None => {
return Err(syn::Error::new(
ident.span(),
- format!("expected {}", all_possible),
+ format!("expected {all_possible}"),
));
}
Some(directive) => directive.parse(to_parse, &mut config, &ident.span())?,
@@ -258,7 +258,7 @@
if parse_completely && !to_parse.is_empty() {
return Err(syn::Error::new(
ident.span(),
- format!("found unexpected input within the directive {}", ident_str),
+ format!("found unexpected input within the directive {ident_str}"),
));
}
if input.is_empty() {
@@ -362,6 +362,7 @@
|| self.is_subclass_holder(cpp_name)
|| self.is_subclass_cpp(cpp_name)
|| self.is_rust_fun(cpp_name)
+ || self.is_rust_type_name(cpp_name)
|| self.is_concrete_type(cpp_name)
|| match &self.allowlist {
Allowlist::Unspecified(_) => panic!("Eek no allowlist yet"),
@@ -408,10 +409,14 @@
}
pub fn is_rust_type(&self, id: &Ident) -> bool {
+ let id_string = id.to_string();
+ self.is_rust_type_name(&id_string) || self.is_subclass_holder(&id_string)
+ }
+
+ fn is_rust_type_name(&self, possible_ty: &str) -> bool {
self.rust_types
.iter()
- .any(|rt| rt.get_final_ident() == &id.to_string())
- || self.is_subclass_holder(&id.to_string())
+ .any(|rt| rt.get_final_ident() == possible_ty)
}
fn is_rust_fun(&self, possible_fun: &str) -> bool {
diff --git a/third_party/autocxx/parser/src/directives.rs b/third_party/autocxx/parser/src/directives.rs
index 70c88fc..1cb35fb 100644
--- a/third_party/autocxx/parser/src/directives.rs
+++ b/third_party/autocxx/parser/src/directives.rs
@@ -275,7 +275,7 @@
}
fn allowlist_err_to_syn_err(err: AllowlistErr, span: &Span) -> syn::Error {
- syn::Error::new(*span, format!("{}", err))
+ syn::Error::new(*span, format!("{err}"))
}
struct StringList<SET, GET>(SET, GET)
@@ -472,7 +472,7 @@
config.extern_rust_funs.push(RustFun {
path,
sig,
- receiver: None,
+ has_receiver: false,
});
Ok(())
}
diff --git a/third_party/autocxx/parser/src/file_locations.rs b/third_party/autocxx/parser/src/file_locations.rs
index 6b3c58a..29acb48 100644
--- a/third_party/autocxx/parser/src/file_locations.rs
+++ b/third_party/autocxx/parser/src/file_locations.rs
@@ -77,7 +77,7 @@
FileLocationStrategy::Custom(_) => panic!("Should never happen in the macro"),
FileLocationStrategy::UnknownMaybeFromOutdir | FileLocationStrategy::FromOutDir(_) => {
let fname = config.get_rs_filename();
- let fname = format!("/{}/{}/{}", BUILD_DIR_NAME, RS_DIR_NAME, fname);
+ let fname = format!("/{BUILD_DIR_NAME}/{RS_DIR_NAME}/{fname}");
// rust-analyzer works better if we ask Rust to do the path
// concatenation rather than doing it in proc-macro code.
// proc-macro code does not itself have access to the value of
diff --git a/third_party/autocxx/parser/src/path.rs b/third_party/autocxx/parser/src/path.rs
index 415b2ef..e3a0f9f 100644
--- a/third_party/autocxx/parser/src/path.rs
+++ b/third_party/autocxx/parser/src/path.rs
@@ -58,7 +58,7 @@
fn parse(input: ParseStream) -> ParseResult<Self> {
let id: Ident = input.parse()?;
let mut p = RustPath::new_from_ident(id);
- while input.parse::<Option<syn::token::Colon2>>()?.is_some() {
+ while input.parse::<Option<syn::token::PathSep>>()?.is_some() {
let id: Ident = input.parse()?;
p = p.append(id);
}
diff --git a/third_party/autocxx/src/lib.rs b/third_party/autocxx/src/lib.rs
index 4b9f26b..fe235a9 100644
--- a/third_party/autocxx/src/lib.rs
+++ b/third_party/autocxx/src/lib.rs
@@ -1,4 +1,6 @@
#![doc = include_str!("../README.md")]
+#![cfg_attr(nightly, feature(unsize))]
+#![cfg_attr(nightly, feature(dispatch_from_dyn))]
// Copyright 2020 Google LLC
//
@@ -19,7 +21,7 @@
pub mod subclass;
mod value_param;
-pub use reference_wrapper::{CppMutRef, CppPin, CppRef};
+pub use reference_wrapper::{AsCppMutRef, AsCppRef, CppMutRef, CppPin, CppRef, CppUniquePtrPin};
#[cfg_attr(doc, aquamarine::aquamarine)]
/// Include some C++ headers in your Rust project.
@@ -82,7 +84,7 @@
///
/// * *Recommended*: provide various [`generate`] directives in the
/// [`include_cpp`] macro. This can specify functions or types.
-/// * *Not recommended*: in your `build.rs`, call [`Builder::auto_allowlist`].
+/// * *Not recommended*: in your `build.rs`, call `Builder::auto_allowlist`.
/// This will attempt to spot _uses_ of FFI bindings anywhere in your Rust code
/// and build the allowlist that way. This is experimental and has known limitations.
/// * *Strongly not recommended*: use [`generate_all`]. This will attempt to
@@ -216,7 +218,7 @@
/// A concrete type to make, for example
/// `concrete!("Container<Contents>")`.
-/// All types msut already be on the allowlist by having used
+/// All types must already be on the allowlist by having used
/// `generate!` or similar.
///
/// A directive to be included inside
@@ -265,9 +267,12 @@
/// policy available here:
/// `safety!(unsafe_references_wrapped)`
/// This policy treats C++ references as scary and requires
-/// them to be wrapped in a `CppRef` type. This `CppRef`
-/// type is implemented within the generated bindings but
-/// follows the contract of [`CppRef`].
+/// them to be wrapped in a `CppRef` type: see [`CppRef`].
+/// This only works on nightly Rust because it
+/// depends upon an unstable feature
+/// (`arbitrary_self_types`). However, it should
+/// eliminate all undefined behavior related to Rust's
+/// stricter aliasing rules than C++.
#[macro_export]
macro_rules! safety {
($($tt:tt)*) => { $crate::usage!{$($tt)*} };
@@ -286,12 +291,43 @@
/// Indicates that a C++ type is not to be generated by autocxx in this case,
/// but instead should refer to some pre-existing Rust type.
-/// Note that the size and alignment of this type *must* be correct.
-/// If you wish for the type to be POD, you can use a `pod!` directive too.
+///
+/// If you wish for the type to be POD, you can use a `pod!` directive too
+/// (but see the "requirements" section below).
///
/// The syntax is:
/// `extern_cpp_type!("CppNameGoesHere", path::to::rust::type)`
///
+/// Generally speaking, this should be used only to refer to types
+/// generated elsewhere by `autocxx` or `cxx` to ensure that they meet
+/// all the right requirements. It's possible - but fragile - to
+/// define such types yourself.
+///
+/// # Requirements for externally defined Rust types
+///
+/// It's generally expected that you would make such a type
+/// in Rust using a separate `include_cpp!` macro, or
+/// a manual `#[cxx::bridge]` directive somehwere. That is, this
+/// directive is intended mainly for use in cross-linking different
+/// sets of bindings in different mods, rather than truly to point to novel
+/// external types.
+///
+/// But with that in mind, here are the requirements you must stick to.
+///
+/// For non-POD external types:
+/// * The size and alignment of this type *must* be correct.
+///
+/// For POD external types:
+/// * As above
+/// * Your type must correspond to the requirements of
+/// [`cxx::kind::Trivial`]. In general, that means, no move constructor
+/// and no destructor. If you generate this type using `cxx` itself
+/// (or `autocxx`) this will be enforced using `static_assert`s
+/// within the generated C++ code. Without using those tools, you're
+/// on your own for determining this... and it's hard because the presence
+/// of particular fields or base classes may well result in your type
+/// violating those rules.
+///
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
@@ -495,6 +531,25 @@
/// for instance. This will contribute to an `extern "Rust"` section of the
/// generated `cxx` bindings, and this type will appear in the C++ header
/// generated for use in C++.
+ ///
+ /// # Finding these bindings from C++
+ ///
+ /// You will likely need to forward-declare this type within your C++ headers
+ /// before you can use it in such function signatures. autocxx can't generate
+ /// headers (with this type definition) until it's parsed your header files;
+ /// logically therefore if your header files mention one of these types
+ /// it's impossible for them to see the definition of the type.
+ ///
+ /// If you're using multiple sets of `include_cpp!` directives, or
+ /// a mixture of `include_cpp!` and `#[cxx::bridge]` bindings, then you
+ /// may be able to `#include "cxxgen.h"` to refer to the generated C++
+ /// function prototypes. In this particular circumstance, you'll want to know
+ /// how exactly the `cxxgen.h` header is named, because one will be
+ /// generated for each of the sets of bindings encountered. The pattern
+ /// can be set manually using `autocxxgen`'s command-line options. If you're
+ /// using `autocxx`'s `build.rs` support, those headers will be named
+ /// `cxxgen.h`, `cxxgen1.h`, `cxxgen2.h` according to the order in which
+ /// the `include_cpp` or `cxx::bridge` bindings are encountered.
pub use autocxx_macro::extern_rust_type;
/// Declare that a given function is a Rust function which is to be exported
@@ -504,6 +559,9 @@
/// #[extern_rust_function]
/// pub fn call_me_from_cpp() { }
/// ```
+ ///
+ /// See [`extern_rust_type`] for details of how to find the generated
+ /// declarations from C++.
pub use autocxx_macro::extern_rust_function;
}
@@ -519,6 +577,7 @@
/// and implemented by any (autocxx-related) [`moveit::New`].
pub trait WithinUniquePtr {
type Inner: UniquePtrTarget + MakeCppStorage;
+ /// Create this item within a [`cxx::UniquePtr`].
fn within_unique_ptr(self) -> cxx::UniquePtr<Self::Inner>;
}
@@ -527,13 +586,23 @@
/// and implemented by any (autocxx-related) [`moveit::New`].
pub trait WithinBox {
type Inner;
+ /// Create this item inside a pinned box. This is a good option if you
+ /// want to own this object within Rust, and want to create Rust references
+ /// to it.
fn within_box(self) -> Pin<Box<Self::Inner>>;
+ /// Create this item inside a [`CppPin`]. This is a good option if you
+ /// want to own this option within Rust, but you want to create [`CppRef`]
+ /// C++ references to it. You'd only want to choose that option if you have
+ /// enabled the C++ reference wrapper support by using the
+ /// `safety!(unsafe_references_wrapped`) directive. If you haven't done
+ /// that, ignore this function.
+ fn within_cpp_pin(self) -> CppPin<Self::Inner>;
}
use cxx::kind::Trivial;
use cxx::ExternType;
+use moveit::Emplace;
use moveit::MakeCppStorage;
-use moveit::{Emplace, EmplaceUnpinned};
impl<N, T> WithinUniquePtr for N
where
@@ -554,6 +623,9 @@
fn within_box(self) -> Pin<Box<T>> {
Box::emplace(self)
}
+ fn within_cpp_pin(self) -> CppPin<Self::Inner> {
+ CppPin::from_pinned_box(Box::emplace(self))
+ }
}
/// Emulates the [`WithinUniquePtr`] trait, but for trivial (plain old data) types.
@@ -624,9 +696,12 @@
pub use crate::c_void;
pub use crate::cpp_semantics;
pub use crate::include_cpp;
+ pub use crate::AsCppMutRef;
+ pub use crate::AsCppRef;
pub use crate::CppMutRef;
pub use crate::CppPin;
pub use crate::CppRef;
+ pub use crate::CppUniquePtrPin;
pub use crate::PinMut;
pub use crate::RValueParam;
pub use crate::ValueParam;
@@ -638,7 +713,6 @@
pub use moveit::moveit;
pub use moveit::new::New;
pub use moveit::Emplace;
- pub use moveit::EmplaceUnpinned;
}
/// Re-export moveit for ease of consumers.
diff --git a/third_party/autocxx/src/reference_wrapper.rs b/third_party/autocxx/src/reference_wrapper.rs
index ed943d3..041bd72 100644
--- a/third_party/autocxx/src/reference_wrapper.rs
+++ b/third_party/autocxx/src/reference_wrapper.rs
@@ -6,15 +6,124 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use core::{marker::PhantomData, ops::Deref, pin::Pin};
+
+#[cfg(nightly)]
+use std::{marker::Unsize, ops::DispatchFromDyn};
+
+use cxx::{memory::UniquePtrTarget, UniquePtr};
+
/// A C++ const reference. These are different from Rust's `&T` in that
-/// these may exist even while the object is mutated elsewhere.
+/// these may exist even while the object is mutated elsewhere. See also
+/// [`CppMutRef`] for the mutable equivalent.
///
-/// This is a trait not a struct due to the nuances of Rust's orphan rule
-/// - implemntations of this trait are found in each set of generated bindings
-/// but they are essentially the same.
-pub trait CppRef<'a, T> {
+/// The key rule is: we *never* dereference these in Rust. Therefore, any
+/// UB here cannot manifest within Rust, but only across in C++, and therefore
+/// they are equivalently safe to using C++ references in pure-C++ codebases.
+///
+/// *Important*: you might be wondering why you've never encountered this type.
+/// These exist in autocxx-generated bindings only if the `unsafe_references_wrapped`
+/// safety policy is given. This may become the default in future.
+///
+/// # Usage
+///
+/// These types of references are pretty useless in Rust. You can't do
+/// field access. But, you can pass them back into C++! And specifically,
+/// you can call methods on them (i.e. use this type as a `this`). So
+/// the common case here is when C++ gives you a reference to some type,
+/// then you want to call methods on that reference.
+///
+/// # Calling methods
+///
+/// As noted, one of the main reasons for this type is to call methods.
+/// Unfortunately, that depends on unstable Rust features. If you can't
+/// call methods on one of these references, check you're using nightly
+/// and add `#![feature(arbitrary_self_types)]` to your crate.
+///
+/// # Lifetimes and cloneability
+///
+/// Although these references implement C++ aliasing semantics, they
+/// do attempt to give you Rust lifetime tracking. This means if a C++ object
+/// gives you a reference, you won't be able to use that reference after the
+/// C++ object is no longer around.
+///
+/// This is usually what you need, since a C++ object will typically give
+/// you a reference to part of _itself_ or something that it owns. But,
+/// if you know that the returned reference lasts longer than its vendor,
+/// you can use `lifetime_cast` to get a long-lived version.
+///
+/// On the other hand, these references do not give you Rust's exclusivity
+/// guarantees. These references can be freely cloned, and using [`CppRef::const_cast`]
+/// you can even make a mutable reference from an immutable reference.
+///
+/// # Field access
+///
+/// Field access would be achieved by adding C++ `get` and/or `set` methods.
+/// It's possible that a future version of `autocxx` could generate such
+/// getters and setters automatically, but they would need to be `unsafe`
+/// because there is no guarantee that the referent of a `CppRef` is actually
+/// what it's supposed to be, or alive. `CppRef`s may flow from C++ to Rust
+/// via arbitrary means, and with sufficient uses of `get` and `set` it would
+/// even be possible to create a use-after-free in pure Rust code (for instance,
+/// store a [`CppPin`] in a struct field, get a `CppRef` to its referent, then
+/// use a setter to reset that field of the struct.)
+///
+/// # Deref
+///
+/// This type implements [`Deref`] because that's the mechanism that the
+/// unstable Rust `arbitrary_self_types` features uses to determine callable
+/// methods. However, actually calling `Deref::deref` is not permitted and will
+/// result in a compilation failure. If you wish to create a Rust reference
+/// from the C++ reference, see [`CppRef::as_ref`].
+///
+/// # Nullness
+///
+/// Creation of a null C++ reference is undefined behavior (because such
+/// a reference can only be created by dereferencing a null pointer.)
+/// However, in practice, they exist, and we need to be compatible with
+/// pre-existing C++ APIs even if they do naughty things like this.
+/// Therefore this `CppRef` type does allow null values. This is a bit
+/// unfortunate because it means `Option<CppRef<T>>`
+/// occupies more space than `CppRef<T>`.
+///
+/// # Dynamic dispatch
+///
+/// You might wonder if you can do this:
+/// ```ignore
+/// let CppRef<dyn Trait> = ...; // obtain some CppRef<concrete type>
+/// ```
+/// Dynamic dispatch works so long as you're using nightly (we require another
+/// unstable feature, `dispatch_from_dyn`). But we need somewhere to store
+/// the trait object, and `CppRef` isn't it -- a `CppRef` can only store a
+/// simple pointer to something else. So, you need to store the trait object
+/// in a `Box` or similar:
+/// ```ignore
+/// trait SomeTrait {
+/// fn some_method(self: CppRef<Self>)
+/// }
+/// impl SomeTrait for ffi::Concrete {
+/// fn some_method(self: CppRef<Self>) {}
+/// }
+/// let obj: Pin<Box<dyn SomeTrait>> = ffi::Concrete::new().within_box();
+/// let obj = CppPin::from_pinned_box(obj);
+/// farm_area.as_cpp_ref().some_method();
+/// ```
+///
+/// # Implementation notes
+///
+/// Internally, this is represented as a raw pointer in Rust. See the note above
+/// about Nullness for why we don't use [`core::ptr::NonNull`].
+#[repr(transparent)]
+pub struct CppRef<'a, T: ?Sized> {
+ ptr: *const T,
+ phantom: PhantomData<&'a T>,
+}
+
+impl<'a, T: ?Sized> CppRef<'a, T> {
/// Retrieve the underlying C++ pointer.
- fn as_ptr(&self) -> *const T;
+ pub fn as_ptr(&self) -> *const T {
+ self.ptr
+ }
/// Get a regular Rust reference out of this C++ reference.
///
@@ -24,21 +133,111 @@
/// C++ or Rust code while the returned reference exists. Callers must
/// also guarantee that no mutable Rust reference is created to the
/// referent while the returned reference exists.
- unsafe fn as_ref(&self) -> &T {
+ ///
+ /// Callers must also be sure that the C++ reference is properly
+ /// aligned, not null, pointing to valid data, etc.
+ pub unsafe fn as_ref(&self) -> &T {
&*self.as_ptr()
}
+
+ /// Create a C++ reference from a raw pointer.
+ pub fn from_ptr(ptr: *const T) -> Self {
+ Self {
+ ptr,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Create a mutable version of this reference, roughly equivalent
+ /// to C++ `const_cast`.
+ ///
+ /// The opposite is to use [`AsCppRef::as_cpp_ref`] on a [`CppMutRef`]
+ /// to obtain a [`CppRef`].
+ ///
+ /// # Safety
+ ///
+ /// Because we never dereference a `CppRef` in Rust, this cannot create
+ /// undefined behavior _within Rust_ and is therefore not unsafe. It is
+ /// however generally unwise, just as it is in C++. Use sparingly.
+ pub fn const_cast(&self) -> CppMutRef<'a, T> {
+ CppMutRef {
+ ptr: self.ptr as *mut T,
+ phantom: self.phantom,
+ }
+ }
+
+ /// Extend the lifetime of the returned reference beyond normal Rust
+ /// borrow checker rules.
+ ///
+ /// Normally, a reference can't be used beyond the lifetime of the object
+ /// which gave it to you, but sometimes C++ APIs can return references
+ /// to global or other longer-lived objects. In such a case you should
+ /// use this method to get a longer-lived reference.
+ ///
+ /// # Usage
+ ///
+ /// When you're given a C++ reference and you know its referent is valid
+ /// for a long time, use this method. Store the resulting `PhantomReferent`
+ /// somewhere in Rust with an equivalent lifetime.
+ /// That object can then vend longer-lived `CppRef`s using
+ /// [`AsCppRef::as_cpp_ref`].
+ ///
+ /// # Safety
+ ///
+ /// Because `CppRef`s are never dereferenced in Rust, misuse of this API
+ /// cannot lead to undefined behavior _in Rust_ and is therefore not
+ /// unsafe. Nevertheless this can lead to UB in C++, so use carefully.
+ pub fn lifetime_cast(&self) -> PhantomReferent<T> {
+ PhantomReferent(self.ptr)
+ }
}
+impl<'a, T: ?Sized> Deref for CppRef<'a, T> {
+ type Target = *const T;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ // With `inline_const` we can simplify this to:
+ // const { panic!("you shouldn't deref CppRef!") }
+ struct C<T: ?Sized>(T);
+ impl<T: ?Sized> C<T> {
+ const V: core::convert::Infallible = panic!(
+ "You cannot directly obtain a Rust reference from a CppRef. Use CppRef::as_ref."
+ );
+ }
+ match C::<T>::V {}
+ }
+}
+
+impl<'a, T: ?Sized> Clone for CppRef<'a, T> {
+ fn clone(&self) -> Self {
+ Self {
+ ptr: self.ptr,
+ phantom: self.phantom,
+ }
+ }
+}
+
+#[cfg(nightly)]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<CppRef<'_, U>> for CppRef<'_, T> {}
+
/// A C++ non-const reference. These are different from Rust's `&mut T` in that
/// several C++ references can exist to the same underlying data ("aliasing")
-/// and that's not permitted in Rust.
+/// and that's not permitted for regular Rust references.
///
-/// This is a trait not a struct due to the nuances of Rust's orphan rule
-/// - implemntations of this trait are found in each set of generated bindings
-/// but they are essentially the same.
-pub trait CppMutRef<'a, T>: CppRef<'a, T> {
+/// See [`CppRef`] for details on safety, usage models and implementation.
+///
+/// You can convert this to a [`CppRef`] using the [`std::convert::Into`] trait.
+#[repr(transparent)]
+pub struct CppMutRef<'a, T: ?Sized> {
+ ptr: *mut T,
+ phantom: PhantomData<&'a T>,
+}
+
+impl<'a, T: ?Sized> CppMutRef<'a, T> {
/// Retrieve the underlying C++ pointer.
- fn as_mut_ptr(&self) -> *mut T;
+ pub fn as_mut_ptr(&self) -> *mut T {
+ self.ptr
+ }
/// Get a regular Rust mutable reference out of this C++ reference.
///
@@ -48,16 +247,98 @@
/// C++ or Rust code while the returned reference exists. Callers must
/// also guarantee that no other Rust reference is created to the referent
/// while the returned reference exists.
- unsafe fn as_mut(&mut self) -> &mut T {
+ ///
+ /// Callers must also be sure that the C++ reference is properly
+ /// aligned, not null, pointing to valid data, etc.
+ pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_mut_ptr()
}
+
+ /// Create a C++ reference from a raw pointer.
+ pub fn from_ptr(ptr: *mut T) -> Self {
+ Self {
+ ptr,
+ phantom: PhantomData,
+ }
+ }
+
+ /// Extend the lifetime of the returned reference beyond normal Rust
+ /// borrow checker rules. See [`CppRef::lifetime_cast`].
+ pub fn lifetime_cast(&mut self) -> PhantomReferentMut<T> {
+ PhantomReferentMut(self.ptr)
+ }
}
-/// Any newtype wrapper which causes the contained object to obey C++ reference
-/// semantics rather than Rust reference semantics.
-///
-/// The complex generics here are working around the orphan rule - the only
-/// important generic is `T` which is the underlying stored type.
+impl<'a, T: ?Sized> Deref for CppMutRef<'a, T> {
+ type Target = *const T;
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ // With `inline_const` we can simplify this to:
+ // const { panic!("you shouldn't deref CppRef!") }
+ struct C<T: ?Sized>(T);
+ impl<T: ?Sized> C<T> {
+ const V: core::convert::Infallible = panic!("You cannot directly obtain a Rust reference from a CppMutRef. Use CppMutRef::as_mut.");
+ }
+ match C::<T>::V {}
+ }
+}
+
+impl<'a, T: ?Sized> Clone for CppMutRef<'a, T> {
+ fn clone(&self) -> Self {
+ Self {
+ ptr: self.ptr,
+ phantom: self.phantom,
+ }
+ }
+}
+
+impl<'a, T> From<CppMutRef<'a, T>> for CppRef<'a, T> {
+ fn from(mutable: CppMutRef<'a, T>) -> Self {
+ Self {
+ ptr: mutable.ptr,
+ phantom: mutable.phantom,
+ }
+ }
+}
+
+#[cfg(nightly)]
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<CppMutRef<'_, U>> for CppMutRef<'_, T> {}
+
+/// Any type which can return a C++ reference to its contents.
+pub trait AsCppRef<T: ?Sized> {
+ /// Returns a reference which obeys C++ reference semantics
+ fn as_cpp_ref(&self) -> CppRef<T>;
+}
+
+/// Any type which can return a C++ reference to its contents.
+pub trait AsCppMutRef<T: ?Sized>: AsCppRef<T> {
+ /// Returns a mutable reference which obeys C++ reference semantics
+ fn as_cpp_mut_ref(&mut self) -> CppMutRef<T>;
+}
+
+impl<'a, T: ?Sized> AsCppRef<T> for CppMutRef<'a, T> {
+ fn as_cpp_ref(&self) -> CppRef<T> {
+ CppRef::from_ptr(self.ptr)
+ }
+}
+
+/// Workaround for the inability to use std::ptr::addr_of! on the contents
+/// of a box.
+#[repr(transparent)]
+struct CppPinContents<T: ?Sized>(T);
+
+impl<T: ?Sized> CppPinContents<T> {
+ fn addr_of(&self) -> *const T {
+ std::ptr::addr_of!(self.0)
+ }
+ fn addr_of_mut(&mut self) -> *mut T {
+ std::ptr::addr_of_mut!(self.0)
+ }
+}
+
+/// A newtype wrapper which causes the contained object to obey C++ reference
+/// semantics rather than Rust reference semantics. That is, multiple aliasing
+/// mutable C++ references may exist to the contents.
///
/// C++ references are permitted to alias one another, and commonly do.
/// Rust references must alias according only to the narrow rules of the
@@ -65,27 +346,98 @@
///
/// If you need C++ to access your Rust object, first imprison it in one of these
/// objects, then use [`Self::as_cpp_ref`] to obtain C++ references to it.
-pub trait CppPin<'a, T: 'a> {
- /// The type of C++ reference created to the contained object.
- type CppRef: CppRef<'a, T>;
+/// If you need the object back for use in the Rust domain, use [`CppPin::extract`],
+/// but be aware of the safety invariants that you - as a human - will need
+/// to guarantee.
+///
+/// # Usage models
+///
+/// From fairly safe to fairly unsafe:
+///
+/// * *Configure a thing in Rust then give it to C++*. Take your Rust object,
+/// set it up freely using Rust references, methods and data, then imprison
+/// it in a `CppPin` and keep it around while you work with it in C++.
+/// There is no possibility of _aliasing_ UB in this usage model, but you
+/// still need to be careful of use-after-free bugs, just as if you were
+/// to create a reference to any data in C++. The Rust borrow checker will
+/// help you a little by ensuring that your `CppRef` objects don't outlive
+/// the `CppPin`, but once those references pass into C++, it can't help.
+/// * *Pass a thing to C++, have it operate on it synchronously, then take
+/// it back*. To do this, you'd imprison your Rust object in a `CppPin`,
+/// then pass mutable C++ references (using [`AsCppMutRef::as_cpp_mut_ref`])
+/// into a C++ function. C++ would duly operate on the object, and thereafter
+/// you could reclaim the object with `extract()`. At this point, you (as
+/// a human) will need to give a guarantee that no references remain in the
+/// C++ domain. If your object was just locally used by a single C++ function,
+/// which has now returned, this type of local analysis may well be practical.
+/// * *Share a thing between Rust and C++*. This object can vend both C++
+/// references and Rust references (via `as_ref` etc.) It may be possible
+/// for you to guarantee that C++ does not mutate the object while any Rust
+/// reference exists. If you choose this model, you'll need to carefully
+/// track exactly what happens to references and pointers on both sides,
+/// and document your evidence for why you are sure this is safe.
+/// Failure here is bad: Rust makes all sorts of optimization decisions based
+/// upon its borrow checker guarantees, so mistakes can lead to undebuggable
+/// action-at-a-distance crashes.
+///
+/// # See also
+///
+/// See also [`CppUniquePtrPin`], which is equivalent for data which is in
+/// a [`cxx::UniquePtr`].
+pub struct CppPin<T: ?Sized>(Box<CppPinContents<T>>);
- /// The type of C++ mutable reference created to the contained object..
- type CppMutRef: CppMutRef<'a, T>;
+impl<T: ?Sized> CppPin<T> {
+ /// Imprison the Rust data within a `CppPin`. This eliminates any remaining
+ /// Rust references (since we take the item by value) and this object
+ /// subsequently only vends C++ style references, not Rust references,
+ /// until or unless `extract` is called.
+ pub fn new(item: T) -> Self
+ where
+ T: Sized,
+ {
+ Self(Box::new(CppPinContents(item)))
+ }
+
+ /// Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining
+ /// Rust references (since we take the item by value) and this object
+ /// subsequently only vends C++ style references, not Rust references,
+ /// until or unless `extract` is called.
+ ///
+ /// If the item is already in a `Box`, this is slightly more efficient than
+ /// `new` because it will avoid moving/reallocating it.
+ pub fn from_box(item: Box<T>) -> Self {
+ // Safety: CppPinContents<T> is #[repr(transparent)] so
+ // this transmute from
+ // Box<T>
+ // to
+ // Box<CppPinContents<T>>
+ // is safe.
+ let contents = unsafe { std::mem::transmute(item) };
+ Self(contents)
+ }
+
+ // Imprison the boxed Rust data within a `CppPin`. This eliminates any remaining
+ /// Rust references (since we take the item by value) and this object
+ /// subsequently only vends C++ style references, not Rust references,
+ /// until or unless `extract` is called.
+ ///
+ /// If the item is already in a `Box`, this is slightly more efficient than
+ /// `new` because it will avoid moving/reallocating it.
+ pub fn from_pinned_box(item: Pin<Box<T>>) -> Self {
+ // Safety: it's OK to un-pin the Box because we'll be putting it
+ // into a CppPin which upholds the same pinned-ness contract.
+ Self::from_box(unsafe { Pin::into_inner_unchecked(item) })
+ }
/// Get an immutable pointer to the underlying object.
- fn as_ptr(&self) -> *const T;
+ pub fn as_ptr(&self) -> *const T {
+ self.0.addr_of()
+ }
/// Get a mutable pointer to the underlying object.
- fn as_mut_ptr(&mut self) -> *mut T;
-
- /// Returns a reference which obeys C++ reference semantics
- fn as_cpp_ref(&self) -> Self::CppRef;
-
- /// Returns a mutable reference which obeys C++ reference semantics.
- ///
- /// Note that this requires unique ownership of `self`, but this is
- /// advisory since the resulting reference can be cloned.
- fn as_cpp_mut_ref(&mut self) -> Self::CppMutRef;
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ self.0.addr_of_mut()
+ }
/// Get a normal Rust reference to the underlying object. This is unsafe.
///
@@ -93,7 +445,7 @@
///
/// You must guarantee that C++ will not mutate the object while the
/// reference exists.
- unsafe fn as_ref(&self) -> &T {
+ pub unsafe fn as_ref(&self) -> &T {
&*self.as_ptr()
}
@@ -103,7 +455,183 @@
///
/// You must guarantee that C++ will not mutate the object while the
/// reference exists.
- unsafe fn as_mut(&mut self) -> &mut T {
+ pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_mut_ptr()
}
+
+ /// Extract the object from within its prison, for re-use again within
+ /// the domain of normal Rust references.
+ ///
+ /// This returns a `Box<T>`: if you want the underlying `T` you can extract
+ /// it using `*`.
+ ///
+ /// # Safety
+ ///
+ /// Callers promise that no remaining C++ references exist either
+ /// in the form of Rust [`CppRef`]/[`CppMutRef`] or any remaining pointers/
+ /// references within C++.
+ pub unsafe fn extract(self) -> Box<T> {
+ // Safety: CppPinContents<T> is #[repr(transparent)] so
+ // this transmute from
+ // Box<CppPinContents<T>>
+ // to
+ // Box<T>
+ // is safe.
+ std::mem::transmute(self.0)
+ }
+}
+
+impl<T: ?Sized> AsCppRef<T> for CppPin<T> {
+ fn as_cpp_ref(&self) -> CppRef<T> {
+ CppRef::from_ptr(self.as_ptr())
+ }
+}
+
+impl<T: ?Sized> AsCppMutRef<T> for CppPin<T> {
+ fn as_cpp_mut_ref(&mut self) -> CppMutRef<T> {
+ CppMutRef::from_ptr(self.as_mut_ptr())
+ }
+}
+
+/// Any newtype wrapper which causes the contained [`UniquePtr`] target to obey C++ reference
+/// semantics rather than Rust reference semantics. That is, multiple aliasing
+/// mutable C++ references may exist to the contents.
+///
+/// C++ references are permitted to alias one another, and commonly do.
+/// Rust references must alias according only to the narrow rules of the
+/// borrow checker.
+pub struct CppUniquePtrPin<T: UniquePtrTarget>(UniquePtr<T>);
+
+impl<T: UniquePtrTarget> CppUniquePtrPin<T> {
+ /// Imprison the type within a `CppPin`. This eliminates any remaining
+ /// Rust references (since we take the item by value) and this object
+ /// subsequently only vends C++ style references, not Rust references.
+ pub fn new(item: UniquePtr<T>) -> Self {
+ Self(item)
+ }
+
+ /// Get an immutable pointer to the underlying object.
+ pub fn as_ptr(&self) -> *const T {
+ // TODO - avoid brief reference here
+ self.0
+ .as_ref()
+ .expect("UniquePtr was null; we can't make a C++ reference")
+ }
+}
+
+impl<T: UniquePtrTarget> AsCppRef<T> for CppUniquePtrPin<T> {
+ fn as_cpp_ref(&self) -> CppRef<T> {
+ CppRef::from_ptr(self.as_ptr())
+ }
+}
+
+impl<T: UniquePtrTarget> AsCppMutRef<T> for CppUniquePtrPin<T> {
+ fn as_cpp_mut_ref(&mut self) -> CppMutRef<T> {
+ let pinnned_ref: Pin<&mut T> = self
+ .0
+ .as_mut()
+ .expect("UniquePtr was null; we can't make a C++ reference");
+ let ptr = unsafe { Pin::into_inner_unchecked(pinnned_ref) };
+ CppMutRef::from_ptr(ptr)
+ }
+}
+
+/// A structure used to extend the lifetime of a returned C++ reference,
+/// to indicate to Rust that it's beyond the normal Rust lifetime rules.
+/// See [`CppRef::lifetime_cast`].
+#[repr(transparent)]
+pub struct PhantomReferent<T: ?Sized>(*const T);
+
+impl<T: ?Sized> AsCppRef<T> for PhantomReferent<T> {
+ fn as_cpp_ref(&self) -> CppRef<T> {
+ CppRef::from_ptr(self.0)
+ }
+}
+
+/// A structure used to extend the lifetime of a returned C++ mutable reference,
+/// to indicate to Rust that it's beyond the normal Rust lifetime rules.
+/// See [`CppRef::lifetime_cast`].
+#[repr(transparent)]
+pub struct PhantomReferentMut<T: ?Sized>(*mut T);
+
+impl<T: ?Sized> AsCppRef<T> for PhantomReferentMut<T> {
+ fn as_cpp_ref(&self) -> CppRef<T> {
+ CppRef::from_ptr(self.0)
+ }
+}
+
+impl<T: ?Sized> AsCppMutRef<T> for PhantomReferentMut<T> {
+ fn as_cpp_mut_ref(&mut self) -> CppMutRef<T> {
+ CppMutRef::from_ptr(self.0)
+ }
+}
+
+#[cfg(all(feature = "arbitrary_self_types", test))]
+mod tests {
+ use super::*;
+
+ struct CppOuter {
+ _a: u32,
+ inner: CppInner,
+ global: *const CppInner,
+ }
+
+ impl CppOuter {
+ fn get_inner_ref<'a>(self: &CppRef<'a, CppOuter>) -> CppRef<'a, CppInner> {
+ // Safety: emulating C++ code for test purposes. This is safe
+ // because we know the data isn't modified during the lifetime of
+ // the returned reference.
+ let self_rust_ref = unsafe { self.as_ref() };
+ CppRef::from_ptr(std::ptr::addr_of!(self_rust_ref.inner))
+ }
+ fn get_global_ref<'a>(self: &CppRef<'a, CppOuter>) -> CppRef<'a, CppInner> {
+ // Safety: emulating C++ code for test purposes. This is safe
+ // because we know the data isn't modified during the lifetime of
+ // the returned reference.
+ let self_rust_ref = unsafe { self.as_ref() };
+ CppRef::from_ptr(self_rust_ref.global)
+ }
+ }
+
+ struct CppInner {
+ b: u32,
+ }
+
+ impl CppInner {
+ fn value_is(self: &CppRef<Self>) -> u32 {
+ // Safety: emulating C++ code for test purposes. This is safe
+ // because we know the data isn't modified during the lifetime of
+ // the returned reference.
+ let self_rust_ref = unsafe { self.as_ref() };
+ self_rust_ref.b
+ }
+ }
+
+ #[test]
+ fn cpp_objects() {
+ let mut global = CppInner { b: 7 };
+ let global_ref_lifetime_phantom;
+ {
+ let outer = CppOuter {
+ _a: 12,
+ inner: CppInner { b: 3 },
+ global: &mut global,
+ };
+ let outer = CppPin::new(outer);
+ let inner_ref = outer.as_cpp_ref().get_inner_ref();
+ assert_eq!(inner_ref.value_is(), 3);
+ global_ref_lifetime_phantom = Some(outer.as_cpp_ref().get_global_ref().lifetime_cast());
+ }
+ let global_ref = global_ref_lifetime_phantom.unwrap();
+ let global_ref = global_ref.as_cpp_ref();
+ assert_eq!(global_ref.value_is(), 7);
+ }
+
+ #[test]
+ fn cpp_pin() {
+ let a = RustThing { _a: 4 };
+ let a = CppPin::new(a);
+ let _ = a.as_cpp_ref();
+ let _ = a.as_cpp_ref();
+ }
}
diff --git a/third_party/autocxx/src/rvalue_param.rs b/third_party/autocxx/src/rvalue_param.rs
index 4acc52e..e380c8a 100644
--- a/third_party/autocxx/src/rvalue_param.rs
+++ b/third_party/autocxx/src/rvalue_param.rs
@@ -78,6 +78,13 @@
/// need to pass a value parameter into C++, and will take responsibility
/// for extracting that value parameter from the [`RValueParam`] and doing
/// any later cleanup.
+///
+/// Because C++ move constructors may modify the original object, we consume
+/// the object and store it, pinned, until the call completes. This avoids any
+/// risk that C++ will mutate objects elsewhere in Rust-land, which could cause
+/// problems in the case of re-entrancy as references might exist to those
+/// other objects and Rust assumes there are no unexpected mutations of objects
+/// where references exist.
#[doc(hidden)]
pub struct RValueParamHandler<T, RVP>
where
diff --git a/third_party/autocxx/src/subclass.rs b/third_party/autocxx/src/subclass.rs
index 6c6ee31..bf905d9 100644
--- a/third_party/autocxx/src/subclass.rs
+++ b/third_party/autocxx/src/subclass.rs
@@ -31,7 +31,7 @@
/// #[subclass(superclass("MyCppSuperclass"))]
/// struct Bar {};
/// ```
-/// * as a directive within the [include_cpp] macro, in which case you
+/// * as a directive within the [crate::include_cpp] macro, in which case you
/// must provide two arguments of the superclass and then the
/// subclass:
/// ```
@@ -102,18 +102,14 @@
/// A type showing how the Rust side of a Rust/C++ subclass pair refers to
/// the C++ side.
#[doc(hidden)]
+#[derive(Default)]
pub enum CppSubclassCppPeerHolder<CppPeer: CppSubclassCppPeer> {
+ #[default]
Empty,
Owned(Box<UniquePtr<CppPeer>>),
Unowned(*mut CppPeer),
}
-impl<CppPeer: CppSubclassCppPeer> Default for CppSubclassCppPeerHolder<CppPeer> {
- fn default() -> Self {
- CppSubclassCppPeerHolder::Empty
- }
-}
-
impl<CppPeer: CppSubclassCppPeer> CppSubclassCppPeerHolder<CppPeer> {
fn pin_mut(&mut self) -> Pin<&mut CppPeer> {
match self {
diff --git a/third_party/autocxx/src/value_param.rs b/third_party/autocxx/src/value_param.rs
index 8e564a1..7386d19 100644
--- a/third_party/autocxx/src/value_param.rs
+++ b/third_party/autocxx/src/value_param.rs
@@ -7,7 +7,7 @@
// except according to those terms.
use cxx::{memory::UniquePtrTarget, UniquePtr};
-use moveit::{CopyNew, DerefMove, MoveNew, New};
+use moveit::{AsMove, CopyNew, MoveNew, New};
use std::{marker::PhantomPinned, mem::MaybeUninit, ops::Deref, pin::Pin};
/// A trait representing a parameter to a C++ function which is received
@@ -192,22 +192,21 @@
/// Explicitly force a value parameter to be taken using any type of [`crate::moveit::new::New`],
/// i.e. a constructor.
-pub fn as_new<N: New<Output = T>, T>(constructor: N) -> impl ValueParam<T> {
+pub fn as_new<N: New>(constructor: N) -> impl ValueParam<N::Output> {
ByNew(constructor)
}
/// Explicitly force a value parameter to be taken by copy.
-pub fn as_copy<P: Deref<Target = T>, T>(ptr: P) -> impl ValueParam<T>
+pub fn as_copy<P: Deref>(ptr: P) -> impl ValueParam<P::Target>
where
- T: CopyNew,
+ P::Target: CopyNew,
{
ByNew(crate::moveit::new::copy(ptr))
}
-/// Explicitly force a value parameter to be taken usign C++ move semantics.
-pub fn as_mov<P: DerefMove + Deref<Target = T>, T>(ptr: P) -> impl ValueParam<T>
+/// Explicitly force a value parameter to be taken using C++ move semantics.
+pub fn as_mov<P: AsMove>(ptr: P) -> impl ValueParam<P::Target>
where
- P: DerefMove,
P::Target: MoveNew,
{
ByNew(crate::moveit::new::mov(ptr))
@@ -216,11 +215,8 @@
#[doc(hidden)]
pub struct ByNew<N: New>(N);
-unsafe impl<N, T> ValueParam<T> for ByNew<N>
-where
- N: New<Output = T>,
-{
- type StackStorage = MaybeUninit<T>;
+unsafe impl<N: New> ValueParam<N::Output> for ByNew<N> {
+ type StackStorage = MaybeUninit<N::Output>;
unsafe fn populate_stack_space(self, mut stack: Pin<&mut Option<Self::StackStorage>>) {
// Safety: we won't move/swap things within the pin.
@@ -228,11 +224,11 @@
*slot = Some(MaybeUninit::uninit());
self.0.new(Pin::new_unchecked(slot.as_mut().unwrap()))
}
- fn get_ptr(stack: Pin<&mut Self::StackStorage>) -> *mut T {
- // Safety: it's OK to (briefly) create a reference to the T because we
+ fn get_ptr(stack: Pin<&mut Self::StackStorage>) -> *mut N::Output {
+ // Safety: it's OK to (briefly) create a reference to the N::Output because we
// populated it within `populate_stack_space`. It's OK to unpack the pin
// because we're not going to move the contents.
- unsafe { Pin::into_inner_unchecked(stack).assume_init_mut() as *mut T }
+ unsafe { Pin::into_inner_unchecked(stack).assume_init_mut() as *mut N::Output }
}
fn do_drop(stack: Pin<&mut Self::StackStorage>) {
diff --git a/third_party/autocxx/tools/mdbook-preprocessor/Cargo.toml b/third_party/autocxx/tools/mdbook-preprocessor/Cargo.toml
index f88e833..b6fb48c 100644
--- a/third_party/autocxx/tools/mdbook-preprocessor/Cargo.toml
+++ b/third_party/autocxx/tools/mdbook-preprocessor/Cargo.toml
@@ -8,28 +8,28 @@
[package]
name = "autocxx-mdbook-preprocessor"
-version = "0.22.3"
+version = "0.26.0"
authors = ["adetaylor <adetaylor@chromium.org>"]
edition = "2021"
[dependencies]
-clap = { version = "3", features = [ "cargo" ] }
+clap = { version = "3", features = ["cargo"] }
serde_json = "1"
itertools = "0.10"
anyhow = "1"
regex = "1"
-autocxx-integration-tests = { path = "../../integration-tests", version="=0.22.3"}
+autocxx-integration-tests = { path = "../../integration-tests", version = "=0.26.0" }
rayon = "1.5"
gag = "1.0"
env_logger = "0.9.0"
[dependencies.syn]
version = "1.0.39"
-features = [ "parsing" ]
+features = ["parsing"]
[dependencies.proc-macro2]
version = "1.0.11"
-features = [ "span-locations" ]
+features = ["span-locations"]
[dependencies.mdbook]
version = "0.4"
diff --git a/third_party/autocxx/tools/mdbook-preprocessor/src/main.rs b/third_party/autocxx/tools/mdbook-preprocessor/src/main.rs
index 1bb4e31..7123ec1 100644
--- a/third_party/autocxx/tools/mdbook-preprocessor/src/main.rs
+++ b/third_party/autocxx/tools/mdbook-preprocessor/src/main.rs
@@ -9,6 +9,7 @@
use std::{
borrow::Cow,
collections::HashSet,
+ ffi::OsString,
fmt::Display,
io::{self, Read},
path::PathBuf,
@@ -135,11 +136,11 @@
&case.cpp,
&case.hdr,
case.rs,
- args.value_of_os("manifest_dir").unwrap(),
+ &OsString::from(args.value_of("manifest_dir").unwrap()),
);
let desc = match err {
Ok(_) => "passed".to_string(),
- Err(ref err) => format!("failed: {:?}", err),
+ Err(ref err) => format!("failed: {err:?}"),
};
eprintln!(
"Doctest {}/{} at {} {}.",
@@ -164,7 +165,7 @@
.read_to_string(&mut stdout_str)
.unwrap();
if !stdout_str.is_empty() {
- eprintln!("Stdout from tests:\n{}", stdout_str);
+ eprintln!("Stdout from tests:\n{stdout_str}");
}
if !fails.is_empty() {
panic!(
@@ -304,7 +305,7 @@
) -> impl Iterator<Item = String> {
let input_str = lines.join("\n");
let fn_call = syn::parse_str::<syn::Expr>(&input_str)
- .unwrap_or_else(|_| panic!("Unable to parse outer function at {}", location));
+ .unwrap_or_else(|_| panic!("Unable to parse outer function at {location}"));
let fn_call = match fn_call {
Expr::Call(expr) => expr,
_ => panic!("Parsing unexpected"),
@@ -338,7 +339,7 @@
cpp,
hdr,
rs: syn::parse_file(&rs)
- .unwrap_or_else(|_| panic!("Unable to parse code at {}", location))
+ .unwrap_or_else(|_| panic!("Unable to parse code at {location}"))
.to_token_stream(),
location,
});
diff --git a/third_party/autocxx/tools/publish-all.sh b/third_party/autocxx/tools/publish-all.sh
index b43b95b..7252b5e 100755
--- a/third_party/autocxx/tools/publish-all.sh
+++ b/third_party/autocxx/tools/publish-all.sh
@@ -11,6 +11,4 @@
echo "Publish: $CRATE"
cargo publish
popd
- sleep 30 # sometimes crates.io takes a moment, and our
- # crates are interdependent.
done
diff --git a/third_party/autocxx/tools/reduce/Cargo.toml b/third_party/autocxx/tools/reduce/Cargo.toml
index 83e3916..c60d2d0 100644
--- a/third_party/autocxx/tools/reduce/Cargo.toml
+++ b/third_party/autocxx/tools/reduce/Cargo.toml
@@ -8,30 +8,32 @@
[package]
name = "autocxx-reduce"
-version = "0.22.3"
+version = "0.26.0"
authors = ["adetaylor <adetaylor@chromium.org>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-autocxx-engine = { version = "=0.22.3", path="../../engine" }
-autocxx-parser = { version = "=0.22.3", path="../../parser", features = [ "reproduction_case" ] }
+autocxx-engine = { version = "=0.26.0", path = "../../engine" }
+autocxx-parser = { version = "=0.26.0", path = "../../parser", features = [
+ "reproduction_case",
+] }
clap = { version = "3.1.2", features = ["cargo"] }
-tempfile = "3.1"
+tempfile = "3.4"
indoc = "1.0"
itertools = "0.10"
serde_json = "1.0"
serde = "1.0"
serde_derive = "1.0"
-syn = "1.0.39"
+syn = "2.0.1"
quote = "1.0"
-cxx-gen = "0.7.68"
+cxx-gen = "0.7.78"
regex = "1.5"
indexmap = "1.8"
[dev-dependencies]
-assert_cmd = "1.0.3"
+assert_cmd = "2"
tempfile = "3.1"
indoc = "1.0"
-proc-macro2 = "1.0"
\ No newline at end of file
+proc-macro2 = "1.0"
diff --git a/third_party/autocxx/tools/reduce/src/main.rs b/third_party/autocxx/tools/reduce/src/main.rs
index 06110cd..d585dee 100644
--- a/third_party/autocxx/tools/reduce/src/main.rs
+++ b/third_party/autocxx/tools/reduce/src/main.rs
@@ -36,6 +36,13 @@
"};
fn main() {
+ // Assemble some defaults for command line arguments
+ let current_exe = std::env::current_exe().unwrap();
+ let our_dir = current_exe.parent().unwrap();
+ let default_gen_cmd = our_dir.join("autocxx-gen").to_str().unwrap().to_string();
+ let rust_libs_path1 = our_dir.to_str().unwrap().to_string();
+ let rust_libs_path2 = our_dir.join("deps").to_str().unwrap().to_string();
+ let default_rlibs = &[rust_libs_path1.as_str(), rust_libs_path2.as_str()];
let matches = Command::new("autocxx-reduce")
.version(crate_version!())
.author(crate_authors!())
@@ -138,6 +145,24 @@
.long("gen-cmd")
.value_name("GEN-CMD")
.help("where to find autocxx-gen")
+ .default_value(&default_gen_cmd)
+ .takes_value(true),
+ )
+ .arg(
+ Arg::new("rustc")
+ .long("rustc")
+ .value_name("RUSTC")
+ .help("where to find rustc")
+ .default_value("rustc")
+ .takes_value(true),
+ )
+ .arg(
+ Arg::new("rlibs")
+ .long("rlibs")
+ .value_name("LIBDIR")
+ .help("where to find rlibs/rmetas for cxx and autocxx")
+ .default_values(default_rlibs)
+ .multiple_values(true)
.takes_value(true),
)
.arg(
@@ -172,6 +197,11 @@
.help("Do not post-compile the C++ generated by autocxxgen"),
)
.arg(
+ Arg::new("no-rustc")
+ .long("no-rustc")
+ .help("Do not compile the rust generated by autocxxgen"),
+ )
+ .arg(
Arg::new("suppress-cxx-inclusions")
.long("suppress-cxx-inclusions")
.takes_value(true)
@@ -222,8 +252,7 @@
let listing_path = tmp_dir.path().join("listing.h");
create_concatenated_header(&headers, &listing_path)?;
announce_progress(&format!(
- "Preprocessing {:?} to {:?}",
- listing_path, concat_path
+ "Preprocessing {listing_path:?} to {concat_path:?}"
));
preprocess(&listing_path, &concat_path, &incs, &defs)?;
let directives: Vec<_> = std::iter::once("#include \"concat.h\"\n".to_string())
@@ -231,7 +260,7 @@
submatches
.values_of("directive")
.unwrap_or_default()
- .map(|s| format!("{}\n", s)),
+ .map(|s| format!("{s}\n")),
)
.collect();
create_rs_file(&rs_path, &directives)?;
@@ -277,33 +306,25 @@
.collect();
let extra_clang_args: Vec<&str> = extra_clang_args.iter().map(|s| s.as_ref()).collect_vec();
- let default_gen_cmd = std::env::current_exe()?
- .parent()
- .unwrap()
- .join("autocxx-gen")
- .to_str()
- .unwrap()
- .to_string();
- let gen_cmd = matches.value_of("gen-cmd").unwrap_or(&default_gen_cmd);
+ let gen_cmd = matches.value_of("gen-cmd").unwrap();
if !Path::new(gen_cmd).exists() {
panic!(
- "autocxx-gen not found in {}. hint: autocxx-reduce --gen-cmd /path/to/autocxx-gen",
- gen_cmd
+ "autocxx-gen not found in {gen_cmd}. hint: autocxx-reduce --gen-cmd /path/to/autocxx-gen"
);
}
+
run_sample_gen_cmd(gen_cmd, &rs_path, tmp_dir.path(), &extra_clang_args)?;
// Create and run an interestingness test which does not filter its output through grep.
let demo_interestingness_test_dir = tmp_dir.path().join("demo-interestingness-test");
std::fs::create_dir(&demo_interestingness_test_dir).unwrap();
let interestingness_test = demo_interestingness_test_dir.join("test-demo.sh");
create_interestingness_test(
+ &matches,
gen_cmd,
&interestingness_test,
None,
&rs_path,
&extra_clang_args,
- !matches.is_present("no-precompile"),
- !matches.is_present("no-postcompile"),
)?;
let demo_dir_concat_path = demo_interestingness_test_dir.join("concat.h");
std::fs::copy(&concat_path, demo_dir_concat_path).unwrap();
@@ -312,13 +333,12 @@
// Now the main interestingness test
let interestingness_test = tmp_dir.path().join("test.sh");
create_interestingness_test(
+ &matches,
gen_cmd,
&interestingness_test,
Some(matches.value_of("problem").unwrap()),
&rs_path,
&extra_clang_args,
- !matches.is_present("no-precompile"),
- !matches.is_present("no-postcompile"),
)?;
run_creduce(
matches.value_of("creduce").unwrap(),
@@ -331,7 +351,7 @@
match output_path {
None => print_minimized_case(&concat_path)?,
Some(output_path) => {
- std::fs::copy(&concat_path, &PathBuf::from(output_path))?;
+ std::fs::copy(&concat_path, PathBuf::from(output_path))?;
}
};
Ok(())
@@ -349,13 +369,13 @@
}
fn announce_progress(msg: &str) {
- println!("=== {} ===", msg);
+ println!("=== {msg} ===");
}
fn print_minimized_case(concat_path: &Path) -> Result<(), std::io::Error> {
announce_progress("Completed. Minimized test case:");
let contents = std::fs::read_to_string(concat_path)?;
- println!("{}", contents);
+ println!("{contents}");
Ok(())
}
@@ -370,7 +390,7 @@
.arg("--help")
.output();
let msg = match cmd {
- Err(error) => panic!("failed to run creduce. creduce_cmd = {}. hint: autocxx-reduce --creduce /path/to/creduce. error = {}", creduce_cmd, error),
+ Err(error) => panic!("failed to run creduce. creduce_cmd = {creduce_cmd}. hint: autocxx-reduce --creduce /path/to/creduce. error = {error}"),
Ok(result) => result.stdout
};
let msg = std::str::from_utf8(&msg).unwrap();
@@ -413,7 +433,7 @@
let args = format_gen_cmd(rs_file, tmp_dir.to_str().unwrap(), extra_clang_args);
let args = args.collect::<Vec<_>>();
let args_str = args.join(" ");
- announce_progress(&format!("Running sample gen cmd: {} {}", gen_cmd, args_str));
+ announce_progress(&format!("Running sample gen cmd: {gen_cmd} {args_str}"));
std::process::Command::new(gen_cmd).args(args).status()?;
Ok(())
}
@@ -451,15 +471,26 @@
}
fn create_interestingness_test(
+ matches: &ArgMatches,
gen_cmd: &str,
test_path: &Path,
problem: Option<&str>,
rs_file: &Path,
extra_clang_args: &[&str],
- precompile: bool,
- postcompile: bool,
) -> Result<(), std::io::Error> {
announce_progress("Creating interestingness test");
+ let precompile = !matches.is_present("no-precompile");
+ let postcompile = !matches.is_present("no-postcompile");
+ let rustc = !matches.is_present("no-rustc");
+
+ let rustc_path = matches.value_of("rustc").unwrap();
+
+ let rust_libs_path: Vec<String> = matches
+ .get_many::<String>("rlibs")
+ .expect("No rlib path specified")
+ .cloned()
+ .collect();
+
// Ensure we refer to the input header by relative path
// because creduce will invoke us in some other directory with
// a copy thereof.
@@ -469,37 +500,47 @@
// For the compile afterwards, we have to avoid including any system headers.
// We rely on equivalent content being hermetically inside concat.h.
let postcompile_step = make_compile_step(postcompile, "gen0.cc", extra_clang_args);
+ let rustc_step = if rustc {
+ let rust_libs_path = rust_libs_path.iter().map(|p| format!(" -L{p}")).join(" ");
+ format!("{rustc_path} --extern cxx --extern autocxx {rust_libs_path} --crate-type rlib --emit=metadata --edition=2021 autocxx-ffi-default-gen.rs 2>&1")
+ } else {
+ "echo Skipping rustc".to_string()
+ };
+ // -q below to exit immediately as soon as a match is found, to avoid
+ // extra compile/codegen steps
let problem_grep = problem
- .map(|problem| format!("| grep \"{}\" >/dev/null 2>&1", problem))
+ .map(|problem| format!("| grep -q \"{problem}\" >/dev/null 2>&1"))
.unwrap_or_default();
+ // We formerly had a 'trap' below but it seems to have caused problems
+ // (trap \"if [[ \\$? -eq 139 ]]; then echo Segfault; fi\" CHLD; {} {} 2>&1 && cat autocxx-ffi-default-gen.rs && cat autocxxgen*.h && {} && {} 2>&1 ) {}
let content = format!(
indoc! {"
- #!/bin/sh
+ #!/bin/bash
set -e
echo Precompile
{}
echo Move
mv concat.h concat-body.h
- echo Codegen
(echo \"#ifndef __CONCAT_H__\"; echo \"#define __CONCAT_H__\"; echo '#include \"concat-body.h\"'; echo \"#endif\") > concat.h
- (trap \"if [[ \\$? -eq 139 ]]; then echo Segfault; fi\" CHLD; {} {} 2>&1 && cat autocxx-ffi-default-gen.rs && cat autocxxgen*.h && {} 2>&1 ) {}
+ echo Codegen
+ ({} {} 2>&1 && cat autocxx-ffi-default-gen.rs && cat autocxxgen*.h && {} && {} 2>&1) {}
echo Remove
rm concat.h
echo Swap back
mv concat-body.h concat.h
echo Done
"},
- precompile_step, gen_cmd, args, postcompile_step, problem_grep
+ precompile_step, gen_cmd, args, rustc_step, postcompile_step, problem_grep
);
- println!("Interestingness test:\n{}", content);
+ println!("Interestingness test:\n{content}");
{
let mut file = File::create(test_path)?;
file.write_all(content.as_bytes())?;
}
- let mut perms = std::fs::metadata(&test_path)?.permissions();
+ let mut perms = std::fs::metadata(test_path)?.permissions();
perms.set_mode(0o700);
- std::fs::set_permissions(&test_path, perms)?;
+ std::fs::set_permissions(test_path, perms)?;
Ok(())
}
@@ -531,14 +572,14 @@
announce_progress("Creating preprocessed header");
let mut file = File::create(listing_path)?;
for header in headers {
- file.write_all(format!("#include \"{}\"\n", header).as_bytes())?;
+ file.write_all(format!("#include \"{header}\"\n").as_bytes())?;
}
Ok(())
}
fn create_file(path: &Path, content: &str) -> Result<(), std::io::Error> {
let mut file = File::create(path)?;
- write!(file, "{}", content)?;
+ write!(file, "{content}")?;
Ok(())
}
@@ -548,10 +589,7 @@
.find_iter(cxx_gen::HEADER)
.map(|m| m.as_str())
.collect(); // for uniqueness
- defines
- .into_iter()
- .map(|def| format!("-D{}", def))
- .collect()
+ defines.into_iter().map(|def| format!("-D{def}")).collect()
}
#[test]
diff --git a/third_party/autocxx/tools/reduce/tests/reduce_test.rs b/third_party/autocxx/tools/reduce/tests/reduce_test.rs
index b277585..15cd627 100644
--- a/third_party/autocxx/tools/reduce/tests/reduce_test.rs
+++ b/third_party/autocxx/tools/reduce/tests/reduce_test.rs
@@ -55,9 +55,8 @@
do_reduce(
|header, demo_code_dir| {
let config = format!(
- "#include \"{}\" generate_all!() block!(\"First\")
- safety!(unsafe_ffi)",
- header
+ "#include \"{header}\" generate_all!() block!(\"First\")
+ safety!(unsafe_ffi)"
);
let json = serde_json::json!({
"header": INPUT_H,
@@ -173,7 +172,7 @@
let demo_code_dir = tmp_dir.path().join("demo");
std::fs::create_dir(&demo_code_dir).unwrap();
let input_header = if include_cxx_h {
- Cow::Owned(format!("#include \"cxx.h\"\n{}", INPUT_H))
+ Cow::Owned(format!("#include \"cxx.h\"\n{INPUT_H}"))
} else {
Cow::Borrowed(INPUT_H)
};
@@ -205,7 +204,7 @@
cmd = cmd.arg("repro").arg("-r").arg(repro_case);
}
}
- eprintln!("Running {:?}", cmd);
+ eprintln!("Running {cmd:?}");
let o = cmd.output()?;
println!("Reduce output: {}", std::str::from_utf8(&o.stdout).unwrap());
println!("Reduce error: {}", std::str::from_utf8(&o.stderr).unwrap());
@@ -220,7 +219,7 @@
fn write_to_file(dir: &Path, filename: &str, content: &[u8]) {
let path = dir.join(filename);
- let mut f = File::create(&path).expect("Unable to create file");
+ let mut f = File::create(path).expect("Unable to create file");
f.write_all(content).expect("Unable to write file");
}
diff --git a/third_party/autocxx/tools/stress-test/Cargo.toml b/third_party/autocxx/tools/stress-test/Cargo.toml
index a651f60..7788fe3 100644
--- a/third_party/autocxx/tools/stress-test/Cargo.toml
+++ b/third_party/autocxx/tools/stress-test/Cargo.toml
@@ -8,14 +8,14 @@
[package]
name = "autocxx-stress-test"
-version = "0.22.3"
+version = "0.26.0"
authors = ["Adrian Taylor <adetaylor@chromium.org>"]
edition = "2021"
[dependencies]
-cxx = "1.0.68"
-autocxx = { path = "../..", version="0.22.3" }
+cxx = "1.0.78"
+autocxx = { path = "../..", version = "0.26.0" }
[build-dependencies]
-autocxx-build = { path = "../../gen/build", version="0.22.3" }
-miette = { version="4.3", features=["fancy"]}
+autocxx-build = { path = "../../gen/build", version = "0.26.0" }
+miette = { version = "5", features = ["fancy"] }
diff --git a/y2022/BUILD b/y2022/BUILD
index f8bf59f..f25925e 100644
--- a/y2022/BUILD
+++ b/y2022/BUILD
@@ -18,10 +18,10 @@
data = [
":aos_config",
":message_bridge_client.sh",
+ "@ctre_phoenix6_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix6_tools_athena//:shared_libraries",
"@ctre_phoenix_api_cpp_athena//:shared_libraries",
"@ctre_phoenix_cci_athena//:shared_libraries",
- "@ctre_phoenixpro_api_cpp_athena//:shared_libraries",
- "@ctre_phoenixpro_tools_athena//:shared_libraries",
],
dirs = [
"//y2022/actors:splines",
@@ -270,7 +270,7 @@
"//frc971/wpilib:wpilib_interface",
"//frc971/wpilib:wpilib_robot_base",
"//third_party:phoenix",
- "//third_party:phoenixpro",
+ "//third_party:phoenix6",
"//third_party:wpilib",
"//y2022/control_loops/superstructure:led_indicator_lib",
"//y2022/control_loops/superstructure:superstructure_can_position_fbs",
diff --git a/y2022_bot3/BUILD b/y2022_bot3/BUILD
index e7146ce..29debe7 100644
--- a/y2022_bot3/BUILD
+++ b/y2022_bot3/BUILD
@@ -8,8 +8,8 @@
],
data = [
":aos_config",
- "@ctre_phoenixpro_api_cpp_athena//:shared_libraries",
- "@ctre_phoenixpro_tools_athena//:shared_libraries",
+ "@ctre_phoenix6_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix6_tools_athena//:shared_libraries",
],
dirs = [
"//y2022_bot3/actors:splines",
diff --git a/y2023/BUILD b/y2023/BUILD
index ed8f347..e200f87 100644
--- a/y2023/BUILD
+++ b/y2023/BUILD
@@ -1,7 +1,6 @@
load("//frc971:downloader.bzl", "robot_downloader")
load("//aos:config.bzl", "aos_config")
load("//tools/build_rules:template.bzl", "jinja2_template")
-load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
load("//aos/util:config_validator_macro.bzl", "config_validator_test")
config_validator_test(
@@ -21,10 +20,10 @@
"//aos/starter:roborio_irq_config.json",
"//y2023/constants:constants.json",
"//y2023/control_loops/superstructure/arm:arm_trajectories_generated.bfbs",
+ "@ctre_phoenix6_api_cpp_athena//:shared_libraries",
+ "@ctre_phoenix6_tools_athena//:shared_libraries",
"@ctre_phoenix_api_cpp_athena//:shared_libraries",
"@ctre_phoenix_cci_athena//:shared_libraries",
- "@ctre_phoenixpro_api_cpp_athena//:shared_libraries",
- "@ctre_phoenixpro_tools_athena//:shared_libraries",
],
dirs = [
"//y2023/www:www_files",
@@ -203,7 +202,7 @@
name = "config_roborio",
src = "y2023_roborio.json",
flatbuffers = [
- ":can_configuration_fbs",
+ "//frc971:can_configuration_fbs",
"//aos/network:remote_message_fbs",
"//aos/network:message_bridge_client_fbs",
"//aos/network:message_bridge_server_fbs",
@@ -271,7 +270,6 @@
],
target_compatible_with = ["//tools/platforms/hardware:roborio"],
deps = [
- ":can_configuration_fbs",
":constants",
"//aos:init",
"//aos:math",
@@ -283,6 +281,7 @@
"//aos/util:log_interval",
"//aos/util:phased_loop",
"//aos/util:wrapping_counter",
+ "//frc971:can_configuration_fbs",
"//frc971/autonomous:auto_mode_fbs",
"//frc971/control_loops:control_loop",
"//frc971/control_loops:control_loops_fbs",
@@ -303,7 +302,7 @@
"//frc971/wpilib:wpilib_interface",
"//frc971/wpilib:wpilib_robot_base",
"//third_party:phoenix",
- "//third_party:phoenixpro",
+ "//third_party:phoenix6",
"//third_party:wpilib",
"//y2023/control_loops/superstructure:led_indicator_lib",
"//y2023/control_loops/superstructure:superstructure_output_fbs",
@@ -384,12 +383,3 @@
"@com_github_google_glog//:glog",
],
)
-
-flatbuffer_cc_library(
- name = "can_configuration_fbs",
- srcs = [
- ":can_configuration.fbs",
- ],
- gen_reflections = 1,
- visibility = ["//visibility:public"],
-)
diff --git a/y2023/wpilib_interface.cc b/y2023/wpilib_interface.cc
index d043e6f..abf11da 100644
--- a/y2023/wpilib_interface.cc
+++ b/y2023/wpilib_interface.cc
@@ -26,7 +26,7 @@
#include "ctre/phoenix/cci/Diagnostics_CCI.h"
#include "ctre/phoenix/motorcontrol/can/TalonFX.h"
#include "ctre/phoenix/motorcontrol/can/TalonSRX.h"
-#include "ctre/phoenixpro/TalonFX.hpp"
+#include "ctre/phoenix6/TalonFX.hpp"
#include "aos/commonmath.h"
#include "aos/containers/sized_array.h"
@@ -40,6 +40,7 @@
#include "aos/util/phased_loop.h"
#include "aos/util/wrapping_counter.h"
#include "frc971/autonomous/auto_mode_generated.h"
+#include "frc971/can_configuration_generated.h"
#include "frc971/control_loops/drivetrain/drivetrain_can_position_generated.h"
#include "frc971/control_loops/drivetrain/drivetrain_position_generated.h"
#include "frc971/input/robot_state_generated.h"
@@ -56,7 +57,6 @@
#include "frc971/wpilib/pdp_fetcher.h"
#include "frc971/wpilib/sensor_reader.h"
#include "frc971/wpilib/wpilib_robot_base.h"
-#include "y2023/can_configuration_generated.h"
#include "y2023/constants.h"
#include "y2023/control_loops/superstructure/led_indicator.h"
#include "y2023/control_loops/superstructure/superstructure_output_generated.h"
@@ -67,6 +67,7 @@
"devices on the CAN bus using Phoenix Tuner");
using ::aos::monotonic_clock;
+using ::frc971::CANConfiguration;
using ::y2023::constants::Values;
namespace superstructure = ::y2023::control_loops::superstructure;
namespace drivetrain = ::y2023::control_loops::drivetrain;
@@ -121,7 +122,7 @@
class Falcon {
public:
Falcon(int device_id, std::string canbus,
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> *signals)
+ std::vector<ctre::phoenix6::BaseStatusSignal *> *signals)
: talon_(device_id, canbus),
device_id_(device_id),
device_temp_(talon_.GetDeviceTemp()),
@@ -152,7 +153,7 @@
}
void PrintConfigs() {
- ctre::phoenixpro::configs::TalonFXConfiguration configuration;
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
ctre::phoenix::StatusCode status =
talon_.GetConfigurator().Refresh(configuration);
if (!status.IsOK()) {
@@ -162,10 +163,10 @@
AOS_LOG(INFO, "configuration: %s", configuration.ToString().c_str());
}
- void WriteConfigs(ctre::phoenixpro::signals::InvertedValue invert) {
+ void WriteConfigs(ctre::phoenix6::signals::InvertedValue invert) {
inverted_ = invert;
- ctre::phoenixpro::configs::CurrentLimitsConfigs current_limits;
+ ctre::phoenix6::configs::CurrentLimitsConfigs current_limits;
current_limits.StatorCurrentLimit =
constants::Values::kDrivetrainStatorCurrentLimit();
current_limits.StatorCurrentLimitEnable = true;
@@ -173,14 +174,14 @@
constants::Values::kDrivetrainSupplyCurrentLimit();
current_limits.SupplyCurrentLimitEnable = true;
- ctre::phoenixpro::configs::MotorOutputConfigs output_configs;
+ ctre::phoenix6::configs::MotorOutputConfigs output_configs;
output_configs.NeutralMode =
- ctre::phoenixpro::signals::NeutralModeValue::Brake;
+ ctre::phoenix6::signals::NeutralModeValue::Brake;
output_configs.DutyCycleNeutralDeadband = 0;
output_configs.Inverted = inverted_;
- ctre::phoenixpro::configs::TalonFXConfiguration configuration;
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
configuration.CurrentLimits = current_limits;
configuration.MotorOutput = output_configs;
@@ -195,7 +196,7 @@
}
void WriteRollerConfigs() {
- ctre::phoenixpro::configs::CurrentLimitsConfigs current_limits;
+ ctre::phoenix6::configs::CurrentLimitsConfigs current_limits;
current_limits.StatorCurrentLimit =
constants::Values::kRollerStatorCurrentLimit();
current_limits.StatorCurrentLimitEnable = true;
@@ -203,12 +204,12 @@
constants::Values::kRollerSupplyCurrentLimit();
current_limits.SupplyCurrentLimitEnable = true;
- ctre::phoenixpro::configs::MotorOutputConfigs output_configs;
+ ctre::phoenix6::configs::MotorOutputConfigs output_configs;
output_configs.NeutralMode =
- ctre::phoenixpro::signals::NeutralModeValue::Brake;
+ ctre::phoenix6::signals::NeutralModeValue::Brake;
output_configs.DutyCycleNeutralDeadband = 0;
- ctre::phoenixpro::configs::TalonFXConfiguration configuration;
+ ctre::phoenix6::configs::TalonFXConfiguration configuration;
configuration.CurrentLimits = current_limits;
configuration.MotorOutput = output_configs;
@@ -222,7 +223,7 @@
PrintConfigs();
}
- ctre::phoenixpro::hardware::TalonFX *talon() { return &talon_; }
+ ctre::phoenix6::hardware::TalonFX *talon() { return &talon_; }
flatbuffers::Offset<frc971::control_loops::CANFalcon> WritePosition(
flatbuffers::FlatBufferBuilder *fbb) {
@@ -235,8 +236,7 @@
builder.add_duty_cycle(duty_cycle());
double invert =
- (inverted_ ==
- ctre::phoenixpro::signals::InvertedValue::Clockwise_Positive
+ (inverted_ == ctre::phoenix6::signals::InvertedValue::Clockwise_Positive
? 1
: -1);
@@ -266,26 +266,24 @@
void RefreshNontimesyncedSignals() { device_temp_.Refresh(); };
private:
- ctre::phoenixpro::hardware::TalonFX talon_;
+ ctre::phoenix6::hardware::TalonFX talon_;
int device_id_;
- ctre::phoenixpro::signals::InvertedValue inverted_;
+ ctre::phoenix6::signals::InvertedValue inverted_;
- ctre::phoenixpro::StatusSignalValue<units::temperature::celsius_t>
- device_temp_;
- ctre::phoenixpro::StatusSignalValue<units::voltage::volt_t> supply_voltage_;
- ctre::phoenixpro::StatusSignalValue<units::current::ampere_t> supply_current_,
+ ctre::phoenix6::StatusSignal<units::temperature::celsius_t> device_temp_;
+ ctre::phoenix6::StatusSignal<units::voltage::volt_t> supply_voltage_;
+ ctre::phoenix6::StatusSignal<units::current::ampere_t> supply_current_,
torque_current_;
- ctre::phoenixpro::StatusSignalValue<units::angle::turn_t> position_;
- ctre::phoenixpro::StatusSignalValue<units::dimensionless::scalar_t>
- duty_cycle_;
+ ctre::phoenix6::StatusSignal<units::angle::turn_t> position_;
+ ctre::phoenix6::StatusSignal<units::dimensionless::scalar_t> duty_cycle_;
};
class CANSensorReader {
public:
CANSensorReader(
aos::EventLoop *event_loop,
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_registry)
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry)
: event_loop_(event_loop),
signals_(signals_registry.begin(), signals_registry.end()),
can_position_sender_(
@@ -328,7 +326,7 @@
private:
void Loop() {
ctre::phoenix::StatusCode status =
- ctre::phoenixpro::BaseStatusSignalValue::WaitForAll(2000_ms, signals_);
+ ctre::phoenix6::BaseStatusSignal::WaitForAll(2000_ms, signals_);
if (!status.IsOK()) {
AOS_LOG(ERROR, "Failed to read signals from falcons: %s: %s",
@@ -384,7 +382,7 @@
aos::EventLoop *event_loop_;
- const std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_;
+ const std::vector<ctre::phoenix6::BaseStatusSignal *> signals_;
aos::Sender<frc971::control_loops::drivetrain::CANPosition>
can_position_sender_;
@@ -761,7 +759,7 @@
void WriteConfigs() { roller_falcon_->WriteRollerConfigs(); }
void Write(const superstructure::Output &output) override {
- ctre::phoenixpro::controls::DutyCycleOut roller_control(
+ ctre::phoenix6::controls::DutyCycleOut roller_control(
SafeSpeed(-output.roller_voltage()));
roller_control.UpdateFreqHz = 0_Hz;
roller_control.EnableFOC = true;
@@ -777,7 +775,7 @@
void Stop() override {
AOS_LOG(WARNING, "Superstructure CAN output too old.\n");
- ctre::phoenixpro::controls::DutyCycleOut stop_command(0.0);
+ ctre::phoenix6::controls::DutyCycleOut stop_command(0.0);
stop_command.UpdateFreqHz = 0_Hz;
stop_command.EnableFOC = true;
@@ -818,11 +816,11 @@
left_under_ = std::move(left_under);
}
- void set_right_inverted(ctre::phoenixpro::signals::InvertedValue invert) {
+ void set_right_inverted(ctre::phoenix6::signals::InvertedValue invert) {
right_inverted_ = invert;
}
- void set_left_inverted(ctre::phoenixpro::signals::InvertedValue invert) {
+ void set_left_inverted(ctre::phoenix6::signals::InvertedValue invert) {
left_inverted_ = invert;
}
@@ -851,12 +849,12 @@
void Write(
const ::frc971::control_loops::drivetrain::Output &output) override {
- ctre::phoenixpro::controls::DutyCycleOut left_control(
+ ctre::phoenix6::controls::DutyCycleOut left_control(
SafeSpeed(output.left_voltage()));
left_control.UpdateFreqHz = 0_Hz;
left_control.EnableFOC = true;
- ctre::phoenixpro::controls::DutyCycleOut right_control(
+ ctre::phoenix6::controls::DutyCycleOut right_control(
SafeSpeed(output.right_voltage()));
right_control.UpdateFreqHz = 0_Hz;
right_control.EnableFOC = true;
@@ -886,7 +884,7 @@
void Stop() override {
AOS_LOG(WARNING, "drivetrain output too old\n");
- ctre::phoenixpro::controls::DutyCycleOut stop_command(0.0);
+ ctre::phoenix6::controls::DutyCycleOut stop_command(0.0);
stop_command.UpdateFreqHz = 0_Hz;
stop_command.EnableFOC = true;
@@ -901,7 +899,7 @@
return (::aos::Clip(voltage, -kMaxBringupPower, kMaxBringupPower) / 12.0);
}
- ctre::phoenixpro::signals::InvertedValue left_inverted_, right_inverted_;
+ ctre::phoenix6::signals::InvertedValue left_inverted_, right_inverted_;
std::shared_ptr<Falcon> right_front_, right_back_, right_under_, left_front_,
left_back_, left_under_;
};
@@ -934,7 +932,7 @@
std::shared_ptr<frc::DigitalOutput> superstructure_reading =
make_unique<frc::DigitalOutput>(25);
- std::vector<ctre::phoenixpro::BaseStatusSignalValue *> signals_registry;
+ std::vector<ctre::phoenix6::BaseStatusSignal *> signals_registry;
std::shared_ptr<Falcon> right_front =
std::make_shared<Falcon>(1, "Drivetrain Bus", &signals_registry);
std::shared_ptr<Falcon> right_back =
@@ -1013,9 +1011,9 @@
drivetrain_writer.set_falcons(right_front, right_back, right_under,
left_front, left_back, left_under);
drivetrain_writer.set_right_inverted(
- ctre::phoenixpro::signals::InvertedValue::Clockwise_Positive);
+ ctre::phoenix6::signals::InvertedValue::Clockwise_Positive);
drivetrain_writer.set_left_inverted(
- ctre::phoenixpro::signals::InvertedValue::CounterClockwise_Positive);
+ ctre::phoenix6::signals::InvertedValue::CounterClockwise_Positive);
SuperstructureCANWriter superstructure_can_writer(&can_output_event_loop);
superstructure_can_writer.set_roller_falcon(roller);
diff --git a/y2023/y2023_roborio.json b/y2023/y2023_roborio.json
index 33d9904..c1e42e6 100644
--- a/y2023/y2023_roborio.json
+++ b/y2023/y2023_roborio.json
@@ -300,7 +300,7 @@
},
{
"name": "/roborio",
- "type": "y2023.CANConfiguration",
+ "type": "frc971.CANConfiguration",
"source_node": "roborio",
"frequency": 2
},