diff --git a/.clippy.toml b/.clippy.toml index 4dd68bb5c..8eb9e0003 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,2 +1,2 @@ # Specify the minimum supported Rust version -msrv = "1.40.0" +msrv = "1.54.0" diff --git a/.github/workflows/cbindgen.yml b/.github/workflows/cbindgen.yml index f2614e9b3..65aa42db2 100644 --- a/.github/workflows/cbindgen.yml +++ b/.github/workflows/cbindgen.yml @@ -14,57 +14,43 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install stable - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@stable with: - profile: minimal - toolchain: stable - override: true - components: rustfmt + components: "clippy, rustfmt" - name: Run rustfmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: -- --check - - - name: Install clippy - uses: dtolnay/rust-toolchain@clippy + run: | + cargo fmt --check - name: Run clippy run: | cargo clippy --workspace -- -D warnings - name: Install minimum supported Rust version - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.54.0 + id: msrv + uses: dtolnay/rust-toolchain@1.54 - name: Build with minimum supported Rust version run: | - cargo +1.54.0 test nonexistent-test --verbose + cargo +${{steps.msrv.outputs.name}} test nonexistent-test --verbose build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true + - name: Install stable Rust + uses: dtolnay/rust-toolchain@stable - name: Install Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: - python-version: '3.8.*' + python-version: '3.8' - name: Install Cython run: | @@ -79,20 +65,23 @@ jobs: run: | cargo build --verbose --no-default-features - - name: Test + - name: Test package env: CBINDGEN_TEST_VERIFY: 1 run: | - cargo test --verbose + cargo package --verbose + (cd target/package/cbindgen-$(cargo run -- --version | cut -d ' ' -f 2) && cargo test --verbose) - - name: Test package + - name: Install nightly Rust + uses: dtolnay/rust-toolchain@nightly + + - name: Test env: CBINDGEN_TEST_VERIFY: 1 run: | - cargo package --verbose - (cd target/package/cbindgen-$(cargo run -- --version | cut -d ' ' -f 2) && cargo test --verbose) + cargo +nightly test --verbose - name: Test minimal-versions run: | - cargo update -Zminimal-versions - cargo test + cargo +nightly update -Zminimal-versions + cargo +nightly test diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 475b28c48..379e476d4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,14 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install stable - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true + uses: dtolnay/rust-toolchain@stable - name: Build cbindgen run: | diff --git a/CHANGES b/CHANGES index 39e61a3ed..3a2a24261 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +## 0.24.4 + + * Move expand infinite recursion fix (#799) + * Add with_cpp_compat to the builder (#796) + * Handle never type in return position consistently (#780) + * Fix warnings (#816, #819) + * Updated documentation (#788, #791, #792, #810, #823) + ## 0.24.3 * Make struct expressions correctly generated through typedefs (#768). diff --git a/Cargo.lock b/Cargo.lock index b5e8a93e4..3c5e7a3fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cbindgen" -version = "0.24.3" +version = "0.24.4" dependencies = [ "clap", "heck", @@ -38,7 +38,7 @@ dependencies = [ "serde", "serde_json", "serial_test", - "syn", + "syn 1.0.109", "tempfile", "toml", ] @@ -51,39 +51,48 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.1.6" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags", + "clap_lex", "indexmap", - "os_str_bytes", "strsim", "termcolor", "textwrap", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[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", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -96,9 +105,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.0" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -115,9 +124,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "lazy_static" @@ -127,42 +136,34 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - [[package]] name = "os_str_bytes" -version = "6.0.0" +version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" [[package]] name = "parking_lot" @@ -177,9 +178,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", @@ -191,27 +192,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.17" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -227,9 +228,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "scopeguard" @@ -239,29 +240,29 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -287,14 +288,14 @@ checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "strsim" @@ -304,13 +305,24 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.89" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -329,33 +341,33 @@ dependencies = [ [[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", ] [[package]] name = "textwrap" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "toml" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index ce91d4eea..fafb18805 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cbindgen" -version = "0.24.3" +version = "0.24.4" authors = [ "Emilio Cobos Álvarez ", "Jeff Muizelaar ", @@ -11,22 +11,19 @@ license = "MPL-2.0" description = "A tool for generating C bindings to Rust code." keywords = ["bindings", "ffi", "code-generation"] categories = ["external-ffi-bindings", "development-tools::ffi"] -repository = "https://github.com/eqrion/cbindgen/" +repository = "https://github.com/eqrion/cbindgen" edition = "2018" exclude = [ "tests/profile.rs", # Test relies in a sub-crate, see https://github.com/rust-lang/cargo/issues/9017 ] -[badges] -travis-ci = { repository = "eqrion/cbindgen" } - [dependencies] clap = { version = "3.1", optional = true } indexmap = "1" log = "0.4" -serde = { version = "1.0.103", default-features = false, features = ["derive"]} +serde = { version = "1.0.103", default-features = false, features = ["derive"] } serde_json = "1.0" -tempfile = "3.0" +tempfile = "=3.3.0" toml = "0.5" proc-macro2 = "1" quote = "1" diff --git a/README.md b/README.md index 837f7eca4..a67ece62f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# `cbindgen`   [![Build Status]][actions] [![Latest Version]][crates.io] [![Api Rustdoc]][rustdoc] [![Rust](https://img.shields.io/badge/rust-1.32%2B-blue.svg?maxAge=3600)](https://github.com/eqrion/cbindgen) +# `cbindgen`   [![Build Status]][actions] [![Latest Version]][crates.io] [![Api Rustdoc]][rustdoc] [![Rust](https://img.shields.io/badge/rust-1.54%2B-blue.svg?maxAge=3600)](https://github.com/eqrion/cbindgen) [Build Status]: https://github.com/eqrion/cbindgen/workflows/cbindgen/badge.svg [actions]: https://github.com/eqrion/cbindgen/actions @@ -49,6 +49,12 @@ cargo install --force cbindgen (--force just makes it update to the latest cbindgen if it's already installed) +Or with Homebrew, run + +```text +brew install cbindgen +``` + To use cbindgen you need two things: * A configuration (cbindgen.toml, which can be empty to start) @@ -79,6 +85,7 @@ in production: * [milksnake](https://github.com/getsentry/milksnake) * [webrender](https://searchfox.org/mozilla-central/source/gfx/webrender_bindings) ([generated header](https://searchfox.org/mozilla-central/source/__GENERATED__/gfx/webrender_bindings/webrender_ffi_generated.h)) * [stylo](https://searchfox.org/mozilla-central/source/layout/style) ([generated header](https://searchfox.org/mozilla-central/source/__GENERATED__/layout/style/ServoStyleConsts.h)) +* [maturin](https://github.com/PyO3/maturin) If you're using `cbindgen` and would like to be added to this list, please open a pull request! diff --git a/contributing.md b/contributing.md index 5cc7a1bca..5625d50d0 100644 --- a/contributing.md +++ b/contributing.md @@ -2,23 +2,23 @@ Thanks for wanting to contribute! -If you want help or mentorship, please file a Github issue and I'll be sure to provide guidance to the best of my ability. +If you want help or mentorship, please file a GitHub issue and I'll be sure to provide guidance to the best of my ability. Otherwise be sure to check out `internals.md` for an overview on the internals. ## Filing a pull request -Check out [Servo's Github workflow](https://github.com/servo/servo/wiki/Github-workflow) for an overview on creating a pull request. +Check out [Servo's GitHub workflow](https://github.com/servo/servo/wiki/Github-workflow) for an overview on creating a pull request. Don't worry about requesting code review, as there is nothing formally setup for this repository. I try and review each pull request as soon as I can. -There is continuous integration setup for `cbindgen` using [travis](https://travis-ci.org/). It automatically runs `cargo test` which runs `cbindgen` against a series of rust files from `tests/rust/` and checks that the output compiles using `gcc` or `g++`. +There is continuous integration setup for `cbindgen` using [GitHub Actions](https://github.com/eqrion/cbindgen/actions). It automatically runs `cargo test` which runs `cbindgen` against a series of Rust files from `tests/rust/` and checks that the output compiles using `gcc` or `g++`. In addition to a C/C++ compiler `cargo test` requires Python and Cython (`python -m pip install Cython`) for checking Cython bindings generated from tests (`.pyx` files). Please run `cargo test` before filing a pull request to be sure that all tests pass. This will also update the test expectations. -Rustfmt is also enforced by travis. To format your code install `rustfmt-preview` using `rustup component add rustfmt-preview` and then `cargo fmt`. Travis runs with rust nightly, so use `rustup run nightly -- cargo fmt` to guarantee consistent results. +Rustfmt is also enforced by GitHub Actions. To format your code install `rustfmt-preview` using `rustup component add rustfmt-preview` and then `cargo fmt`. GitHub Actions runs with Rust nightly, so use `rustup run nightly -- cargo fmt` to guarantee consistent results. Writing new tests with your pull requests is also appreciated. diff --git a/docs.md b/docs.md index 9a434aa06..d420f2dbe 100644 --- a/docs.md +++ b/docs.md @@ -72,7 +72,7 @@ Be sure to add the following section to your Cargo.toml: ``` [build-dependencies] -cbindgen = "0.20.0" +cbindgen = "0.24.0" ``` If you'd like to use a `build.rs` script with a `cbindgen.toml`, consider using [`cbindgen::generate()`](https://docs.rs/cbindgen/*/cbindgen/fn.generate.html) instead. @@ -514,7 +514,7 @@ documentation_style = "doxy" # * "full": The full documentation. # # default: "full" -documentation_style = "short" +documentation_length = "short" diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index b489d68a4..e164e79be 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -34,7 +34,7 @@ pub struct Bindings { noop: bool, } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] enum NamespaceOperation { Open, Close, diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index 76a142c91..17d4ad1df 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -149,6 +149,12 @@ impl Builder { self } + #[allow(unused)] + pub fn with_cpp_compat(mut self, cpp_compat: bool) -> Builder { + self.config.cpp_compat = cpp_compat; + self + } + #[allow(unused)] pub fn with_style(mut self, style: Style) -> Builder { self.config.style = style; @@ -339,6 +345,24 @@ impl Builder { } pub fn generate(self) -> Result { + // If macro expansion is enabled, then cbindgen will attempt to build the crate + // and will run its build script which may run cbindgen again. That second run may start + // infinite recursion, or overwrite previously written files with bindings. + // So if we are called recursively, we are skipping the whole generation + // and produce "noop" bindings that won't be able to overwrite anything. + if std::env::var("_CBINDGEN_IS_RUNNING").is_ok() { + return Ok(Bindings::new( + self.config, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), + true, + )); + } + let mut result = Parse::new(); if self.std_types { diff --git a/src/bindgen/cargo/cargo_metadata.rs b/src/bindgen/cargo/cargo_metadata.rs index b9d5c0111..01ab80f06 100644 --- a/src/bindgen/cargo/cargo_metadata.rs +++ b/src/bindgen/cargo/cargo_metadata.rs @@ -202,14 +202,9 @@ fn discover_target(manifest_path: &Path) -> Option { }; let field = "host: "; - rustc_output.lines().find_map(|l| { - // XXX l.strip_prefix(field) re-implemented to preserve MSRV - if l.starts_with(field) { - Some(l[field.len()..].into()) - } else { - None - } - }) + rustc_output + .lines() + .find_map(|l| l.strip_prefix(field).map(|stripped| stripped.to_string())) } /// The main entry point to obtaining metadata @@ -253,6 +248,6 @@ pub fn metadata( } }; - let meta: Metadata = serde_json::from_str(&*metadata)?; + let meta: Metadata = serde_json::from_str(&metadata)?; Ok(meta) } diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 0bc89ece5..459cd4081 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -4,6 +4,7 @@ use std::io::Write; +use crate::bindgen::config::Layout; use crate::bindgen::declarationtyperesolver::DeclarationType; use crate::bindgen::ir::{ConstExpr, Function, GenericArgument, Type}; use crate::bindgen::writer::{ListType, SourceWriter}; @@ -20,15 +21,16 @@ enum CDeclarator { is_ref: bool, }, Array(String), - Func(Vec<(Option, CDecl)>, bool), + Func { + args: Vec<(Option, CDecl)>, + layout: Layout, + never_return: bool, + }, } impl CDeclarator { fn is_ptr(&self) -> bool { - match self { - CDeclarator::Ptr { .. } | CDeclarator::Func(..) => true, - _ => false, - } + matches!(self, CDeclarator::Ptr { .. } | CDeclarator::Func { .. }) } } @@ -89,9 +91,9 @@ impl CDecl { cdecl } - fn from_func(f: &Function, layout_vertical: bool, config: &Config) -> CDecl { + fn from_func(f: &Function, layout: Layout, config: &Config) -> CDecl { let mut cdecl = CDecl::new(); - cdecl.build_func(f, layout_vertical, config); + cdecl.build_func(f, layout, config); cdecl } @@ -100,7 +102,7 @@ impl CDecl { self } - fn build_func(&mut self, f: &Function, layout_vertical: bool, config: &Config) { + fn build_func(&mut self, f: &Function, layout: Layout, config: &Config) { let args = f .args .iter() @@ -116,8 +118,11 @@ impl CDecl { ) }) .collect(); - self.declarators - .push(CDeclarator::Func(args, layout_vertical)); + self.declarators.push(CDeclarator::Func { + args, + layout, + never_return: f.never_return, + }); self.build_type(&f.ret, false, config); } @@ -186,6 +191,7 @@ impl CDecl { ref ret, ref args, is_nullable: _, + never_return, } => { let args = args .iter() @@ -196,7 +202,11 @@ impl CDecl { is_nullable: true, is_ref: false, }); - self.declarators.push(CDeclarator::Func(args, false)); + self.declarators.push(CDeclarator::Func { + args, + layout: config.function.args.clone(), + never_return: *never_return, + }); self.build_type(ret, false, config); } } @@ -307,7 +317,7 @@ impl CDecl { out.write("("); } } - CDeclarator::Func(..) => { + CDeclarator::Func { .. } => { if next_is_pointer { out.write("("); } @@ -341,7 +351,11 @@ impl CDecl { last_was_pointer = false; } - CDeclarator::Func(ref args, layout_vertical) => { + CDeclarator::Func { + ref args, + ref layout, + never_return, + } => { if last_was_pointer { out.write(")"); } @@ -350,10 +364,16 @@ impl CDecl { if args.is_empty() && config.language == Language::C { out.write("void"); } - if layout_vertical { + + fn write_vertical( + out: &mut SourceWriter, + config: &Config, + args: &[(Option, CDecl)], + ident: Option<&str>, + ) { let align_length = out.line_length_for_align(); out.push_set_spaces(align_length); - for (i, &(ref arg_ident, ref arg_ty)) in args.iter().enumerate() { + for (i, (arg_ident, arg_ty)) in args.iter().enumerate() { if i != 0 { out.write(","); out.new_line(); @@ -379,8 +399,15 @@ impl CDecl { } } out.pop_tab(); - } else { - for (i, &(ref arg_ident, ref arg_ty)) in args.iter().enumerate() { + } + + fn write_horizontal( + out: &mut SourceWriter, + config: &Config, + args: &[(Option, CDecl)], + ident: Option<&str>, + ) { + for (i, (arg_ident, arg_ty)) in args.iter().enumerate() { if i != 0 { out.write(", "); } @@ -405,8 +432,27 @@ impl CDecl { } } } + + match layout { + Layout::Vertical => write_vertical(out, config, args, ident), + Layout::Horizontal => write_horizontal(out, config, args, ident), + Layout::Auto => { + if !out.try_write( + |out| write_horizontal(out, config, args, ident), + config.line_length, + ) { + write_vertical(out, config, args, ident) + } + } + } out.write(")"); + if never_return && config.language != Language::Cython { + if let Some(ref no_return_attr) = config.function.no_return { + out.write_fmt(format_args!(" {}", no_return_attr)); + } + } + last_was_pointer = true; } } @@ -416,14 +462,14 @@ impl CDecl { fn is_func(&self) -> bool { self.declarators .iter() - .any(|decl| matches!(decl, CDeclarator::Func(_, _))) + .any(|decl| matches!(decl, CDeclarator::Func { .. })) } } pub fn write_func( out: &mut SourceWriter, f: &Function, - layout_vertical: bool, + layout: Layout, config: &Config, ) { let rename_ident; @@ -435,7 +481,8 @@ pub fn write_func( } _ => f.path().name(), }; - CDecl::from_func(f, layout_vertical, config).write(out, Some(ident), config); + + CDecl::from_func(f, layout, config).write(out, Some(ident), config); } pub fn write_field(out: &mut SourceWriter, t: &Type, ident: &str, config: &Config) { diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 47a192e8a..ace64f788 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -18,7 +18,7 @@ pub use crate::bindgen::rename::RenameRule; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); /// A language type to generate bindings for. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Language { Cxx, C, @@ -121,7 +121,7 @@ impl FromStr for LineEndingStyle { deserialize_enum_str!(LineEndingStyle); /// A style of braces to use for generating code. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Braces { SameLine, NextLine, @@ -144,7 +144,7 @@ impl FromStr for Braces { deserialize_enum_str!(Braces); /// A type of layout to use when generating long lines of code. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Layout { Horizontal, Vertical, @@ -170,7 +170,7 @@ impl FromStr for Layout { deserialize_enum_str!(Layout); /// How the comments containing documentation should be styled. -#[derive(Debug, Clone, PartialEq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum DocumentationStyle { C, C99, @@ -221,7 +221,7 @@ impl FromStr for DocumentationLength { deserialize_enum_str!(DocumentationLength); /// A style of Style to use when generating structs and enums. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Style { Both, Tag, @@ -278,7 +278,7 @@ impl FromStr for Style { deserialize_enum_str!(Style); /// Different item types that we can generate and filter. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum ItemType { Constants, Globals, @@ -312,7 +312,7 @@ impl FromStr for ItemType { deserialize_enum_str!(ItemType); /// Type which specifies the sort order of functions -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SortKey { Name, None, @@ -731,7 +731,7 @@ pub struct MacroExpansionConfig { } /// Controls which Cargo profile is used for macro expansion. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Profile { Debug, Release, diff --git a/src/bindgen/dependencies.rs b/src/bindgen/dependencies.rs index 870d12919..6a9873818 100644 --- a/src/bindgen/dependencies.rs +++ b/src/bindgen/dependencies.rs @@ -26,17 +26,15 @@ impl Dependencies { // Sort untagged enums and opaque structs into their own layers because they don't // depend on each other or anything else. let ordering = |a: &ItemContainer, b: &ItemContainer| match (a, b) { - (&ItemContainer::Enum(ref x), &ItemContainer::Enum(ref y)) + (ItemContainer::Enum(x), ItemContainer::Enum(y)) if x.tag.is_none() && y.tag.is_none() => { x.path.cmp(&y.path) } - (&ItemContainer::Enum(ref x), _) if x.tag.is_none() => Ordering::Less, - (_, &ItemContainer::Enum(ref x)) if x.tag.is_none() => Ordering::Greater, + (ItemContainer::Enum(x), _) if x.tag.is_none() => Ordering::Less, + (_, ItemContainer::Enum(x)) if x.tag.is_none() => Ordering::Greater, - (&ItemContainer::OpaqueItem(ref x), &ItemContainer::OpaqueItem(ref y)) => { - x.path.cmp(&y.path) - } + (ItemContainer::OpaqueItem(x), ItemContainer::OpaqueItem(y)) => x.path.cmp(&y.path), (&ItemContainer::OpaqueItem(_), _) => Ordering::Less, (_, &ItemContainer::OpaqueItem(_)) => Ordering::Greater, diff --git a/src/bindgen/ir/annotation.rs b/src/bindgen/ir/annotation.rs index 208a17778..c3c8db03d 100644 --- a/src/bindgen/ir/annotation.rs +++ b/src/bindgen/ir/annotation.rs @@ -130,19 +130,19 @@ impl AnnotationSet { pub fn list(&self, name: &str) -> Option> { match self.annotations.get(name) { - Some(&AnnotationValue::List(ref x)) => Some(x.clone()), + Some(AnnotationValue::List(x)) => Some(x.clone()), _ => None, } } pub fn atom(&self, name: &str) -> Option> { match self.annotations.get(name) { - Some(&AnnotationValue::Atom(ref x)) => Some(x.clone()), + Some(AnnotationValue::Atom(x)) => Some(x.clone()), _ => None, } } pub fn bool(&self, name: &str) -> Option { match self.annotations.get(name) { - Some(&AnnotationValue::Bool(ref x)) => Some(*x), + Some(AnnotationValue::Bool(x)) => Some(*x), _ => None, } } @@ -152,7 +152,7 @@ impl AnnotationSet { T: Default + FromStr, { match self.annotations.get(name) { - Some(&AnnotationValue::Atom(ref x)) => Some( + Some(AnnotationValue::Atom(x)) => Some( x.as_ref() .map_or(T::default(), |y| y.parse::().ok().unwrap()), ), diff --git a/src/bindgen/ir/cfg.rs b/src/bindgen/ir/cfg.rs index f4c7e1a76..82d1a64c8 100644 --- a/src/bindgen/ir/cfg.rs +++ b/src/bindgen/ir/cfg.rs @@ -201,13 +201,13 @@ pub trait ToCondition: Sized { fn to_condition(&self, config: &Config) -> Option; } -impl<'a> ToCondition for Option { +impl ToCondition for Option { fn to_condition(&self, config: &Config) -> Option { self.as_ref()?.to_condition(config) } } -impl<'a> ToCondition for Cfg { +impl ToCondition for Cfg { fn to_condition(&self, config: &Config) -> Option { match *self { Cfg::Boolean(ref cfg_name) => { diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index b21c445e4..908feae2b 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -1197,7 +1197,7 @@ impl Enum { write!(out, "static {} {}(", self.export_name, variant.export_name); if let VariantBody::Body { ref body, .. } = variant.body { - let skip_fields = if body.has_tag_field { 1 } else { 0 }; + let skip_fields = body.has_tag_field as usize; let vec: Vec<_> = body .fields .iter() @@ -1224,7 +1224,7 @@ impl Enum { .. } = variant.body { - let skip_fields = if body.has_tag_field { 1 } else { 0 }; + let skip_fields = body.has_tag_field as usize; for field in body.fields.iter().skip(skip_fields) { out.new_line(); match field.ty { @@ -1279,7 +1279,7 @@ impl Enum { VariantBody::Empty(..) => return, }; - let skip_fields = if body.has_tag_field { 1 } else { 0 }; + let skip_fields = body.has_tag_field as usize; let field_count = body.fields.len() - skip_fields; if field_count == 0 { return; diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index a2d0d2275..29dc67026 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -12,8 +12,7 @@ use crate::bindgen::config::{Config, Language, Layout}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ - AnnotationSet, Cfg, ConditionWrite, Documentation, GenericPath, Path, PrimitiveType, - ToCondition, Type, + AnnotationSet, Cfg, ConditionWrite, Documentation, GenericPath, Path, ToCondition, Type, }; use crate::bindgen::library::Library; use crate::bindgen::monomorph::Monomorphs; @@ -56,18 +55,7 @@ impl Function { ) -> Result { let mut args = sig.inputs.iter().try_skip_map(|x| x.as_argument())?; - let mut never_return = false; - let mut ret = match sig.output { - syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), - syn::ReturnType::Type(_, ref ty) => { - if let syn::Type::Never(_) = ty.as_ref() { - never_return = true; - Type::Primitive(PrimitiveType::Void) - } else { - Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void)) - } - } - }; + let (mut ret, never_return) = Type::load_from_output(&sig.output)?; if let Some(self_path) = self_type_path { for arg in &mut args { @@ -89,10 +77,6 @@ impl Function { }) } - pub(crate) fn never_return(&self, config: &Config) -> bool { - self.never_return && config.language != Language::Cython - } - pub fn swift_name(&self, config: &Config) -> Option { if config.language == Language::Cython { return None; @@ -265,7 +249,7 @@ impl Function { }; for (i, arg) in self.args.iter().enumerate() { match &arg.ty { - Type::FuncPtr { ret, args, is_nullable: _ } => { + Type::FuncPtr { ret, args, is_nullable: _, never_return: _ } => { out.write("[UnmanagedFunctionPointer(CallingConvention.Cdecl)]"); out.new_line(); out.write("public delegate "); @@ -337,7 +321,7 @@ impl Source for Function { } } } - cdecl::write_func(out, func, false, config); + cdecl::write_func(out, func, Layout::Horizontal, config); if !func.extern_decl { if let Some(ref postfix) = postfix { @@ -351,12 +335,6 @@ impl Source for Function { } } - if func.never_return(config) { - if let Some(ref no_return_attr) = config.function.no_return { - out.write_fmt(format_args!(" {}", no_return_attr)); - } - } - out.write(";"); condition.write_after(config, out); @@ -401,7 +379,7 @@ impl Source for Function { } } } - cdecl::write_func(out, func, true, config); + cdecl::write_func(out, func, Layout::Vertical, config); if !func.extern_decl { if let Some(ref postfix) = postfix { out.new_line(); @@ -415,19 +393,11 @@ impl Source for Function { } } - if func.never_return(config) { - if let Some(ref no_return_attr) = config.function.no_return { - out.write_fmt(format_args!(" {}", no_return_attr)); - } - } - out.write(";"); condition.write_after(config, out); } - let option_1 = out.measure(|out| write_1(self, config, out)); - if config.language == Language::Csharp { write!( out, @@ -439,12 +409,14 @@ impl Source for Function { self.write_delegate_types(config, out); } - if (config.function.args == Layout::Auto && option_1 <= config.line_length) - || config.function.args == Layout::Horizontal - { - write_1(self, config, out); - } else { - write_2(self, config, out); + match config.function.args { + Layout::Horizontal => write_1(self, config, out), + Layout::Vertical => write_2(self, config, out), + Layout::Auto => { + if !out.try_write(|out| write_1(self, config, out), config.line_length) { + write_2(self, config, out) + } + } } if config.language == Language::Csharp { diff --git a/src/bindgen/ir/item.rs b/src/bindgen/ir/item.rs index a1c3a7521..16d98f55d 100644 --- a/src/bindgen/ir/item.rs +++ b/src/bindgen/ir/item.rs @@ -219,12 +219,12 @@ impl ItemMap { F: FnMut(&T), { match self.data.get(path) { - Some(&ItemValue::Cfg(ref items)) => { + Some(ItemValue::Cfg(items)) => { for item in items { callback(item); } } - Some(&ItemValue::Single(ref item)) => { + Some(ItemValue::Single(item)) => { callback(item); } None => {} diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 22a9434de..c1e51ba53 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -294,10 +294,7 @@ impl Item for Struct { // Rename the types used in fields { - let fields = self - .fields - .iter_mut() - .skip(if self.has_tag_field { 1 } else { 0 }); + let fields = self.fields.iter_mut().skip(self.has_tag_field as usize); for field in fields { field.ty.rename_for_config(config, &self.generic_params); } @@ -616,7 +613,7 @@ impl Source for Struct { out.close_brace(false); } - let skip_fields = if self.has_tag_field { 1 } else { 0 }; + let skip_fields = self.has_tag_field as usize; macro_rules! emit_op { ($op_name:expr, $op:expr, $conjuc:expr) => {{ diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index c08020b10..d51cd638e 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -300,10 +300,7 @@ impl PrimitiveType { } fn can_cmp_order(&self) -> bool { - match *self { - PrimitiveType::Bool => false, - _ => true, - } + !matches!(*self, PrimitiveType::Bool) } fn can_cmp_eq(&self) -> bool { @@ -407,6 +404,7 @@ pub enum Type { ret: Box, args: Vec<(Option, Type)>, is_nullable: bool, + never_return: bool, }, } @@ -420,6 +418,22 @@ impl Type { } } + pub fn load_from_output(output: &syn::ReturnType) -> Result<(Type, bool), String> { + let mut never_return = false; + let ty = match output { + syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), + syn::ReturnType::Type(_, ref ty) => { + if let syn::Type::Never(_) = ty.as_ref() { + never_return = true; + Type::Primitive(PrimitiveType::Void) + } else { + Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void)) + } + } + }; + Ok((ty, never_return)) + } + pub fn load(ty: &syn::Type) -> Result, String> { let converted = match *ty { syn::Type::Reference(ref reference) => { @@ -507,21 +521,12 @@ impl Type { }) }) })?; - let ret = match function.output { - syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), - syn::ReturnType::Type(_, ref ty) => { - if let Some(x) = Type::load(ty)? { - x - } else { - Type::Primitive(PrimitiveType::Void) - } - } - }; - + let (ret, never_return) = Type::load_from_output(&function.output)?; Type::FuncPtr { ret: Box::new(ret), args, is_nullable: false, + never_return, } } syn::Type::Tuple(ref tuple) => { @@ -543,10 +548,7 @@ impl Type { pub fn is_primitive_or_ptr_primitive(&self) -> bool { match *self { Type::Primitive(..) => true, - Type::Ptr { ref ty, .. } => match ty.as_ref() { - Type::Primitive(..) => true, - _ => false, - }, + Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive(..)), _ => false, } } @@ -585,10 +587,12 @@ impl Type { ref ret, ref args, is_nullable: false, + never_return, } => Some(Type::FuncPtr { ret: ret.clone(), args: args.clone(), is_nullable: true, + never_return, }), _ => None, } @@ -784,6 +788,7 @@ impl Type { ref ret, ref args, is_nullable, + never_return, } => Type::FuncPtr { ret: Box::new(ret.specialize(mappings)), args: args @@ -792,6 +797,7 @@ impl Type { .map(|(name, ty)| (name, ty.specialize(mappings))) .collect(), is_nullable, + never_return, }, } } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 23ec38dc6..c00a6ebc6 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -54,24 +54,6 @@ impl Library { } pub fn generate(mut self) -> Result { - // If macro expansion is enabled, then cbindgen will attempt to build the crate - // and will run its build script which may run cbindgen again. That second run may start - // infinite recursion, or overwrite previously written files with bindings. - // So if we are called recursively, we are skipping the whole generation - // and produce "noop" bindings that won't be able to overwrite anything. - if std::env::var("_CBINDGEN_IS_RUNNING").is_ok() { - return Ok(Bindings::new( - self.config, - Default::default(), - Default::default(), - Default::default(), - Default::default(), - Default::default(), - Default::default(), - true, - )); - } - self.transfer_annotations(); self.simplify_standard_types(); diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs index f20bb3ce9..c8769f83c 100644 --- a/src/bindgen/mangle.rs +++ b/src/bindgen/mangle.rs @@ -112,13 +112,13 @@ impl<'a> Mangler<'a> { } else { Separator::BeginMutPtr }); - self.append_mangled_type(&**ty, last); + self.append_mangled_type(ty, last); } Type::FuncPtr { ref ret, ref args, .. } => { self.push(Separator::BeginFn); - self.append_mangled_type(&**ret, args.is_empty()); + self.append_mangled_type(ret, args.is_empty()); for (i, arg) in args.iter().enumerate() { self.push(Separator::BetweenFnArg); let last = last && i == args.len() - 1; diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 81681ba17..a964cd2d8 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -515,10 +515,10 @@ impl Parse { self.load_syn_ty(crate_name, mod_cfg, item); } syn::Item::Impl(ref item_impl) => { - let has_assoc_const = item_impl.items.iter().any(|item| match item { - syn::ImplItem::Const(_) => true, - _ => false, - }); + let has_assoc_const = item_impl + .items + .iter() + .any(|item| matches!(item, syn::ImplItem::Const(_))); if has_assoc_const { impls_with_assoc_consts.push(item_impl); } diff --git a/src/bindgen/writer.rs b/src/bindgen/writer.rs index 785608093..6ea68fce9 100644 --- a/src/bindgen/writer.rs +++ b/src/bindgen/writer.rs @@ -19,18 +19,6 @@ pub enum ListType<'a> { Wrap(&'a str, &'a str), } -/// An empty file used for creating a null source writer and measuring line -/// metrics for various code layouts. -pub struct NullFile; -impl Write for NullFile { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - /// A utility wrapper to write unbuffered data and correctly adjust positions. struct InnerWriter<'a, 'b: 'a, F: 'a + Write>(&'a mut SourceWriter<'b, F>); @@ -68,7 +56,7 @@ pub struct SourceWriter<'a, F: Write> { max_line_length: usize, } -pub type MeasureWriter<'a> = SourceWriter<'a, NullFile>; +pub type MeasureWriter<'a> = SourceWriter<'a, &'a mut Vec>; impl<'a, F: Write> SourceWriter<'a, F> { pub fn new(out: F, bindings: &'a Bindings) -> Self { @@ -89,23 +77,39 @@ impl<'a, F: Write> SourceWriter<'a, F> { /// Takes a function that writes source and returns the maximum line length /// written. - pub fn measure(&self, func: T) -> usize + pub fn try_write(&mut self, func: T, max_line_length: usize) -> bool where T: Fn(&mut MeasureWriter), { - let mut measurer = SourceWriter { - out: NullFile, - bindings: self.bindings, - spaces: self.spaces.clone(), - line_started: self.line_started, - line_length: self.line_length, - line_number: self.line_number, - max_line_length: self.line_length, - }; + if self.line_length > max_line_length { + return false; + } - func(&mut measurer); + let mut buffer = Vec::new(); + let line_length = { + let mut measurer = SourceWriter { + out: &mut buffer, + bindings: self.bindings, + spaces: self.spaces.clone(), + line_started: self.line_started, + line_length: self.line_length, + line_number: self.line_number, + max_line_length: self.line_length, + }; + + func(&mut measurer); + + measurer.max_line_length + }; - measurer.max_line_length + if line_length > max_line_length { + return false; + } + // We don't want the extra alignment, it's already accounted for by the + // measurer. + self.line_started = true; + InnerWriter(self).write_all(&buffer).unwrap(); + true } fn spaces(&self) -> usize { @@ -205,10 +209,10 @@ impl<'a, F: Write> SourceWriter<'a, F> { InnerWriter(self).write_fmt(fmt).unwrap(); } - pub fn write_horizontal_source_list<'b, S: Source>( + pub fn write_horizontal_source_list( &mut self, items: &[S], - list_type: ListType<'b>, + list_type: ListType<'_>, ) { for (i, item) in items.iter().enumerate() { item.write(&self.bindings.config, self); @@ -226,11 +230,7 @@ impl<'a, F: Write> SourceWriter<'a, F> { } } - pub fn write_vertical_source_list<'b, S: Source>( - &mut self, - items: &[S], - list_type: ListType<'b>, - ) { + pub fn write_vertical_source_list(&mut self, items: &[S], list_type: ListType<'_>) { let align_length = self.line_length_for_align(); self.push_set_spaces(align_length); for (i, item) in items.iter().enumerate() { diff --git a/src/main.rs b/src/main.rs index 3e55f9666..d8d209ca3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,7 +113,7 @@ fn load_bindings(input: &Path, matches: &ArgMatches) -> Result let binding_crate_dir = lib.find_crate_dir(&lib.binding_crate_ref()); if let Some(binding_crate_dir) = binding_crate_dir { - Config::from_root_or_default(&binding_crate_dir) + Config::from_root_or_default(binding_crate_dir) } else { // This shouldn't happen Config::from_root_or_default(input) @@ -157,7 +157,7 @@ fn main() { .long("lang") .value_name("LANGUAGE") .help("Specify the language to output bindings in") - .possible_values(&["c++", "C++", "c", "C", "cython", "Cython", "cs", "CS"]), + .possible_values(["c++", "C++", "c", "C", "cython", "Cython", "cs", "CS"]), ) .arg( Arg::new("cpp-compat") @@ -176,7 +176,7 @@ fn main() { .long("style") .value_name("STYLE") .help("Specify the declaration style to use for bindings") - .possible_values(&["Both", "both", "Tag", "tag", "Type", "type"]), + .possible_values(["Both", "both", "Tag", "tag", "Type", "type"]), ) .arg( Arg::new("d") @@ -253,7 +253,7 @@ fn main() { "Specify the profile to use when expanding macros. \ Has no effect otherwise." ) - .possible_values(&["Debug", "debug", "Release", "release"]), + .possible_values(["Debug", "debug", "Release", "release"]), ) .arg( Arg::new("quiet") diff --git a/tests/expectations/function_noreturn.both.c b/tests/expectations/function_noreturn.both.c new file mode 100644 index 000000000..1a21ba67f --- /dev/null +++ b/tests/expectations/function_noreturn.both.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +typedef struct Example { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +} Example; + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(struct Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); diff --git a/tests/expectations/function_noreturn.both.compat.c b/tests/expectations/function_noreturn.both.compat.c new file mode 100644 index 000000000..7336e5995 --- /dev/null +++ b/tests/expectations/function_noreturn.both.compat.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +typedef struct Example { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +} Example; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(struct Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/function_noreturn.c b/tests/expectations/function_noreturn.c index e715ae3b8..ba5c1167d 100644 --- a/tests/expectations/function_noreturn.c +++ b/tests/expectations/function_noreturn.c @@ -11,6 +11,10 @@ #endif // NO_RETURN_ATTR +typedef struct { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +} Example; + void loop_forever(void) NO_RETURN_ATTR; -uint8_t normal_return(void); +uint8_t normal_return(Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); diff --git a/tests/expectations/function_noreturn.compat.c b/tests/expectations/function_noreturn.compat.c index 12238b3bb..6ea836f09 100644 --- a/tests/expectations/function_noreturn.compat.c +++ b/tests/expectations/function_noreturn.compat.c @@ -11,13 +11,17 @@ #endif // NO_RETURN_ATTR +typedef struct { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +} Example; + #ifdef __cplusplus extern "C" { #endif // __cplusplus void loop_forever(void) NO_RETURN_ATTR; -uint8_t normal_return(void); +uint8_t normal_return(Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/function_noreturn.cpp b/tests/expectations/function_noreturn.cpp index 9a3040c97..5adbe111a 100644 --- a/tests/expectations/function_noreturn.cpp +++ b/tests/expectations/function_noreturn.cpp @@ -12,10 +12,14 @@ #endif // NO_RETURN_ATTR +struct Example { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +}; + extern "C" { void loop_forever() NO_RETURN_ATTR; -uint8_t normal_return(); +uint8_t normal_return(Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); } // extern "C" diff --git a/tests/expectations/function_noreturn.pyx b/tests/expectations/function_noreturn.pyx index 1af76c542..21683cbd9 100644 --- a/tests/expectations/function_noreturn.pyx +++ b/tests/expectations/function_noreturn.pyx @@ -14,6 +14,9 @@ cdef extern from *: cdef extern from *: + ctypedef struct Example: + void (*f)(uintptr_t, uintptr_t); + void loop_forever(); - uint8_t normal_return(); + uint8_t normal_return(Example arg, void (*other)(uint8_t)); diff --git a/tests/expectations/function_noreturn.tag.c b/tests/expectations/function_noreturn.tag.c new file mode 100644 index 000000000..48ead97ca --- /dev/null +++ b/tests/expectations/function_noreturn.tag.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +struct Example { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +}; + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(struct Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); diff --git a/tests/expectations/function_noreturn.tag.compat.c b/tests/expectations/function_noreturn.tag.compat.c new file mode 100644 index 000000000..dcb0e5b0c --- /dev/null +++ b/tests/expectations/function_noreturn.tag.compat.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +struct Example { + void (*f)(uintptr_t, uintptr_t) NO_RETURN_ATTR; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void loop_forever(void) NO_RETURN_ATTR; + +uint8_t normal_return(struct Example arg, void (*other)(uint8_t) NO_RETURN_ATTR); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/function_noreturn.tag.pyx b/tests/expectations/function_noreturn.tag.pyx new file mode 100644 index 000000000..6235dca0e --- /dev/null +++ b/tests/expectations/function_noreturn.tag.pyx @@ -0,0 +1,22 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list +#ifndef NO_RETURN_ATTR + #ifdef __GNUC__ + #define NO_RETURN_ATTR __attribute__ ((noreturn)) + #else // __GNUC__ + #define NO_RETURN_ATTR + #endif // __GNUC__ +#endif // NO_RETURN_ATTR + + +cdef extern from *: + + cdef struct Example: + void (*f)(uintptr_t, uintptr_t); + + void loop_forever(); + + uint8_t normal_return(Example arg, void (*other)(uint8_t)); diff --git a/tests/expectations/function_ptr.c b/tests/expectations/function_ptr.c new file mode 100644 index 000000000..1041a6b34 --- /dev/null +++ b/tests/expectations/function_ptr.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +typedef void (*MyCallback)(uintptr_t a, uintptr_t b); + +typedef void (*MyOtherCallback)(uintptr_t a, + uintptr_t lot, + uintptr_t of, + uintptr_t args, + uintptr_t and_then_some); + +void my_function(MyCallback a, MyOtherCallback b); diff --git a/tests/expectations/function_ptr.compat.c b/tests/expectations/function_ptr.compat.c new file mode 100644 index 000000000..be3870ce1 --- /dev/null +++ b/tests/expectations/function_ptr.compat.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +typedef void (*MyCallback)(uintptr_t a, uintptr_t b); + +typedef void (*MyOtherCallback)(uintptr_t a, + uintptr_t lot, + uintptr_t of, + uintptr_t args, + uintptr_t and_then_some); + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void my_function(MyCallback a, MyOtherCallback b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/function_ptr.cpp b/tests/expectations/function_ptr.cpp new file mode 100644 index 000000000..217a16081 --- /dev/null +++ b/tests/expectations/function_ptr.cpp @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +using MyCallback = void(*)(uintptr_t a, uintptr_t b); + +using MyOtherCallback = void(*)(uintptr_t a, + uintptr_t lot, + uintptr_t of, + uintptr_t args, + uintptr_t and_then_some); + +extern "C" { + +void my_function(MyCallback a, MyOtherCallback b); + +} // extern "C" diff --git a/tests/expectations/function_ptr.pyx b/tests/expectations/function_ptr.pyx new file mode 100644 index 000000000..371774209 --- /dev/null +++ b/tests/expectations/function_ptr.pyx @@ -0,0 +1,17 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef void (*MyCallback)(uintptr_t a, uintptr_t b); + + ctypedef void (*MyOtherCallback)(uintptr_t a, + uintptr_t lot, + uintptr_t of, + uintptr_t args, + uintptr_t and_then_some); + + void my_function(MyCallback a, MyOtherCallback b); diff --git a/tests/rust/function_noreturn.rs b/tests/rust/function_noreturn.rs index 94a23957a..d7777adb4 100644 --- a/tests/rust/function_noreturn.rs +++ b/tests/rust/function_noreturn.rs @@ -1,9 +1,14 @@ #[no_mangle] -pub extern fn loop_forever() -> ! { +pub extern "C" fn loop_forever() -> ! { loop {} } #[no_mangle] -pub extern fn normal_return() -> u8 { +pub extern "C" fn normal_return(arg: Example, other: extern "C" fn(u8) -> !) -> u8 { 0 } + +#[repr(C)] +pub struct Example { + pub f: extern "C" fn(usize, usize) -> !, +} diff --git a/tests/rust/function_ptr.rs b/tests/rust/function_ptr.rs new file mode 100644 index 000000000..59adb52b3 --- /dev/null +++ b/tests/rust/function_ptr.rs @@ -0,0 +1,6 @@ +pub type MyCallback = Option; + +pub type MyOtherCallback = Option; + +#[no_mangle] +pub extern "C" fn my_function(a: MyCallback, b: MyOtherCallback) {} diff --git a/tests/tests.rs b/tests/tests.rs index cd7133cdc..92adeded6 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -23,7 +23,7 @@ fn run_cbindgen( style: Option