diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml
new file mode 100644
index 0000000..544bfee
--- /dev/null
+++ b/.github/workflows/dependabot.yml
@@ -0,0 +1,41 @@
+name: Dependabot automation
+on:
+ pull_request:
+ check_run:
+ types: [completed]
+
+permissions:
+ contents: write
+ pull-requests: write
+
+jobs:
+ approve:
+ runs-on: ubuntu-latest
+ if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request' }}
+ steps:
+ - name: Fetch metadata
+ id: metadata
+ uses: dependabot/fetch-metadata@v1
+ with:
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
+ - name: Approve PR
+ env:
+ PR_URL: ${{github.event.pull_request.html_url}}
+ GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
+ run: gh pr review --approve "$PR_URL"
+
+ auto_merge:
+ runs-on: ubuntu-latest
+ if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'check_run' }}
+ steps:
+ - name: Fetch metadata
+ id: metadata
+ uses: dependabot/fetch-metadata@v1
+ with:
+ github-token: "${{ secrets.GITHUB_TOKEN }}"
+ - name: Enable PR auto-merge
+ if: steps.metadata.outputs.update-type == 'version-update:semver-patch'
+ env:
+ PR_URL: ${{github.event.pull_request.html_url}}
+ GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
+ run: gh pr merge --auto --merge "$PR_URL"
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 52ffcb7..bf4eaa6 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -41,7 +41,7 @@ jobs:
fail-fast: false
matrix:
toolchain:
- - "1.70" # Minimal supported Rust version (MSRV)
+ - "1.74" # Minimal supported Rust version (MSRV)
- stable
- beta
steps:
@@ -106,7 +106,7 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov.info
- fail_ci_if_error: true
+ fail_ci_if_error: false
deny:
runs-on: ubuntu-latest
diff --git a/Cargo.lock b/Cargo.lock
index 80f3b93..76a9513 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,9 +19,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
-version = "0.6.11"
+version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
+checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -33,9 +33,9 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.4"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
[[package]]
name = "anstyle-parse"
@@ -67,9 +67,9 @@ dependencies = [
[[package]]
name = "assert_cmd"
-version = "2.0.13"
+version = "2.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467"
+checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8"
dependencies = [
"anstyle",
"bstr",
@@ -92,17 +92,11 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-[[package]]
-name = "bitflags"
-version = "2.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
-
[[package]]
name = "bstr"
-version = "1.9.0"
+version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc"
+checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
dependencies = [
"memchr",
"regex-automata",
@@ -111,9 +105,9 @@ dependencies = [
[[package]]
name = "bumpalo"
-version = "3.14.0"
+version = "3.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
[[package]]
name = "cast"
@@ -129,9 +123,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ciborium"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
@@ -140,15 +134,15 @@ dependencies = [
[[package]]
name = "ciborium-io"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
-version = "0.2.1"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
@@ -261,6 +255,12 @@ version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
[[package]]
name = "difflib"
version = "0.4.0"
@@ -275,19 +275,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "either"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
-
-[[package]]
-name = "errno"
-version = "0.3.8"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
-dependencies = [
- "libc",
- "windows-sys",
-]
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "float-cmp"
@@ -300,9 +290,13 @@ dependencies = [
[[package]]
name = "half"
-version = "1.8.2"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
+checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
[[package]]
name = "heck"
@@ -312,9 +306,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
-version = "0.3.4"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "indoc"
@@ -324,12 +318,12 @@ checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]]
name = "is-terminal"
-version = "0.4.10"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
+checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
dependencies = [
"hermit-abi",
- "rustix",
+ "libc",
"windows-sys",
]
@@ -359,24 +353,18 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "js-sys"
-version = "0.3.67"
+version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
+checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
-version = "0.2.152"
+version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "lock_api"
@@ -390,9 +378,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.20"
+version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memchr"
@@ -417,9 +405,9 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-traits"
-version = "0.2.17"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
@@ -487,6 +475,12 @@ dependencies = [
"plotters-backend",
]
+[[package]]
+name = "portable-atomic"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+
[[package]]
name = "predicates"
version = "3.1.0"
@@ -538,23 +532,24 @@ dependencies = [
[[package]]
name = "pyo3"
-version = "0.20.2"
+version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a89dc7a5850d0e983be1ec2a463a171d20990487c3cfcd68b5363f1ee3d6fe0"
+checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233"
dependencies = [
"cfg-if",
"libc",
"memoffset",
"parking_lot",
+ "portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
]
[[package]]
name = "pyo3-build-config"
-version = "0.20.2"
+version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07426f0d8fe5a601f26293f300afd1a7b1ed5e78b2a705870c5f30893c5163be"
+checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7"
dependencies = [
"once_cell",
"target-lexicon",
@@ -562,9 +557,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
-version = "0.20.2"
+version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbb7dec17e17766b46bca4f1a4215a85006b4c2ecde122076c562dd058da6cf1"
+checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa"
dependencies = [
"libc",
"pyo3-build-config",
@@ -572,7 +567,7 @@ dependencies = [
[[package]]
name = "pyo3_bindgen"
-version = "0.2.0"
+version = "0.3.0"
dependencies = [
"pyo3_bindgen_engine",
"pyo3_bindgen_macros",
@@ -580,7 +575,7 @@ dependencies = [
[[package]]
name = "pyo3_bindgen_cli"
-version = "0.2.0"
+version = "0.3.0"
dependencies = [
"assert_cmd",
"clap",
@@ -592,7 +587,7 @@ dependencies = [
[[package]]
name = "pyo3_bindgen_engine"
-version = "0.2.0"
+version = "0.3.0"
dependencies = [
"criterion",
"indoc",
@@ -602,12 +597,15 @@ dependencies = [
"pyo3",
"pyo3-build-config",
"quote",
+ "rustc-hash",
"syn",
+ "thiserror",
+ "typed-builder",
]
[[package]]
name = "pyo3_bindgen_macros"
-version = "0.2.0"
+version = "0.3.0"
dependencies = [
"proc-macro2",
"pyo3",
@@ -627,9 +625,9 @@ dependencies = [
[[package]]
name = "rayon"
-version = "1.8.1"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
+checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
dependencies = [
"either",
"rayon-core",
@@ -651,7 +649,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
- "bitflags 1.3.2",
+ "bitflags",
]
[[package]]
@@ -668,9 +666,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.4"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
dependencies = [
"aho-corasick",
"memchr",
@@ -684,23 +682,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
-name = "rustix"
-version = "0.38.30"
+name = "rustc-hash"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca"
-dependencies = [
- "bitflags 2.4.2",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys",
-]
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ryu"
-version = "1.0.16"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "same-file"
@@ -719,18 +710,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
-version = "1.0.195"
+version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.195"
+version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
@@ -739,9 +730,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.111"
+version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
+checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
dependencies = [
"itoa",
"ryu",
@@ -762,9 +753,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "syn"
-version = "2.0.49"
+version = "2.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496"
+checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
dependencies = [
"proc-macro2",
"quote",
@@ -773,9 +764,9 @@ dependencies = [
[[package]]
name = "target-lexicon"
-version = "0.12.13"
+version = "0.12.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
+checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
[[package]]
name = "termtree"
@@ -783,6 +774,26 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+[[package]]
+name = "thiserror"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "tinytemplate"
version = "1.2.1"
@@ -793,6 +804,26 @@ dependencies = [
"serde_json",
]
+[[package]]
+name = "typed-builder"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "444d8748011b93cb168770e8092458cb0f8854f931ff82fdf6ddfbd72a9c933e"
+dependencies = [
+ "typed-builder-macro",
+]
+
+[[package]]
+name = "typed-builder-macro"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "563b3b88238ec95680aef36bdece66896eaa7ce3c0f1b4f39d38fb2435261352"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "unicode-ident"
version = "1.0.12"
@@ -816,9 +847,9 @@ dependencies = [
[[package]]
name = "walkdir"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
@@ -826,9 +857,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
-version = "0.2.90"
+version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
+checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -836,9 +867,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.90"
+version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
+checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
dependencies = [
"bumpalo",
"log",
@@ -851,9 +882,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.90"
+version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
+checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -861,9 +892,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.90"
+version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
+checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
dependencies = [
"proc-macro2",
"quote",
@@ -874,15 +905,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.90"
+version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
+checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
[[package]]
name = "web-sys"
-version = "0.3.67"
+version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
+checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -925,7 +956,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets 0.52.0",
+ "windows-targets 0.52.4",
]
[[package]]
@@ -945,17 +976,17 @@ dependencies = [
[[package]]
name = "windows-targets"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
- "windows_aarch64_gnullvm 0.52.0",
- "windows_aarch64_msvc 0.52.0",
- "windows_i686_gnu 0.52.0",
- "windows_i686_msvc 0.52.0",
- "windows_x86_64_gnu 0.52.0",
- "windows_x86_64_gnullvm 0.52.0",
- "windows_x86_64_msvc 0.52.0",
+ "windows_aarch64_gnullvm 0.52.4",
+ "windows_aarch64_msvc 0.52.4",
+ "windows_i686_gnu 0.52.4",
+ "windows_i686_msvc 0.52.4",
+ "windows_x86_64_gnu 0.52.4",
+ "windows_x86_64_gnullvm 0.52.4",
+ "windows_x86_64_msvc 0.52.4",
]
[[package]]
@@ -966,9 +997,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
@@ -978,9 +1009,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
@@ -990,9 +1021,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
@@ -1002,9 +1033,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
@@ -1014,9 +1045,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
@@ -1026,9 +1057,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
@@ -1038,6 +1069,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.52.0"
+version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
diff --git a/Cargo.toml b/Cargo.toml
index 1b8fe0f..178b4d2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,13 +19,13 @@ keywords = ["bindgen", "ffi", "pyo3", "python"]
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/AndrejOrsula/pyo3_bindgen"
-rust-version = "1.70"
-version = "0.2.0"
+rust-version = "1.74"
+version = "0.3.0"
[workspace.dependencies]
-pyo3_bindgen = { path = "pyo3_bindgen", version = "0.2.0" }
-pyo3_bindgen_engine = { path = "pyo3_bindgen_engine", version = "0.2.0" }
-pyo3_bindgen_macros = { path = "pyo3_bindgen_macros", version = "0.2.0" }
+pyo3_bindgen = { path = "pyo3_bindgen", version = "0.3.0" }
+pyo3_bindgen_engine = { path = "pyo3_bindgen_engine", version = "0.3.0" }
+pyo3_bindgen_macros = { path = "pyo3_bindgen_macros", version = "0.3.0" }
assert_cmd = { version = "2" }
clap = { version = "4.5", features = ["derive"] }
@@ -38,4 +38,7 @@ proc-macro2 = { version = "1" }
pyo3 = { version = "0.20", default-features = false }
pyo3-build-config = { version = "0.20", features = ["resolve-config"] }
quote = { version = "1" }
+rustc-hash = { version = "1" }
syn = { version = "2" }
+thiserror = { version = "1" }
+typed-builder = { version = "0.18" }
diff --git a/README.md b/README.md
index f536dc0..2d0103e 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@ pub fn main() -> pyo3::PyResult<()> {
This project is intended to simplify the integration or transition of existing Python codebases into Rust. You, as a developer, gain immediate access to the Rust type system and countless other benefits of modern compiled languages with the generated bindings. Furthermore, the entire stock of high-quality crates from [crates.io](https://crates.io) becomes at your disposal.
-On its own, the generated Rust code does not provide any performance benefits over using the Python code (it might actually be slower — yet to be benchmarked). However, it can be used as a starting point for further optimization if you decide to rewrite performance-critical parts of your codebase in pure Rust.
+On its own, the generated Rust code does not provide any performance benefits over using the Python code. However, it can be used as a starting point for further optimization if you decide to rewrite performance-critical parts of your codebase in pure Rust.
## Overview
@@ -92,23 +92,24 @@ Add `pyo3` as a dependency and `pyo3_bindgen` as a build dependency to your [`Ca
pyo3 = { version = "0.20", features = ["auto-initialize"] }
[build-dependencies]
-pyo3_bindgen = { version = "0.1" }
+pyo3_bindgen = { version = "0.3" }
```
### Option 1: Build script
-Create a [`build.rs`](https://doc.rust-lang.org/cargo/reference/build-scripts.html) script in the root of your crate that generates bindings to the `target_module` Python module.
+Create a [`build.rs`](https://doc.rust-lang.org/cargo/reference/build-scripts.html) script in the root of your crate that generates bindings to the `py_module` Python module.
```rs
// build.rs
-
-fn main() {
- // Generate Rust bindings to the Python module
- pyo3_bindgen::build_bindings(
- "target_module",
- std::path::Path::new(&std::env::var("OUT_DIR").unwrap()).join("bindings.rs"),
- )
- .unwrap();
+use pyo3_bindgen::{Codegen, Config};
+
+fn main() -> Result<(), Box> {
+ // Generate Rust bindings to Python modules
+ Codegen::new(Config::default())?
+ .module_name("py_module")?
+ .module_names(&["other_module.core", "other_module.utils.io"])?
+ .build(std::path::Path::new(&std::env::var("OUT_DIR")?).join("bindings.rs"))?;
+ Ok(())
}
```
@@ -116,7 +117,7 @@ Afterwards, include the generated bindings anywhere in your crate.
```rs
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
-pub use target_module::*;
+pub use py_module::*;
```
### Option 2: CLI tool
@@ -131,7 +132,7 @@ Afterwards, run the `pyo3_bindgen` executable while passing the name of the targ
```bash
# Pass `--help` to show the usage and available options
-pyo3_bindgen -m target_module -o bindings.rs
+pyo3_bindgen -m py_module other_module.core -o bindings.rs
```
### Option 3 \[Experimental\]: Procedural macros
@@ -142,28 +143,30 @@ Enable the `macros` feature of `pyo3_bindgen`.
```toml
[build-dependencies]
-pyo3_bindgen = { version = "0.1", features = ["macros"] }
+pyo3_bindgen = { version = "0.3", features = ["macros"] }
```
Then, you can call the `import_python!` macro anywhere in your crate.
```rs
-pyo3_bindgen::import_python!("target_module");
-pub use target_module::*;
+pyo3_bindgen::import_python!("py_module");
+pub use py_module::*;
```
## Status
This project is in early development, and as such, the API of the generated bindings is not yet stable.
-- Not all Python types are mapped to their Rust equivalents yet. For this reason, some additional typecasting might be currently required when using the generated bindings (e.g. `let typed_value: target_module::Class = any_value.extract()?;`).
-- The binding generation is primarily designed to be used inside build scripts or via procedural macros. Therefore, the performance of the codegen process is [benchmarked](./pyo3_bindgen_engine/benches/bindgen.rs) to understand the potential impact on build times. Although there is currently plenty of room for optimization in the current naive implementation, even the largest modules are processed in less than a second on a *modern* laptop.
-- The generation of bindings should never panic as long as the target Python module can be successfully imported. If it does, it is a bug resulting from an unexpected edge-case Python module structure or an unforeseen combination of enabled PyO3 features.
-- However, the generated bindings might not directly compile in some specific cases. Currently, there are two known issue; bindings will contain duplicate function definitions if present in the original code, and function parameters might use the same name as a class defined in the same scope (allowed in Python but not in Rust). If you encounter any other issues, consider manually rewriting the problematic parts of the bindings.
-- Although implemented, the procedural macros might not work in all cases - especially when some PyO3 features are enabled. In most cases, PyO3 fails to import the target Python module when used from within a `proc_macro` crate. Therefore, it is recommended to use build scripts instead for now.
-- The code will be refactored and cleaned up in the upcoming releases. The current implementation is a result of a very quick prototype that was built to test the feasibility of the idea. For example, configurability of the generated bindings is planned (e.g. allowlist/ignorelist of attributes). Furthermore, automatic generation of dependent Python modules will be considered in order to provide a more complete typing experience.
-
-Please [report](https://github.com/AndrejOrsula/pyo3_bindgen/issues/new) any issues that you might encounter. Contributions are more than welcome! If you are looking for a place to start, consider searching for `TODO` comments in the codebase.
+- Not all Python types are mapped to their Rust equivalents yet. For this reason, some additional typecasting might be currently required when using the generated bindings (e.g. `let typed_value: py_module::MyClass = get_value()?.extract()?;`).
+- The binding generation is primarily designed to be used inside build scripts or via procedural macros. Therefore, the performance of the codegen process is [benchmarked](./pyo3_bindgen_engine/benches/bindgen.rs) to understand the potential impact on build times. Here are some preliminary results for version `0.3.0` with the default configuration (measured: parsing IO & codegen | not measured: compilation of the generated bindings, which takes much longer):
+ - `sys`: 1.24 ms (0.66k total LoC)
+ - `os`: 8.38 ms (3.88k total LoC)
+ - `numpy`: 1.02 s (294k total LoC)
+ - `torch`: 7.05 s (1.08M total LoC)
+- The generation of bindings should never panic as long as the target Python module can be successfully imported. If it does, please [report](https://github.com/AndrejOrsula/pyo3_bindgen/issues/new) this as a bug.
+- The generated bindings should always be compilable and usable in Rust. If you encounter any issues, consider manually fixing the problematic parts of the bindings and please [report](https://github.com/AndrejOrsula/pyo3_bindgen/issues/new) this as a bug.
+- However, the generated bindings are based on the introspection of the target Python module. Therefore, the correctness of the generated bindings is directly dependent on the quality of the type annotations and docstrings in the target Python module. Ideally, the generated bindings should be considered unsafe and serve as a starting point for safe and idiomatic Rust APIs.
+- Although implemented, the procedural macro does not work in many cases because PyO3 fails to import the target Python module when used from within a `proc_macro` crate. Therefore, it is recommended to use build scripts instead for now.
## License
diff --git a/pyo3_bindgen/src/lib.rs b/pyo3_bindgen/src/lib.rs
index 67ae92a..c337265 100644
--- a/pyo3_bindgen/src/lib.rs
+++ b/pyo3_bindgen/src/lib.rs
@@ -1,78 +1,8 @@
-//! Public API library for automatic generation of Rust FFI bindings to Python modules.
-//!
-//! ## Instructions
-//!
-//! Add `pyo3` as a dependency and `pyo3_bindgen` as a build dependency to your [`Cargo.toml`](https://doc.rust-lang.org/cargo/reference/manifest.html) manifest (`auto-initialize` feature of `pyo3` is optional and shown here for your convenience).
-//!
-//! ```toml
-//! [dependencies]
-//! pyo3 = { version = "0.20", features = ["auto-initialize"] }
-//!
-//! [build-dependencies]
-//! pyo3_bindgen = { version = "0.1" }
-//! ```
-//!
-//! ### Option 1: Build script
-//!
-//! Create a [`build.rs`](https://doc.rust-lang.org/cargo/reference/build-scripts.html) script in the root of your crate that generates bindings to the `target_module` Python module.
-//!
-//! ```rs
-//! // build.rs
-//!
-//! fn main() {
-//! // Generate Rust bindings to the Python module
-//! pyo3_bindgen::build_bindings(
-//! "target_module",
-//! std::path::Path::new(&std::env::var("OUT_DIR").unwrap()).join("bindings.rs"),
-//! )
-//! .unwrap();
-//! }
-//! ```
-//!
-//! Afterwards, include the generated bindings anywhere in your crate.
-//!
-//! ```rs
-//! include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
-//! pub use target_module::*;
-//! ```
-//!
-//! ### Option 2: CLI tool
-//!
-//! Install the `pyo3_bindgen` executable with `cargo`.
-//!
-//! ```bash
-//! cargo install --locked pyo3_bindgen_cli
-//! ```
-//!
-//! Afterwards, run the `pyo3_bindgen` executable while passing the name of the target Python module.
-//!
-//! ```bash
-//! # Pass `--help` to show the usage and available options
-//! pyo3_bindgen -m target_module -o bindings.rs
-//! ```
-//!
-//! ### Option 3 \[Experimental\]: Procedural macros
-//!
-//! > **Note:** This feature is experimental and will probably fail in many cases. It is recommended to use build scripts instead.
-//!
-//! Enable the `macros` feature of `pyo3_bindgen`.
-//!
-//! ```toml
-//! [build-dependencies]
-//! pyo3_bindgen = { version = "0.1", features = ["macros"] }
-//! ```
-//!
-//! Then, you can call the `import_python!` macro anywhere in your crate.
-//!
-//! ```rs
-//! pyo3_bindgen::import_python!("target_module");
-//! pub use target_module::*;
-//! ```
+#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../README.md"))]
-pub use pyo3_bindgen_engine::{
- self as engine, build_bindings, generate_bindings, generate_bindings_for_module,
- generate_bindings_from_str,
-};
+// Public API re-exports from engine
+pub use pyo3_bindgen_engine::{pyo3, Codegen, Config, PyBindgenError, PyBindgenResult};
+// Public API re-exports from macros
#[cfg(feature = "macros")]
-pub use pyo3_bindgen_macros::{self as macros, import_python};
+pub use pyo3_bindgen_macros::import_python;
diff --git a/pyo3_bindgen_cli/src/main.rs b/pyo3_bindgen_cli/src/main.rs
index 86e0306..ee7e8d1 100644
--- a/pyo3_bindgen_cli/src/main.rs
+++ b/pyo3_bindgen_cli/src/main.rs
@@ -1,19 +1,25 @@
//! CLI tool for automatic generation of Rust FFI bindings to Python modules.
use clap::Parser;
+use std::io::Write;
fn main() {
// Parse the CLI arguments
let args = Args::parse();
// Generate the bindings for the module specified by the `--module-name` argument
- let bindings = pyo3_bindgen::generate_bindings(&args.module_name).unwrap_or_else(|_| {
- panic!(
- "Failed to generate bindings for module: {}",
- args.module_name
- )
- });
-
+ let bindings = args
+ .module_names
+ .iter()
+ .fold(pyo3_bindgen::Codegen::default(), |codegen, module_name| {
+ codegen.module_name(module_name).unwrap_or_else(|err| {
+ panic!("Failed to parse the content of '{module_name}' Python module:\n{err}")
+ })
+ })
+ .generate()
+ .unwrap_or_else(|err| panic!("Failed to generate bindings for Python modules:\n{err}"));
+
+ // Format the bindings with prettyplease
let bindings = prettyplease::unparse(&syn::parse2(bindings).unwrap());
if let Some(output) = args.output {
@@ -27,7 +33,7 @@ fn main() {
.unwrap_or_else(|_| panic!("Failed to write to file: {}", output.display()));
} else {
// Otherwise, print the bindings to STDOUT
- println!("{bindings}");
+ std::io::stdout().write_all(bindings.as_bytes()).unwrap();
}
}
@@ -35,9 +41,9 @@ fn main() {
#[derive(Parser)]
#[command(author, version, about)]
struct Args {
- #[arg(short, long)]
+ #[arg(short='m', long="module-name", required=true, num_args=1..)]
/// Name of the Python module for which to generate the bindings
- pub module_name: String,
+ pub module_names: Vec,
#[arg(short, long)]
/// Name of the output file to which to write the bindings [default: STDOUT]
pub output: Option,
@@ -50,37 +56,49 @@ mod tests {
#[test]
fn test_parser_all() {
// Arrange
- let input = ["", "-m", "pip", "--output", "bindings.rs"];
+ let input = ["", "-m", "os", "--output", "bindings.rs"];
// Act
let args = Args::parse_from(input);
// Assert
- assert_eq!(args.module_name, "pip");
+ assert_eq!(args.module_names, ["os"]);
assert_eq!(args.output, Some("bindings.rs".into()));
}
#[test]
fn test_parser_short() {
// Arrange
- let input = ["", "-m", "numpy"];
+ let input = ["", "-m", "sys"];
// Act
let args = Args::parse_from(input);
// Assert
- assert_eq!(args.module_name, "numpy");
+ assert_eq!(args.module_names, ["sys"]);
}
#[test]
fn test_parser_long() {
// Arrange
- let input = ["", "--module-name", "setuptools"];
+ let input = ["", "--module-name", "io"];
+
+ // Act
+ let args = Args::parse_from(input);
+
+ // Assert
+ assert_eq!(args.module_names, ["io"]);
+ }
+
+ #[test]
+ fn test_parser_multiple() {
+ // Arrange
+ let input = ["", "-m", "os", "sys", "--module-name", "io"];
// Act
let args = Args::parse_from(input);
// Assert
- assert_eq!(args.module_name, "setuptools");
+ assert_eq!(args.module_names, ["os", "sys", "io"]);
}
}
diff --git a/pyo3_bindgen_cli/tests/cli.rs b/pyo3_bindgen_cli/tests/cli.rs
index 221034f..e0c64a8 100644
--- a/pyo3_bindgen_cli/tests/cli.rs
+++ b/pyo3_bindgen_cli/tests/cli.rs
@@ -17,7 +17,7 @@ mod test_cli {
assert.success().stdout(
predicate::str::contains(format!("Usage: {BIN_NAME}"))
.and(predicate::str::contains("Options:"))
- .and(predicate::str::contains("--module-name "))
+ .and(predicate::str::contains("--module-name "))
.and(predicate::str::contains("--output