mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-22 04:28:00 +00:00
Use scale-typegen as a backend for the codegen (#1260)
* integrate scale-typegen, remove types mod * reintroduce default substitutes and derives * support runtime_types only again * generating polkadot.rs ok * update scale-typegen to discrete error types * scale-typegen-api-changes * add note about UncheckedExtrinsic in default substitutes * add resursive attributes and derives * adjust example where Clone bound recursive * move scale-typegen dependency to workspace * expose default typegen settings * lightclient: Fix wasm socket closure called after being dropped (#1289) * lightclient: Close wasm socket while dropping from connecting state Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Construct one time only closures Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * testing: Enable console logs for lightclient WASM testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Separate wakes and check connectivity on poll_read Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Close the socket depending on internal state Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Revert "lightclient: Separate wakes and check connectivity on poll_read" This reverts commit 866094001d4c0b119a80ed681a74b323f74eae1b. * lightclient: Return pending if socket is opening from poll_read Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Close the socket on `poll_close` Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Reset closures on Drop to avoid recursive invokation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * lightclient: Close the socket if not already closing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * workflows: Install rustup component for building substrate (#1295) Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Command to fetch chainSpec and optimise its size (#1278) * cli: Add chainSpec command Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli/chainSpec: Move to dedicated module Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Compute the state root hash Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Remove code substitutes Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * artifacts: Update polkadot.json Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * scripts: Generate the chain spec Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Remove testing artifacts Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Fix clippy Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Apply rustfmt Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Introduce feature flag for smoldot dependency Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * cli: Rename chain-spec to chain-spec-pruning Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * scripts: Update chain-spec command Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * remove comments and unused args * Update substrate- and signer-related dependencies (#1297) * update crypto dependencies, adjust keypair * add scale_info::TypeInfo derive in some places * add multi signature derive * fix lock file * fix lock file again :| * adjust to new interface in scale-typegen * use released scale typegen * reintroduce type aliases * introduce type aliases again using scale-typegen * cargo fmt and clippy * reconcile changes with master branch * update polkadot.rs * bump scale-typgen to fix substitution * implemented Alex suggestions, regenerated polkadot.rs (did not change) * resolve conflicts in Cargo.lock * make expect messages more clear * correct typos --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> Co-authored-by: Alexandru Vasile <60601340+lexnv@users.noreply.github.com>
This commit is contained in:
Generated
+157
-195
@@ -52,19 +52,19 @@ version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
|
||||
dependencies = [
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
@@ -117,9 +117,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
|
||||
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@@ -146,9 +146,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -165,9 +165,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
|
||||
[[package]]
|
||||
name = "ark-bls12-377"
|
||||
@@ -344,7 +344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener 4.0.0",
|
||||
"event-listener 4.0.3",
|
||||
"event-listener-strategy",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
@@ -356,7 +356,7 @@ version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c"
|
||||
dependencies = [
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
@@ -370,25 +370,25 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd1f344136bad34df1f83a47f3fd7f2ab85d75cb8a940af4ccf6d482a84ea01b"
|
||||
dependencies = [
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.2.1"
|
||||
version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6d3b15875ba253d1110c740755e246537483f152fa334f91abd7fe84c88b3ff"
|
||||
checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7"
|
||||
dependencies = [
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix 0.38.26",
|
||||
"rustix 0.38.28",
|
||||
"slab",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -405,11 +405,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "3.2.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c"
|
||||
checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
|
||||
dependencies = [
|
||||
"event-listener 4.0.0",
|
||||
"event-listener 4.0.3",
|
||||
"event-listener-strategy",
|
||||
"pin-project-lite",
|
||||
]
|
||||
@@ -433,13 +433,13 @@ checksum = "15c1cd5d253ecac3d3cf15e390fd96bd92a13b1d14497d81abf077304794fb04"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-io",
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"async-signal",
|
||||
"blocking",
|
||||
"cfg-if",
|
||||
"event-listener 4.0.0",
|
||||
"event-listener 4.0.3",
|
||||
"futures-lite",
|
||||
"rustix 0.38.26",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@@ -455,7 +455,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 0.38.26",
|
||||
"rustix 0.38.28",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.48.0",
|
||||
@@ -463,15 +463,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.5.0"
|
||||
version = "4.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
|
||||
checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.74"
|
||||
version = "0.1.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
|
||||
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -518,7 +518,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object 0.32.1",
|
||||
"object 0.32.2",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
@@ -536,9 +536,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.5"
|
||||
version = "0.21.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
@@ -548,9 +548,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f2139706359229bfa8f19142ac1155b4b80beafb7a60471ac5dd109d4a19778"
|
||||
checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -692,7 +692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"async-task",
|
||||
"fastrand",
|
||||
"futures-io",
|
||||
@@ -847,9 +847,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.13"
|
||||
version = "4.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
|
||||
checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -857,9 +857,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.12"
|
||||
version = "4.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||
checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -947,9 +947,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.5"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
@@ -1002,9 +1002,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -1065,46 +1065,37 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.15"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset 0.9.0",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.8"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
|
||||
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.16"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
@@ -1301,12 +1292,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
@@ -1458,9 +1443,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "4.0.0"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "770d968249b5d99410d61f5bf89057f3199a077a04d087092f58e7d10692baae"
|
||||
checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
@@ -1473,15 +1458,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
|
||||
dependencies = [
|
||||
"event-listener 4.0.0",
|
||||
"event-listener 4.0.3",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd"
|
||||
checksum = "b6267a1fa6f59179ea4afc8e50fd8612a3cc60bc858f786ff877a4a8cb042799"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
@@ -1618,9 +1603,9 @@ checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aeee267a1883f7ebef3700f262d2d54de95dfaf38189015a74fdc4e0c7ad8143"
|
||||
checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
@@ -1721,9 +1706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -1872,7 +1857,7 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"ahash 0.8.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1881,7 +1866,7 @@ version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"ahash 0.8.7",
|
||||
"allocator-api2",
|
||||
"serde",
|
||||
]
|
||||
@@ -1955,11 +1940,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.5"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
|
||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1975,9 +1960,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
@@ -1998,9 +1983,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
version = "0.14.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
|
||||
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -2013,7 +1998,7 @@ dependencies = [
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2 0.4.10",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -2038,9 +2023,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.58"
|
||||
version = "0.1.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
|
||||
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
@@ -2224,9 +2209,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
@@ -2345,9 +2330,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
@@ -2460,9 +2445,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
|
||||
[[package]]
|
||||
name = "memfd"
|
||||
@@ -2470,7 +2455,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
|
||||
dependencies = [
|
||||
"rustix 0.38.26",
|
||||
"rustix 0.38.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2482,15 +2467,6 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memory-db"
|
||||
version = "0.32.0"
|
||||
@@ -2664,18 +2640,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
version = "0.32.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
@@ -2860,9 +2836,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "platforms"
|
||||
version = "3.2.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0"
|
||||
checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
@@ -2901,7 +2877,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"pin-project-lite",
|
||||
"rustix 0.38.26",
|
||||
"rustix 0.38.28",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -2923,16 +2899,6 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "primitive-types"
|
||||
version = "0.12.2"
|
||||
@@ -3082,7 +3048,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3125,18 +3091,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast"
|
||||
version = "1.0.20"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acde58d073e9c79da00f2b5b84eed919c8326832648a5b109b3fce1bb1175280"
|
||||
checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f"
|
||||
dependencies = [
|
||||
"ref-cast-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast-impl"
|
||||
version = "1.0.20"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925"
|
||||
checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3194,7 +3160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
@@ -3244,9 +3210,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.26"
|
||||
version = "0.38.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
|
||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
@@ -3257,9 +3223,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.9"
|
||||
version = "0.21.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9"
|
||||
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
@@ -3285,7 +3251,7 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3317,9 +3283,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
@@ -3423,6 +3389,19 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scale-typegen"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00860983481ac590ac87972062909bef0d6a658013b592ccc0f2feb272feab11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scale-info",
|
||||
"syn 2.0.48",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scale-value"
|
||||
version = "0.13.0"
|
||||
@@ -3445,11 +3424,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.22"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3458,7 +3437,7 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"ahash 0.8.7",
|
||||
"cfg-if",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
@@ -3586,9 +3565,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
||||
|
||||
[[package]]
|
||||
name = "send_wrapper"
|
||||
@@ -3613,9 +3592,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.12"
|
||||
version = "0.11.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff"
|
||||
checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3633,9 +3612,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
version = "1.0.111"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -3759,7 +3738,7 @@ dependencies = [
|
||||
"async-executor",
|
||||
"async-fs",
|
||||
"async-io",
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"async-net",
|
||||
"async-process",
|
||||
"blocking",
|
||||
@@ -3773,9 +3752,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d1eaa97d77be4d026a1e7ffad1bb3b78448763b357ea6f8188d3e6f736a9b9"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.4",
|
||||
"async-lock 3.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"atomic-take",
|
||||
"base64 0.21.5",
|
||||
"base64 0.21.6",
|
||||
"bip39",
|
||||
"blake2-rfc",
|
||||
"bs58",
|
||||
@@ -3784,7 +3763,7 @@ dependencies = [
|
||||
"derive_more",
|
||||
"ed25519-zebra 4.0.3",
|
||||
"either",
|
||||
"event-listener 4.0.0",
|
||||
"event-listener 4.0.3",
|
||||
"fnv",
|
||||
"futures-lite",
|
||||
"futures-util",
|
||||
@@ -3828,12 +3807,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-lock 3.2.0",
|
||||
"base64 0.21.5",
|
||||
"async-lock 3.3.0",
|
||||
"base64 0.21.6",
|
||||
"blake2-rfc",
|
||||
"derive_more",
|
||||
"either",
|
||||
"event-listener 4.0.0",
|
||||
"event-listener 4.0.3",
|
||||
"fnv",
|
||||
"futures-channel",
|
||||
"futures-lite",
|
||||
@@ -3857,16 +3836,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.5"
|
||||
@@ -4183,7 +4152,7 @@ version = "27.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9c4bf89a5bd74f696cd1f23d83bb6abe6bd0abad1f3c70d4b0d7ebec4098cfe"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"ahash 0.8.7",
|
||||
"hash-db",
|
||||
"hashbrown 0.13.2",
|
||||
"lazy_static",
|
||||
@@ -4250,9 +4219,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ss58-registry"
|
||||
version = "1.44.0"
|
||||
version = "1.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35935738370302d5e33963665b77541e4b990a3e919ec904c837a56cfc891de1"
|
||||
checksum = "3c0c74081753a8ce1c8eb10b9f262ab6f7017e5ad3317c17a54c7ab65fcb3c6e"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"num-format",
|
||||
@@ -4339,7 +4308,7 @@ dependencies = [
|
||||
"either",
|
||||
"frame-metadata 16.0.0",
|
||||
"futures",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"hex",
|
||||
"impl-serde",
|
||||
"jsonrpsee",
|
||||
@@ -4372,7 +4341,7 @@ dependencies = [
|
||||
name = "subxt-cli"
|
||||
version = "0.33.0"
|
||||
dependencies = [
|
||||
"clap 4.4.13",
|
||||
"clap 4.4.14",
|
||||
"color-eyre",
|
||||
"frame-metadata 16.0.0",
|
||||
"hex",
|
||||
@@ -4395,17 +4364,16 @@ dependencies = [
|
||||
name = "subxt-codegen"
|
||||
version = "0.33.0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"frame-metadata 16.0.0",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"heck",
|
||||
"hex",
|
||||
"jsonrpsee",
|
||||
"parity-scale-codec",
|
||||
"pretty_assertions",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scale-info",
|
||||
"scale-typegen",
|
||||
"subxt-metadata",
|
||||
"syn 2.0.48",
|
||||
"thiserror",
|
||||
@@ -4420,7 +4388,7 @@ dependencies = [
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"futures-util",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"instant",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
@@ -4468,7 +4436,7 @@ name = "subxt-signer"
|
||||
version = "0.33.0"
|
||||
dependencies = [
|
||||
"bip39",
|
||||
"getrandom 0.2.11",
|
||||
"getrandom 0.2.12",
|
||||
"hex",
|
||||
"hmac 0.12.1",
|
||||
"parity-scale-codec",
|
||||
@@ -4516,9 +4484,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.12"
|
||||
version = "0.12.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
|
||||
checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae"
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
@@ -4552,18 +4520,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.53"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09"
|
||||
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.53"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19"
|
||||
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4617,7 +4585,7 @@ dependencies = [
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.5",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
@@ -4859,15 +4827,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.86"
|
||||
version = "1.0.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8419ecd263363827c5730386f418715766f584e2f874d32c23c5b00bd9727e7e"
|
||||
checksum = "76de4f783e610194f6c98bfd53f9fc52bb2e0d02c947621e8a0f4ecc799b2880"
|
||||
dependencies = [
|
||||
"basic-toml",
|
||||
"glob 0.3.1",
|
||||
@@ -4924,9 +4892,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.13"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@@ -5298,7 +5266,7 @@ dependencies = [
|
||||
"log",
|
||||
"mach",
|
||||
"memfd",
|
||||
"memoffset 0.8.0",
|
||||
"memoffset",
|
||||
"paste",
|
||||
"rand 0.8.5",
|
||||
"rustix 0.36.17",
|
||||
@@ -5339,7 +5307,7 @@ dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.26",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -5376,11 +5344,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5583,9 +5551,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.25"
|
||||
version = "0.5.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e87b8dfbe3baffbe687eef2e164e32286eff31a5ee16463ce03d991643ec94"
|
||||
checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -5611,12 +5579,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "yap"
|
||||
version = "0.11.0"
|
||||
|
||||
+3
-7
@@ -17,13 +17,7 @@ members = [
|
||||
# We exclude any crates that would depend on non mutually
|
||||
# exclusive feature flags and thus can't compile with the
|
||||
# workspace:
|
||||
exclude = [
|
||||
"testing/wasm-rpc-tests",
|
||||
"testing/wasm-lightclient-tests",
|
||||
"signer/wasm-tests",
|
||||
"examples/wasm-example",
|
||||
"examples/parachain-example"
|
||||
]
|
||||
exclude = ["testing/wasm-rpc-tests", "testing/wasm-lightclient-tests", "signer/wasm-tests", "examples/wasm-example", "examples/parachain-example"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
@@ -100,6 +94,8 @@ url = "2.5.0"
|
||||
wabt = "0.10.0"
|
||||
wasm-bindgen-test = "0.3.24"
|
||||
which = "5.0.0"
|
||||
scale-typegen-description = "0.1.0"
|
||||
scale-typegen = "0.1.1"
|
||||
|
||||
# Light client support:
|
||||
smoldot = { version = "0.16.0", default-features = false }
|
||||
|
||||
@@ -173,7 +173,8 @@ fn codegen(
|
||||
.map_err(|e| eyre!("Cannot parse derive for type {ty_str}: {e}"))?;
|
||||
let derive = syn::parse_str(&derive)
|
||||
.map_err(|e| eyre!("Cannot parse derive for type {ty_str}: {e}"))?;
|
||||
codegen.add_derives_for_type(ty, std::iter::once(derive));
|
||||
// Note: recursive derives and attributes not supported in the CLI => recursive: false
|
||||
codegen.add_derives_for_type(ty, std::iter::once(derive), false);
|
||||
}
|
||||
|
||||
// Configure attribtues:
|
||||
@@ -190,7 +191,8 @@ fn codegen(
|
||||
.map_err(|e| eyre!("Cannot parse attribute for type {ty_str}: {e}"))?;
|
||||
let attribute: OuterAttribute = syn::parse_str(&attr)
|
||||
.map_err(|e| eyre!("Cannot parse attribute for type {ty_str}: {e}"))?;
|
||||
codegen.add_attributes_for_type(ty, std::iter::once(attribute.0));
|
||||
// Note: recursive derives and attributes not supported in the CLI => recursive: false
|
||||
codegen.add_attributes_for_type(ty, std::iter::once(attribute.0), false);
|
||||
}
|
||||
|
||||
// Insert type substitutions:
|
||||
|
||||
+10
-10
@@ -228,11 +228,11 @@ impl StorageEntryDiff {
|
||||
let value_1_ty_id = storage_entry_1.entry_type().value_ty();
|
||||
let value_1_hash = metadata_1
|
||||
.type_hash(value_1_ty_id)
|
||||
.expect("type should be present");
|
||||
.expect("type is in metadata; qed");
|
||||
let value_2_ty_id = storage_entry_2.entry_type().value_ty();
|
||||
let value_2_hash = metadata_1
|
||||
.type_hash(value_2_ty_id)
|
||||
.expect("type should be present");
|
||||
.expect("type is in metadata; qed");
|
||||
let value_different = value_1_hash != value_2_hash;
|
||||
|
||||
let key_1_hash = storage_entry_1
|
||||
@@ -241,7 +241,7 @@ impl StorageEntryDiff {
|
||||
.map(|key_ty| {
|
||||
metadata_1
|
||||
.type_hash(key_ty)
|
||||
.expect("type should be present")
|
||||
.expect("type is in metadata; qed")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let key_2_hash = storage_entry_2
|
||||
@@ -250,7 +250,7 @@ impl StorageEntryDiff {
|
||||
.map(|key_ty| {
|
||||
metadata_2
|
||||
.type_hash(key_ty)
|
||||
.expect("type should be present")
|
||||
.expect("type is in metadata; qed")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let key_different = key_1_hash != key_2_hash;
|
||||
@@ -309,12 +309,12 @@ fn storage_differences<'a>(
|
||||
|e| {
|
||||
pallet_metadata_1
|
||||
.storage_hash(e.name())
|
||||
.expect("storage entry should be present")
|
||||
.expect("storage entry is in metadata; qed")
|
||||
},
|
||||
|e| {
|
||||
pallet_metadata_2
|
||||
.storage_hash(e.name())
|
||||
.expect("storage entry should be present")
|
||||
.expect("storage entry is in metadata; qed")
|
||||
},
|
||||
|e| e.name(),
|
||||
)
|
||||
@@ -330,12 +330,12 @@ fn calls_differences<'a>(
|
||||
|e| {
|
||||
pallet_metadata_1
|
||||
.call_hash(&e.name)
|
||||
.expect("call should be present")
|
||||
.expect("call is in metadata; qed")
|
||||
},
|
||||
|e| {
|
||||
pallet_metadata_2
|
||||
.call_hash(&e.name)
|
||||
.expect("call should be present")
|
||||
.expect("call is in metadata; qed")
|
||||
},
|
||||
|e| &e.name,
|
||||
);
|
||||
@@ -351,12 +351,12 @@ fn constants_differences<'a>(
|
||||
|e| {
|
||||
pallet_metadata_1
|
||||
.constant_hash(e.name())
|
||||
.expect("constant should be present")
|
||||
.expect("constant is in metadata; qed")
|
||||
},
|
||||
|e| {
|
||||
pallet_metadata_2
|
||||
.constant_hash(e.name())
|
||||
.expect("constant should be present")
|
||||
.expect("constant is in metadata; qed")
|
||||
},
|
||||
|e| e.name(),
|
||||
)
|
||||
|
||||
@@ -142,7 +142,7 @@ pub async fn run(opts: Opts, output: &mut impl std::io::Write) -> color_eyre::Re
|
||||
explore_constants(command, &metadata, pallet_metadata, output)
|
||||
}
|
||||
PalletSubcommand::Storage(command) => {
|
||||
// if the metadata came from some url, we use that same url to make storage calls against.
|
||||
// if the metadata is in some url, we use that same url to make storage calls against.
|
||||
let node_url = opts.file_or_url.url.map(|url| url.to_string());
|
||||
explore_storage(command, &metadata, pallet_metadata, node_url, output).await
|
||||
}
|
||||
|
||||
+1
-3
@@ -31,12 +31,10 @@ jsonrpsee = { workspace = true, features = ["async-client", "client-ws-transport
|
||||
hex = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
||||
thiserror = { workspace = true }
|
||||
scale-typegen = { workspace = true }
|
||||
|
||||
# Included if "web" feature is enabled, to enable its js feature.
|
||||
getrandom = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bitvec = { workspace = true }
|
||||
scale-info = { workspace = true, features = ["bit-vec"] }
|
||||
pretty_assertions = { workspace = true }
|
||||
frame-metadata = { workspace = true }
|
||||
|
||||
+31
-45
@@ -3,10 +3,10 @@
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::CodegenError;
|
||||
use crate::types::{CompositeDefFields, TypeGenerator};
|
||||
use heck::{ToSnakeCase as _, ToUpperCamelCase as _};
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use scale_typegen::{typegen::ir::type_ir::CompositeIRKind, TypeGenerator};
|
||||
use subxt_metadata::PalletMetadata;
|
||||
|
||||
/// Generate calls from the provided pallet's metadata. Each call returns a `StaticTxPayload`
|
||||
@@ -14,81 +14,69 @@ use subxt_metadata::PalletMetadata;
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `metadata` - Runtime metadata from which the calls are generated.
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata.
|
||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||
/// - `pallet` - Pallet metadata from which the calls are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
||||
pub fn generate_calls(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
// Early return if the pallet has no calls.
|
||||
let Some(call_ty) = pallet.call_ty_id() else {
|
||||
return Ok(quote!());
|
||||
};
|
||||
|
||||
let mut struct_defs = super::generate_structs_from_variants(
|
||||
let variant_names_and_struct_defs = super::generate_structs_from_variants(
|
||||
type_gen,
|
||||
types_mod_ident,
|
||||
call_ty,
|
||||
|name| name.to_upper_camel_case().into(),
|
||||
"Call",
|
||||
crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
|
||||
let result = struct_defs
|
||||
.iter_mut()
|
||||
.map(|(variant_name, struct_def, aliases)| {
|
||||
let fn_name = format_ident!("{}", variant_name.to_snake_case());
|
||||
|
||||
let result: Vec<_> = match struct_def.fields {
|
||||
CompositeDefFields::Named(ref named_fields) => named_fields
|
||||
let (call_structs, call_fns): (Vec<_>, Vec<_>) = variant_names_and_struct_defs
|
||||
.into_iter()
|
||||
.map(|var| {
|
||||
let (call_fn_args, call_args): (Vec<_>, Vec<_>) = match &var.composite.kind {
|
||||
CompositeIRKind::Named(named_fields) => named_fields
|
||||
.iter()
|
||||
.map(|(name, field)| {
|
||||
let call_arg = if field.is_boxed() {
|
||||
// Note: fn_arg_type this is relative the type path of the type alias when prefixed with `types::`, e.g. `set_max_code_size::New`
|
||||
let fn_arg_type = &field.type_path;
|
||||
let call_arg = if field.is_boxed {
|
||||
quote! { #name: ::std::boxed::Box::new(#name) }
|
||||
} else {
|
||||
quote! { #name }
|
||||
};
|
||||
|
||||
let alias_name =
|
||||
format_ident!("{}", name.to_string().to_upper_camel_case());
|
||||
|
||||
(quote!( #name: types::#fn_name::#alias_name ), call_arg)
|
||||
(quote!( #name: types::#fn_arg_type ), call_arg)
|
||||
})
|
||||
.collect(),
|
||||
CompositeDefFields::NoFields => Default::default(),
|
||||
CompositeDefFields::Unnamed(_) => {
|
||||
.unzip(),
|
||||
CompositeIRKind::NoFields => Default::default(),
|
||||
CompositeIRKind::Unnamed(_) => {
|
||||
return Err(CodegenError::InvalidCallVariant(call_ty))
|
||||
}
|
||||
};
|
||||
|
||||
let call_fn_args = result.iter().map(|(call_fn_arg, _)| call_fn_arg);
|
||||
let call_args = result.iter().map(|(_, call_arg)| call_arg);
|
||||
|
||||
let pallet_name = pallet.name();
|
||||
let call_name = &variant_name;
|
||||
let struct_name = &struct_def.name;
|
||||
let call_name = &var.variant_name;
|
||||
let struct_name = &var.composite.name;
|
||||
let Some(call_hash) = pallet.call_hash(call_name) else {
|
||||
return Err(CodegenError::MissingCallMetadata(
|
||||
pallet_name.into(),
|
||||
call_name.to_string(),
|
||||
));
|
||||
};
|
||||
|
||||
let fn_name = format_ident!("{}", var.variant_name.to_snake_case());
|
||||
// Propagate the documentation just to `TransactionApi` methods, while
|
||||
// draining the documentation of inner call structures.
|
||||
let docs = should_gen_docs.then_some(struct_def.docs.take()).flatten();
|
||||
let docs = &var.composite.docs;
|
||||
|
||||
// this converts the composite into a full struct type. No Type Parameters needed here.
|
||||
let struct_def = type_gen.upcast_composite(&var.composite);
|
||||
let alias_mod = var.type_alias_mod;
|
||||
// The call structure's documentation was stripped above.
|
||||
let call_struct = quote! {
|
||||
#struct_def
|
||||
|
||||
#aliases
|
||||
#alias_mod
|
||||
|
||||
impl #crate_path::blocks::StaticExtrinsic for #struct_name {
|
||||
const PALLET: &'static str = #pallet_name;
|
||||
@@ -113,17 +101,15 @@ pub fn generate_calls(
|
||||
|
||||
Ok((call_struct, client_fn))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.unzip();
|
||||
|
||||
let call_structs = result.iter().map(|(call_struct, _)| call_struct);
|
||||
let call_fns = result.iter().map(|(_, client_fn)| client_fn);
|
||||
let call_type = type_gen.resolve_type_path(call_ty)?;
|
||||
let call_ty = type_gen.resolve_type(call_ty)?;
|
||||
let docs = type_gen.docs_from_scale_info(&call_ty.docs);
|
||||
|
||||
let call_type = type_gen.resolve_type_path(call_ty);
|
||||
let call_ty = type_gen.resolve_type(call_ty);
|
||||
let docs = &call_ty.docs;
|
||||
let docs = should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
|
||||
Ok(quote! {
|
||||
#docs
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::types::TypeGenerator;
|
||||
use heck::ToSnakeCase as _;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use scale_typegen::TypeGenerator;
|
||||
use subxt_metadata::PalletMetadata;
|
||||
|
||||
use super::CodegenError;
|
||||
@@ -29,16 +29,13 @@ use super::CodegenError;
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `metadata` - Runtime metadata from which the calls are generated.
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata
|
||||
/// - `pallet` - Pallet metadata from which the calls are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||
/// - `pallet` - Pallet metadata from which the constants are generated.
|
||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
||||
pub fn generate_constants(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
// Early return if the pallet has no constants.
|
||||
if pallet.constants().len() == 0 {
|
||||
@@ -58,9 +55,11 @@ pub fn generate_constants(
|
||||
));
|
||||
};
|
||||
|
||||
let return_ty = type_gen.resolve_type_path(constant.ty());
|
||||
let return_ty = type_gen.resolve_type_path(constant.ty())?;
|
||||
let docs = constant.docs();
|
||||
let docs = should_gen_docs
|
||||
let docs = type_gen
|
||||
.settings()
|
||||
.should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -77,6 +76,8 @@ pub fn generate_constants(
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
|
||||
Ok(quote! {
|
||||
pub mod constants {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::types::TypeGenerator;
|
||||
use heck::ToSnakeCase as _;
|
||||
use scale_typegen::TypeGenerator;
|
||||
use std::collections::HashSet;
|
||||
use subxt_metadata::{CustomValueMetadata, Metadata};
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
@@ -60,6 +59,7 @@ fn generate_custom_value_fn(
|
||||
let (return_ty, decodable) = if type_is_valid {
|
||||
let return_ty = type_gen
|
||||
.resolve_type_path(custom_value.type_id())
|
||||
.expect("type is in metadata; qed")
|
||||
.to_token_stream();
|
||||
let decodable = quote!(#crate_path::custom_values::Yes);
|
||||
(return_ty, decodable)
|
||||
|
||||
@@ -4,26 +4,26 @@
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use scale_typegen::TypeGenerator;
|
||||
use subxt_metadata::PalletMetadata;
|
||||
|
||||
use crate::types::TypeGenerator;
|
||||
|
||||
use super::CodegenError;
|
||||
|
||||
/// Generate error type alias from the provided pallet metadata.
|
||||
pub fn generate_error_type_alias(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
let Some(error_ty) = pallet.error_ty_id() else {
|
||||
return Ok(quote!());
|
||||
};
|
||||
|
||||
let error_type = type_gen.resolve_type_path(error_ty);
|
||||
let error_ty = type_gen.resolve_type(error_ty);
|
||||
let error_type = type_gen.resolve_type_path(error_ty)?;
|
||||
let error_ty = type_gen.resolve_type(error_ty)?;
|
||||
let docs = &error_ty.docs;
|
||||
let docs = should_gen_docs
|
||||
let docs = type_gen
|
||||
.settings()
|
||||
.should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
Ok(quote! {
|
||||
|
||||
+26
-33
@@ -2,9 +2,9 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::types::TypeGenerator;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use scale_typegen::TypeGenerator;
|
||||
use subxt_metadata::PalletMetadata;
|
||||
|
||||
use super::CodegenError;
|
||||
@@ -35,55 +35,48 @@ use super::CodegenError;
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata.
|
||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||
/// - `pallet` - Pallet metadata from which the events are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
||||
pub fn generate_events(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
// Early return if the pallet has no events.
|
||||
let Some(event_ty) = pallet.event_ty_id() else {
|
||||
return Ok(quote!());
|
||||
};
|
||||
|
||||
let struct_defs = super::generate_structs_from_variants(
|
||||
type_gen,
|
||||
types_mod_ident,
|
||||
event_ty,
|
||||
|name| name.into(),
|
||||
"Event",
|
||||
crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
let variant_names_and_struct_defs =
|
||||
super::generate_structs_from_variants(type_gen, event_ty, |name| name.into(), "Event")?;
|
||||
|
||||
let event_structs = struct_defs
|
||||
.iter()
|
||||
.map(|(variant_name, struct_def, aliases)| {
|
||||
let pallet_name = pallet.name();
|
||||
let event_struct = &struct_def.name;
|
||||
let event_name = variant_name;
|
||||
let event_structs = variant_names_and_struct_defs.into_iter().map(|var| {
|
||||
let pallet_name = pallet.name();
|
||||
let event_struct_name = &var.composite.name;
|
||||
let event_name = var.variant_name;
|
||||
let alias_mod = var.type_alias_mod;
|
||||
let struct_def = type_gen.upcast_composite(&var.composite);
|
||||
quote! {
|
||||
#struct_def
|
||||
#alias_mod
|
||||
|
||||
quote! {
|
||||
#struct_def
|
||||
|
||||
#aliases
|
||||
|
||||
impl #crate_path::events::StaticEvent for #event_struct {
|
||||
const PALLET: &'static str = #pallet_name;
|
||||
const EVENT: &'static str = #event_name;
|
||||
}
|
||||
impl #crate_path::events::StaticEvent for #event_struct_name {
|
||||
const PALLET: &'static str = #pallet_name;
|
||||
const EVENT: &'static str = #event_name;
|
||||
}
|
||||
});
|
||||
let event_type = type_gen.resolve_type_path(event_ty);
|
||||
let event_ty = type_gen.resolve_type(event_ty);
|
||||
}
|
||||
});
|
||||
|
||||
let event_type = type_gen.resolve_type_path(event_ty)?;
|
||||
let event_ty = type_gen.resolve_type(event_ty)?;
|
||||
let docs = &event_ty.docs;
|
||||
let docs = should_gen_docs
|
||||
let docs = type_gen
|
||||
.settings()
|
||||
.should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
|
||||
Ok(quote! {
|
||||
#docs
|
||||
|
||||
+111
-140
@@ -12,20 +12,20 @@ mod events;
|
||||
mod runtime_apis;
|
||||
mod storage;
|
||||
|
||||
use scale_typegen::typegen::ir::type_ir::{CompositeFieldIR, CompositeIR, CompositeIRKind};
|
||||
use scale_typegen::typegen::type_params::TypeParameters;
|
||||
use scale_typegen::typegen::type_path::TypePath;
|
||||
use scale_typegen::TypeGenerator;
|
||||
use subxt_metadata::Metadata;
|
||||
use syn::{parse_quote, Ident};
|
||||
|
||||
use crate::api::custom_values::generate_custom_values;
|
||||
use crate::error::CodegenError;
|
||||
use crate::types::DerivesRegistry;
|
||||
use crate::{
|
||||
ir,
|
||||
types::{CompositeDef, CompositeDefFields, TypeGenerator, TypeSubstitutes},
|
||||
};
|
||||
use crate::subxt_type_gen_settings;
|
||||
use crate::{api::custom_values::generate_custom_values, ir};
|
||||
|
||||
use heck::ToSnakeCase as _;
|
||||
use heck::{ToSnakeCase as _, ToUpperCamelCase};
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::parse_quote;
|
||||
|
||||
/// Create the API for interacting with a Substrate runtime.
|
||||
pub struct RuntimeGenerator {
|
||||
@@ -60,27 +60,22 @@ impl RuntimeGenerator {
|
||||
pub fn generate_runtime_types(
|
||||
&self,
|
||||
item_mod: syn::ItemMod,
|
||||
derives: DerivesRegistry,
|
||||
type_substitutes: TypeSubstitutes,
|
||||
derives: scale_typegen::DerivesRegistry,
|
||||
type_substitutes: scale_typegen::TypeSubstitutes,
|
||||
crate_path: syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
let item_mod_attrs = item_mod.attrs.clone();
|
||||
|
||||
let item_mod_ir = ir::ItemMod::try_from(item_mod)?;
|
||||
|
||||
let settings =
|
||||
subxt_type_gen_settings(derives, type_substitutes, &crate_path, should_gen_docs);
|
||||
|
||||
let type_gen = TypeGenerator::new(self.metadata.types(), &settings);
|
||||
let types_mod = type_gen.generate_types_mod()?;
|
||||
let mod_ident = &item_mod_ir.ident;
|
||||
let rust_items = item_mod_ir.rust_items();
|
||||
|
||||
let type_gen = TypeGenerator::new(
|
||||
self.metadata.types(),
|
||||
"runtime_types",
|
||||
type_substitutes,
|
||||
derives,
|
||||
crate_path,
|
||||
should_gen_docs,
|
||||
);
|
||||
let types_mod = type_gen.generate_types_mod()?;
|
||||
|
||||
Ok(quote! {
|
||||
#( #item_mod_attrs )*
|
||||
#[allow(dead_code, unused_imports, non_camel_case_types)]
|
||||
@@ -114,24 +109,20 @@ impl RuntimeGenerator {
|
||||
pub fn generate_runtime(
|
||||
&self,
|
||||
item_mod: syn::ItemMod,
|
||||
derives: DerivesRegistry,
|
||||
type_substitutes: TypeSubstitutes,
|
||||
derives: scale_typegen::DerivesRegistry,
|
||||
type_substitutes: scale_typegen::TypeSubstitutes,
|
||||
crate_path: syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
let item_mod_attrs = item_mod.attrs.clone();
|
||||
let item_mod_ir = ir::ItemMod::try_from(item_mod)?;
|
||||
|
||||
let type_gen = TypeGenerator::new(
|
||||
self.metadata.types(),
|
||||
"runtime_types",
|
||||
type_substitutes,
|
||||
derives,
|
||||
crate_path.clone(),
|
||||
should_gen_docs,
|
||||
);
|
||||
let settings =
|
||||
subxt_type_gen_settings(derives, type_substitutes, &crate_path, should_gen_docs);
|
||||
|
||||
let type_gen = TypeGenerator::new(self.metadata.types(), &settings);
|
||||
let types_mod = type_gen.generate_types_mod()?;
|
||||
let types_mod_ident = types_mod.ident();
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
let pallets_with_mod_names = self
|
||||
.metadata
|
||||
.pallets()
|
||||
@@ -165,39 +156,15 @@ impl RuntimeGenerator {
|
||||
let modules = pallets_with_mod_names
|
||||
.iter()
|
||||
.map(|(pallet, mod_name)| {
|
||||
let calls = calls::generate_calls(
|
||||
&type_gen,
|
||||
pallet,
|
||||
types_mod_ident,
|
||||
&crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
let calls = calls::generate_calls(&type_gen, pallet, &crate_path)?;
|
||||
|
||||
let event = events::generate_events(
|
||||
&type_gen,
|
||||
pallet,
|
||||
types_mod_ident,
|
||||
&crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
let event = events::generate_events(&type_gen, pallet, &crate_path)?;
|
||||
|
||||
let storage_mod = storage::generate_storage(
|
||||
&type_gen,
|
||||
pallet,
|
||||
types_mod_ident,
|
||||
&crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
let storage_mod = storage::generate_storage(&type_gen, pallet, &crate_path)?;
|
||||
|
||||
let constants_mod = constants::generate_constants(
|
||||
&type_gen,
|
||||
pallet,
|
||||
types_mod_ident,
|
||||
&crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
let constants_mod = constants::generate_constants(&type_gen, pallet, &crate_path)?;
|
||||
|
||||
let errors = errors::generate_error_type_alias(&type_gen, pallet, should_gen_docs)?;
|
||||
let errors = errors::generate_error_type_alias(&type_gen, pallet)?;
|
||||
|
||||
Ok(quote! {
|
||||
pub mod #mod_name {
|
||||
@@ -242,14 +209,14 @@ impl RuntimeGenerator {
|
||||
&type_gen,
|
||||
types_mod_ident,
|
||||
&crate_path,
|
||||
should_gen_docs,
|
||||
)?;
|
||||
|
||||
// Fetch the paths of the outer enums.
|
||||
// Substrate exposes those under `kitchensink_runtime`, while Polkadot under `polkadot_runtime`.
|
||||
let call_path = type_gen.resolve_type_path(self.metadata.outer_enums().call_enum_ty());
|
||||
let event_path = type_gen.resolve_type_path(self.metadata.outer_enums().event_enum_ty());
|
||||
let error_path = type_gen.resolve_type_path(self.metadata.outer_enums().error_enum_ty());
|
||||
|
||||
let call_path = type_gen.resolve_type_path(self.metadata.outer_enums().call_enum_ty())?;
|
||||
let event_path = type_gen.resolve_type_path(self.metadata.outer_enums().event_enum_ty())?;
|
||||
let error_path = type_gen.resolve_type_path(self.metadata.outer_enums().error_enum_ty())?;
|
||||
|
||||
let custom_values = generate_custom_values(&self.metadata, &type_gen, &crate_path);
|
||||
|
||||
@@ -358,17 +325,14 @@ impl RuntimeGenerator {
|
||||
/// Return a vector of tuples of variant names and corresponding struct definitions.
|
||||
pub fn generate_structs_from_variants<F>(
|
||||
type_gen: &TypeGenerator,
|
||||
types_mod_ident: &syn::Ident,
|
||||
type_id: u32,
|
||||
variant_to_struct_name: F,
|
||||
error_message_type_name: &str,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<Vec<(String, CompositeDef, TypeAliases)>, CodegenError>
|
||||
) -> Result<Vec<StructFromVariant>, CodegenError>
|
||||
where
|
||||
F: Fn(&str) -> std::borrow::Cow<str>,
|
||||
{
|
||||
let ty = type_gen.resolve_type(type_id);
|
||||
let ty = type_gen.resolve_type(type_id)?;
|
||||
|
||||
let scale_info::TypeDef::Variant(variant) = &ty.type_def else {
|
||||
return Err(CodegenError::InvalidType(error_message_type_name.into()));
|
||||
@@ -378,84 +342,91 @@ where
|
||||
.variants
|
||||
.iter()
|
||||
.map(|var| {
|
||||
let mut type_params = TypeParameters::from_scale_info(&[]);
|
||||
let composite_ir_kind =
|
||||
type_gen.create_composite_ir_kind(&var.fields, &mut type_params)?;
|
||||
let struct_name = variant_to_struct_name(&var.name);
|
||||
let mut composite = CompositeIR::new(
|
||||
syn::parse_str(&struct_name).expect("enum variant is a valid ident; qed"),
|
||||
composite_ir_kind,
|
||||
type_gen.docs_from_scale_info(&var.docs),
|
||||
);
|
||||
|
||||
let fields = CompositeDefFields::from_scale_info_fields(
|
||||
struct_name.as_ref(),
|
||||
&var.fields,
|
||||
&[],
|
||||
type_gen,
|
||||
)?;
|
||||
|
||||
let alias_module_name = format_ident!("{}", var.name.to_snake_case());
|
||||
|
||||
let docs = should_gen_docs.then_some(&*var.docs).unwrap_or_default();
|
||||
let struct_def = CompositeDef::struct_def(
|
||||
&ty,
|
||||
struct_name.as_ref(),
|
||||
Default::default(),
|
||||
fields.clone(),
|
||||
Some(parse_quote!(pub)),
|
||||
type_gen,
|
||||
docs,
|
||||
crate_path,
|
||||
Some(alias_module_name.clone()),
|
||||
)?;
|
||||
|
||||
let type_aliases = TypeAliases::new(fields, types_mod_ident.clone(), alias_module_name);
|
||||
|
||||
Ok((var.name.to_string(), struct_def, type_aliases))
|
||||
let type_alias_mod = generate_type_alias_mod(&mut composite, type_gen);
|
||||
Ok(StructFromVariant {
|
||||
variant_name: var.name.to_string(),
|
||||
composite,
|
||||
type_alias_mod,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Generate the type aliases from a set of enum / struct definitions.
|
||||
pub struct StructFromVariant {
|
||||
variant_name: String,
|
||||
composite: CompositeIR,
|
||||
type_alias_mod: TokenStream2,
|
||||
}
|
||||
|
||||
/// Modifies the composite, by replacing its types with references to the generated type alias module.
|
||||
/// Returns the TokenStream of the type alias module.
|
||||
///
|
||||
/// The type aliases are used to make the generated code more readable.
|
||||
#[derive(Debug)]
|
||||
pub struct TypeAliases {
|
||||
fields: CompositeDefFields,
|
||||
types_mod_ident: syn::Ident,
|
||||
mod_name: syn::Ident,
|
||||
}
|
||||
/// E.g a struct like this:
|
||||
/// ```ignore
|
||||
/// pub struct SetMaxCodeSize {
|
||||
/// pub new: ::core::primitive::u32,
|
||||
/// }
|
||||
/// ```
|
||||
/// will be made into this:
|
||||
/// ```ignore
|
||||
/// pub struct SetMaxCodeSize {
|
||||
/// pub new: set_max_code_size::New,
|
||||
/// }
|
||||
/// ```
|
||||
/// And the type alias module will look like this:
|
||||
/// ```ignore
|
||||
/// pub mod set_max_code_size {
|
||||
/// use super::runtime_types;
|
||||
/// pub type New = ::core::primitive::u32;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn generate_type_alias_mod(
|
||||
composite: &mut CompositeIR,
|
||||
type_gen: &TypeGenerator,
|
||||
) -> TokenStream2 {
|
||||
let mut aliases: Vec<TokenStream2> = vec![];
|
||||
let alias_mod_name: Ident = syn::parse_str(&composite.name.to_string().to_snake_case())
|
||||
.expect("composite name in snake_case should be a valid identifier");
|
||||
|
||||
impl TypeAliases {
|
||||
pub fn new(
|
||||
fields: CompositeDefFields,
|
||||
types_mod_ident: syn::Ident,
|
||||
mod_name: syn::Ident,
|
||||
) -> Self {
|
||||
TypeAliases {
|
||||
fields,
|
||||
types_mod_ident,
|
||||
mod_name,
|
||||
let mut modify_field_to_be_type_alias = |field: &mut CompositeFieldIR, alias_name: Ident| {
|
||||
let type_path = &field.type_path;
|
||||
aliases.push(quote!(pub type #alias_name = #type_path;));
|
||||
|
||||
let type_alias_path: syn::Path = parse_quote!(#alias_mod_name::#alias_name);
|
||||
field.type_path = TypePath::from_syn_path(type_alias_path);
|
||||
};
|
||||
|
||||
match &mut composite.kind {
|
||||
CompositeIRKind::NoFields => {
|
||||
return quote!(); // no types mod generated for unit structs.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for TypeAliases {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
let has_fields = matches!(&self.fields, CompositeDefFields::Named(fields) if !fields.is_empty())
|
||||
|| matches!(&self.fields, CompositeDefFields::Unnamed(fields) if !fields.is_empty());
|
||||
if !has_fields {
|
||||
return;
|
||||
}
|
||||
|
||||
let visibility: syn::Visibility = parse_quote!(pub);
|
||||
|
||||
let aliases = self
|
||||
.fields
|
||||
.to_type_aliases_tokens(Some(visibility).as_ref());
|
||||
|
||||
let mod_name = &self.mod_name;
|
||||
let types_mod_ident = &self.types_mod_ident;
|
||||
|
||||
tokens.extend(quote! {
|
||||
pub mod #mod_name {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
#aliases
|
||||
CompositeIRKind::Named(named) => {
|
||||
for (name, field) in named.iter_mut() {
|
||||
let alias_name = format_ident!("{}", name.to_string().to_upper_camel_case());
|
||||
modify_field_to_be_type_alias(field, alias_name);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
CompositeIRKind::Unnamed(unnamed) => {
|
||||
for (i, field) in unnamed.iter_mut().enumerate() {
|
||||
let alias_name = format_ident!("Field{}", i);
|
||||
modify_field_to_be_type_alias(field, alias_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
quote!(pub mod #alias_mod_name {
|
||||
use super::#types_mod_ident;
|
||||
#( #aliases )*
|
||||
})
|
||||
}
|
||||
|
||||
+107
-95
@@ -4,140 +4,155 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{types::TypeGenerator, CodegenError};
|
||||
use heck::ToSnakeCase as _;
|
||||
use heck::ToUpperCamelCase as _;
|
||||
|
||||
use scale_typegen::TypeGenerator;
|
||||
use subxt_metadata::{Metadata, RuntimeApiMetadata};
|
||||
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
use crate::CodegenError;
|
||||
|
||||
/// Generates runtime functions for the given API metadata.
|
||||
fn generate_runtime_api(
|
||||
api: RuntimeApiMetadata,
|
||||
type_gen: &TypeGenerator,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<(TokenStream2, TokenStream2), CodegenError> {
|
||||
// Trait name must remain as is (upper case) to identity the runtime call.
|
||||
let trait_name_str = api.name();
|
||||
// The snake case for the trait name.
|
||||
let trait_name_snake = format_ident!("{}", api.name().to_snake_case());
|
||||
let docs = api.docs();
|
||||
let docs: TokenStream2 = should_gen_docs
|
||||
let docs: TokenStream2 = type_gen
|
||||
.settings()
|
||||
.should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
|
||||
let structs_and_methods: Vec<_> = api.methods().map(|method| {
|
||||
let method_name = format_ident!("{}", method.name());
|
||||
let method_name_str = method.name();
|
||||
let structs_and_methods: Vec<_> = api
|
||||
.methods()
|
||||
.map(|method| {
|
||||
let method_name = format_ident!("{}", method.name());
|
||||
let method_name_str = method.name();
|
||||
|
||||
let docs = method.docs();
|
||||
let docs: TokenStream2 = should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
let docs = method.docs();
|
||||
let docs: TokenStream2 = type_gen
|
||||
.settings()
|
||||
.should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut unique_names = HashSet::new();
|
||||
let mut unique_aliases = HashSet::new();
|
||||
let mut unique_names = HashSet::new();
|
||||
let mut unique_aliases = HashSet::new();
|
||||
|
||||
let inputs: Vec<_> = method.inputs().enumerate().map(|(idx, input)| {
|
||||
// These are method names, which can just be '_', but struct field names can't
|
||||
// just be an underscore, so fix any such names we find to work in structs.
|
||||
let inputs: Vec<_> = method
|
||||
.inputs()
|
||||
.enumerate()
|
||||
.map(|(idx, input)| {
|
||||
// These are method names, which can just be '_', but struct field names can't
|
||||
// just be an underscore, so fix any such names we find to work in structs.
|
||||
let mut name = input.name.trim_start_matches('_').to_string();
|
||||
if name.is_empty() {
|
||||
name = format!("_{}", idx);
|
||||
}
|
||||
while !unique_names.insert(name.clone()) {
|
||||
// Name is already used, append the index until it is unique.
|
||||
name = format!("{}_param{}", name, idx);
|
||||
}
|
||||
|
||||
let mut name = input.name.trim_start_matches('_').to_string();
|
||||
if name.is_empty() {
|
||||
name = format!("_{}", idx);
|
||||
}
|
||||
while !unique_names.insert(name.clone()) {
|
||||
// Name is already used, append the index until it is unique.
|
||||
name = format!("{}_param{}", name, idx);
|
||||
}
|
||||
let mut alias = name.to_upper_camel_case();
|
||||
// Note: name is not empty.
|
||||
if alias.as_bytes()[0].is_ascii_digit() {
|
||||
alias = format!("Param{}", alias);
|
||||
}
|
||||
while !unique_aliases.insert(alias.clone()) {
|
||||
alias = format!("{}Param{}", alias, idx);
|
||||
}
|
||||
|
||||
let mut alias = name.to_upper_camel_case();
|
||||
// Note: name is not empty.
|
||||
if alias.as_bytes()[0].is_ascii_digit() {
|
||||
alias = format!("Param{}", alias);
|
||||
}
|
||||
while !unique_aliases.insert(alias.clone()) {
|
||||
alias = format!("{}Param{}", alias, idx);
|
||||
}
|
||||
let (alias_name, name) = (format_ident!("{alias}"), format_ident!("{name}"));
|
||||
|
||||
let (alias_name, name) = (format_ident!("{alias}"), format_ident!("{name}"));
|
||||
// Generate alias for runtime type.
|
||||
let ty = type_gen
|
||||
.resolve_type_path(input.ty)
|
||||
.expect("runtime api input type is in metadata; qed");
|
||||
let aliased_param = quote!( pub type #alias_name = #ty; );
|
||||
|
||||
// Generate alias for runtime type.
|
||||
let ty = type_gen.resolve_type_path(input.ty);
|
||||
let aliased_param = quote!( pub type #alias_name = #ty; );
|
||||
// Structures are placed on the same level as the alias module.
|
||||
let struct_ty_path = quote!( #method_name::#alias_name );
|
||||
let struct_param = quote!(#name: #struct_ty_path);
|
||||
|
||||
// Structures are placed on the same level as the alias module.
|
||||
let struct_ty_path = quote!( #method_name::#alias_name );
|
||||
let struct_param = quote!(#name: #struct_ty_path);
|
||||
// Function parameters must be indented by `types`.
|
||||
let fn_param = quote!(#name: types::#struct_ty_path);
|
||||
(fn_param, struct_param, name, aliased_param)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Function parameters must be indented by `types`.
|
||||
let fn_param = quote!(#name: types::#struct_ty_path);
|
||||
(fn_param, struct_param, name, aliased_param)
|
||||
}).collect();
|
||||
let fn_params = inputs.iter().map(|(fn_param, _, _, _)| fn_param);
|
||||
let struct_params = inputs.iter().map(|(_, struct_param, _, _)| struct_param);
|
||||
let param_names = inputs.iter().map(|(_, _, name, _)| name);
|
||||
let type_aliases = inputs.iter().map(|(_, _, _, aliased_param)| aliased_param);
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
|
||||
let fn_params = inputs.iter().map(|(fn_param, _, _, _)| fn_param);
|
||||
let struct_params = inputs.iter().map(|(_, struct_param, _, _)| struct_param);
|
||||
let param_names = inputs.iter().map(|(_, _, name, _,)| name);
|
||||
let type_aliases = inputs.iter().map(|(_, _, _, aliased_param)| aliased_param);
|
||||
|
||||
let output = type_gen.resolve_type_path(method.output_ty());
|
||||
let aliased_module = quote!(
|
||||
pub mod #method_name {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
#( #type_aliases )*
|
||||
|
||||
// Guard the `Output` name against collisions by placing it in a dedicated module.
|
||||
pub mod output {
|
||||
let output = type_gen.resolve_type_path(method.output_ty())?;
|
||||
let aliased_module = quote!(
|
||||
pub mod #method_name {
|
||||
use super::#types_mod_ident;
|
||||
pub type Output = #output;
|
||||
|
||||
#( #type_aliases )*
|
||||
|
||||
// Guard the `Output` name against collisions by placing it in a dedicated module.
|
||||
pub mod output {
|
||||
use super::#types_mod_ident;
|
||||
pub type Output = #output;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
// From the method metadata generate a structure that holds
|
||||
// all parameter types. This structure is used with metadata
|
||||
// to encode parameters to the call via `encode_as_fields_to`.
|
||||
let derives = type_gen.default_derives();
|
||||
let struct_name = format_ident!("{}", method.name().to_upper_camel_case());
|
||||
let struct_input = quote!(
|
||||
#aliased_module
|
||||
// From the method metadata generate a structure that holds
|
||||
// all parameter types. This structure is used with metadata
|
||||
// to encode parameters to the call via `encode_as_fields_to`.
|
||||
let derives = type_gen.settings().derives.default_derives();
|
||||
let struct_name = format_ident!("{}", method.name().to_upper_camel_case());
|
||||
let struct_input = quote!(
|
||||
#aliased_module
|
||||
|
||||
#derives
|
||||
pub struct #struct_name {
|
||||
#( pub #struct_params, )*
|
||||
}
|
||||
);
|
||||
#derives
|
||||
pub struct #struct_name {
|
||||
#( pub #struct_params, )*
|
||||
}
|
||||
);
|
||||
|
||||
let Some(call_hash) = api.method_hash(method.name()) else {
|
||||
return Err(CodegenError::MissingRuntimeApiMetadata(
|
||||
trait_name_str.to_owned(),
|
||||
method_name_str.to_owned(),
|
||||
))
|
||||
};
|
||||
let Some(call_hash) = api.method_hash(method.name()) else {
|
||||
return Err(CodegenError::MissingRuntimeApiMetadata(
|
||||
trait_name_str.to_owned(),
|
||||
method_name_str.to_owned(),
|
||||
))
|
||||
};
|
||||
|
||||
let method = quote!(
|
||||
#docs
|
||||
pub fn #method_name(&self, #( #fn_params, )* ) -> #crate_path::runtime_api::Payload<types::#struct_name, types::#method_name::output::Output> {
|
||||
#crate_path::runtime_api::Payload::new_static(
|
||||
#trait_name_str,
|
||||
#method_name_str,
|
||||
types::#struct_name { #( #param_names, )* },
|
||||
[#(#call_hash,)*],
|
||||
)
|
||||
}
|
||||
);
|
||||
let method = quote!(
|
||||
#docs
|
||||
pub fn #method_name(&self, #( #fn_params, )* ) -> #crate_path::runtime_api::Payload<types::#struct_name, types::#method_name::output::Output> {
|
||||
#crate_path::runtime_api::Payload::new_static(
|
||||
#trait_name_str,
|
||||
#method_name_str,
|
||||
types::#struct_name { #( #param_names, )* },
|
||||
[#(#call_hash,)*],
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
Ok((struct_input, method))
|
||||
}).collect::<Result<_, _>>()?;
|
||||
Ok((struct_input, method))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let trait_name = format_ident!("{}", trait_name_str);
|
||||
|
||||
let structs = structs_and_methods.iter().map(|(struct_, _)| struct_);
|
||||
let methods = structs_and_methods.iter().map(|(_, method)| method);
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
|
||||
let runtime_api = quote!(
|
||||
pub mod #trait_name_snake {
|
||||
@@ -175,13 +190,10 @@ pub fn generate_runtime_apis(
|
||||
type_gen: &TypeGenerator,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
let runtime_fns: Vec<_> = metadata
|
||||
.runtime_api_traits()
|
||||
.map(|api| {
|
||||
generate_runtime_api(api, type_gen, types_mod_ident, crate_path, should_gen_docs)
|
||||
})
|
||||
.map(|api| generate_runtime_api(api, type_gen, crate_path))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let runtime_apis_def = runtime_fns.iter().map(|(apis, _)| apis);
|
||||
|
||||
+28
-28
@@ -2,13 +2,11 @@
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::types::TypeGenerator;
|
||||
use crate::types::TypePath;
|
||||
use heck::ToSnakeCase as _;
|
||||
use heck::ToUpperCamelCase as _;
|
||||
use heck::{ToSnakeCase as _, ToUpperCamelCase};
|
||||
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use scale_info::TypeDef;
|
||||
use scale_typegen::{typegen::type_path::TypePath, TypeGenerator};
|
||||
use subxt_metadata::{
|
||||
PalletMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType,
|
||||
};
|
||||
@@ -20,37 +18,26 @@ use super::CodegenError;
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `metadata` - Runtime metadata from which the storages are generated.
|
||||
/// - `type_gen` - The type generator containing all types defined by metadata.
|
||||
/// - `pallet` - Pallet metadata from which the storages are generated.
|
||||
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
|
||||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime metadata.
|
||||
/// - `pallet` - Pallet metadata from which the storage items are generated.
|
||||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency.
|
||||
pub fn generate_storage(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata,
|
||||
types_mod_ident: &syn::Ident,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
let Some(storage) = pallet.storage() else {
|
||||
return Ok(quote!());
|
||||
};
|
||||
|
||||
let (storage_fns, alias_modules): (Vec<_>, Vec<_>) = storage
|
||||
let (storage_fns, alias_modules): (Vec<TokenStream2>, Vec<TokenStream2>) = storage
|
||||
.entries()
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
generate_storage_entry_fns(
|
||||
type_gen,
|
||||
pallet,
|
||||
entry,
|
||||
crate_path,
|
||||
should_gen_docs,
|
||||
types_mod_ident,
|
||||
)
|
||||
})
|
||||
.map(|entry| generate_storage_entry_fns(type_gen, pallet, entry, crate_path))
|
||||
.collect::<Result<Vec<_>, CodegenError>>()?
|
||||
.into_iter()
|
||||
.unzip();
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
|
||||
Ok(quote! {
|
||||
pub mod storage {
|
||||
@@ -71,17 +58,18 @@ pub fn generate_storage(
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns storage entry functions and alias modules.
|
||||
fn generate_storage_entry_fns(
|
||||
type_gen: &TypeGenerator,
|
||||
pallet: &PalletMetadata,
|
||||
storage_entry: &StorageEntryMetadata,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> Result<(TokenStream2, TokenStream2), CodegenError> {
|
||||
let snake_case_name = storage_entry.name().to_snake_case();
|
||||
let storage_entry_ty = storage_entry.entry_type().value_ty();
|
||||
let storage_entry_value_ty = type_gen.resolve_type_path(storage_entry_ty);
|
||||
let storage_entry_value_ty = type_gen
|
||||
.resolve_type_path(storage_entry_ty)
|
||||
.expect("storage type is in metadata; qed");
|
||||
|
||||
let alias_name = format_ident!("{}", storage_entry.name().to_upper_camel_case());
|
||||
let alias_module_name = format_ident!("{snake_case_name}");
|
||||
@@ -89,7 +77,9 @@ fn generate_storage_entry_fns(
|
||||
|
||||
let storage_entry_map = |idx, id| {
|
||||
let ident: Ident = format_ident!("_{}", idx);
|
||||
let ty_path = type_gen.resolve_type_path(id);
|
||||
let ty_path = type_gen
|
||||
.resolve_type_path(id)
|
||||
.expect("type is in metadata; qed");
|
||||
|
||||
let alias_name = format_ident!("Param{}", idx);
|
||||
let alias_type = primitive_type_alias(&ty_path);
|
||||
@@ -103,7 +93,11 @@ fn generate_storage_entry_fns(
|
||||
let keys: Vec<(Ident, TokenStream, TokenStream)> = match storage_entry.entry_type() {
|
||||
StorageEntryType::Plain(_) => vec![],
|
||||
StorageEntryType::Map { key_ty, .. } => {
|
||||
match &type_gen.resolve_type(*key_ty).type_def {
|
||||
match &type_gen
|
||||
.resolve_type(*key_ty)
|
||||
.expect("key type should be present")
|
||||
.type_def
|
||||
{
|
||||
// An N-map; return each of the keys separately.
|
||||
TypeDef::Tuple(tuple) => tuple
|
||||
.fields
|
||||
@@ -128,7 +122,9 @@ fn generate_storage_entry_fns(
|
||||
};
|
||||
|
||||
let docs = storage_entry.docs();
|
||||
let docs = should_gen_docs
|
||||
let docs = type_gen
|
||||
.settings()
|
||||
.should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -181,6 +177,7 @@ fn generate_storage_entry_fns(
|
||||
|
||||
let alias_types = keys.iter().map(|(_, alias_type, _)| alias_type);
|
||||
|
||||
let types_mod_ident = type_gen.types_mod_ident();
|
||||
// Generate type alias for the return type only, since
|
||||
// the keys of the storage entry are not explicitly named.
|
||||
let alias_module = quote! {
|
||||
@@ -217,9 +214,10 @@ fn primitive_type_alias(type_path: &TypePath) -> TokenStream {
|
||||
mod tests {
|
||||
use crate::RuntimeGenerator;
|
||||
use frame_metadata::v15;
|
||||
use heck::ToUpperCamelCase as _;
|
||||
use heck::ToUpperCamelCase;
|
||||
use quote::{format_ident, quote};
|
||||
use scale_info::{meta_type, MetaType};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use subxt_metadata::Metadata;
|
||||
@@ -330,6 +328,8 @@ mod tests {
|
||||
_0: impl ::std::borrow::Borrow<types::#name_ident::Param0>,
|
||||
)
|
||||
);
|
||||
dbg!(&generated_str);
|
||||
dbg!(&expected_storage_constructor.to_string());
|
||||
assert!(generated_str.contains(&expected_storage_constructor.to_string()));
|
||||
|
||||
let alias_name = format_ident!("{}", name.to_upper_camel_case());
|
||||
|
||||
+5
-50
@@ -5,14 +5,12 @@
|
||||
//! Errors that can be emitted from codegen.
|
||||
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use scale_typegen::TypegenError;
|
||||
|
||||
/// Error returned when the Codegen cannot generate the runtime API.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum CodegenError {
|
||||
/// The given metadata type could not be found.
|
||||
#[error("Could not find type with ID {0} in the type registry; please raise a support issue.")]
|
||||
TypeNotFound(u32),
|
||||
/// Cannot fetch the metadata bytes.
|
||||
#[error("Failed to fetch metadata, make sure that you're pointing at a node which is providing substrate-based metadata: {0}")]
|
||||
Fetch(#[from] FetchMetadataError),
|
||||
@@ -22,12 +20,6 @@ pub enum CodegenError {
|
||||
/// Out of line modules are not supported.
|
||||
#[error("Out-of-line subxt modules are not supported, make sure you are providing a body to your module: pub mod polkadot {{ ... }}")]
|
||||
InvalidModule(Span),
|
||||
/// Expected named or unnamed fields.
|
||||
#[error("Fields should either be all named or all unnamed, make sure you are providing a valid metadata: {0}")]
|
||||
InvalidFields(String),
|
||||
/// Substitute types must have a valid path.
|
||||
#[error("Type substitution error: {0}")]
|
||||
TypeSubstitutionError(#[from] TypeSubstitutionError),
|
||||
/// Invalid type path.
|
||||
#[error("Invalid type path {0}: {1}")]
|
||||
InvalidTypePath(String, syn::Error),
|
||||
@@ -56,6 +48,9 @@ pub enum CodegenError {
|
||||
"Extrinsic call type could not be found. Make sure you are providing a valid substrate-based metadata"
|
||||
)]
|
||||
MissingCallType,
|
||||
/// Cannot generate types.
|
||||
#[error("Type Generation failed: {0}")]
|
||||
TypeGeneration(#[from] TypegenError),
|
||||
}
|
||||
|
||||
impl CodegenError {
|
||||
@@ -65,7 +60,7 @@ impl CodegenError {
|
||||
fn get_location(&self) -> Span {
|
||||
match self {
|
||||
Self::InvalidModule(span) => *span,
|
||||
Self::TypeSubstitutionError(err) => err.get_location(),
|
||||
Self::TypeGeneration(TypegenError::InvalidSubstitute(err)) => err.span,
|
||||
Self::InvalidTypePath(_, err) => err.span(),
|
||||
_ => proc_macro2::Span::call_site(),
|
||||
}
|
||||
@@ -102,43 +97,3 @@ pub enum FetchMetadataError {
|
||||
#[error("Other error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
/// Error attempting to do type substitution.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum TypeSubstitutionError {
|
||||
/// Substitute "to" type must be an absolute path.
|
||||
#[error("`substitute_type(with = <path>)` must be a path prefixed with 'crate::' or '::'")]
|
||||
ExpectedAbsolutePath(Span),
|
||||
/// Substitute types must have a valid path.
|
||||
#[error("Substitute types must have a valid path.")]
|
||||
EmptySubstitutePath(Span),
|
||||
/// From/To substitution types should use angle bracket generics.
|
||||
#[error("Expected the from/to type generics to have the form 'Foo<A,B,C..>'.")]
|
||||
ExpectedAngleBracketGenerics(Span),
|
||||
/// Source substitute type must be an ident.
|
||||
#[error("Expected an ident like 'Foo' or 'A' to mark a type to be substituted.")]
|
||||
InvalidFromType(Span),
|
||||
/// Target type is invalid.
|
||||
#[error("Expected an ident like 'Foo' or an absolute concrete path like '::path::to::Bar' for the substitute type.")]
|
||||
InvalidToType(Span),
|
||||
/// Target ident doesn't correspond to any source type.
|
||||
#[error("Cannot find matching param on 'from' type.")]
|
||||
NoMatchingFromType(Span),
|
||||
}
|
||||
|
||||
impl TypeSubstitutionError {
|
||||
/// Fetch the location for this error.
|
||||
// Todo: Probably worth storing location outside of the variant,
|
||||
// so that there's a common way to set a location for some error.
|
||||
fn get_location(&self) -> Span {
|
||||
match self {
|
||||
TypeSubstitutionError::ExpectedAbsolutePath(span) => *span,
|
||||
TypeSubstitutionError::EmptySubstitutePath(span) => *span,
|
||||
TypeSubstitutionError::ExpectedAngleBracketGenerics(span) => *span,
|
||||
TypeSubstitutionError::InvalidFromType(span) => *span,
|
||||
TypeSubstitutionError::InvalidToType(span) => *span,
|
||||
TypeSubstitutionError::NoMatchingFromType(span) => *span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+177
-34
@@ -9,10 +9,8 @@
|
||||
#![deny(unused_crate_dependencies, missing_docs)]
|
||||
|
||||
mod api;
|
||||
mod ir;
|
||||
mod types;
|
||||
|
||||
pub mod error;
|
||||
mod ir;
|
||||
|
||||
// These should probably be in a separate crate; they are used by the
|
||||
// macro and CLI tool, so they only live here because this is a common
|
||||
@@ -25,14 +23,12 @@ use getrandom as _;
|
||||
|
||||
use api::RuntimeGenerator;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use scale_typegen::{
|
||||
typegen::settings::substitutes::absolute_path, DerivesRegistry, TypeGeneratorSettings,
|
||||
TypeSubstitutes, TypegenError,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// We expose these only because they are currently needed in subxt-explorer.
|
||||
// Eventually we'll move the type generation stuff out into a separate crate.
|
||||
#[doc(hidden)]
|
||||
pub mod __private {
|
||||
pub use crate::types::{DerivesRegistry, TypeDefGen, TypeGenerator, TypeSubstitutes};
|
||||
}
|
||||
use syn::parse_quote;
|
||||
|
||||
// Part of the public interface, so expose:
|
||||
pub use error::CodegenError;
|
||||
@@ -72,6 +68,8 @@ pub struct CodegenBuilder {
|
||||
type_substitutes: HashMap<syn::Path, syn::Path>,
|
||||
derives_for_type: HashMap<syn::TypePath, Vec<syn::Path>>,
|
||||
attributes_for_type: HashMap<syn::TypePath, Vec<syn::Attribute>>,
|
||||
derives_for_type_recursive: HashMap<syn::TypePath, Vec<syn::Path>>,
|
||||
attributes_for_type_recursive: HashMap<syn::TypePath, Vec<syn::Attribute>>,
|
||||
}
|
||||
|
||||
impl Default for CodegenBuilder {
|
||||
@@ -90,6 +88,8 @@ impl Default for CodegenBuilder {
|
||||
type_substitutes: HashMap::new(),
|
||||
derives_for_type: HashMap::new(),
|
||||
attributes_for_type: HashMap::new(),
|
||||
derives_for_type_recursive: HashMap::new(),
|
||||
attributes_for_type_recursive: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,33 +159,47 @@ impl CodegenBuilder {
|
||||
|
||||
/// Set additional derives for a specific type at the path given.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// For composite types, you may also need to set the same additional derives on all of
|
||||
/// the contained types as well to avoid compile errors in the generated code.
|
||||
/// If you want to set the additional derives on all contained types recursively as well,
|
||||
/// you can set the `recursive` argument to `true`. If you don't do that,
|
||||
/// there might be compile errors in the generated code, if the derived trait
|
||||
/// relies on the fact that contained types also implement that trait.
|
||||
pub fn add_derives_for_type(
|
||||
&mut self,
|
||||
ty: syn::TypePath,
|
||||
derives: impl IntoIterator<Item = syn::Path>,
|
||||
recursive: bool,
|
||||
) {
|
||||
self.derives_for_type.entry(ty).or_default().extend(derives);
|
||||
if recursive {
|
||||
self.derives_for_type_recursive
|
||||
.entry(ty)
|
||||
.or_default()
|
||||
.extend(derives);
|
||||
} else {
|
||||
self.derives_for_type.entry(ty).or_default().extend(derives);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set additional attributes for a specific type at the path given.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// For composite types, you may also need to consider contained types and whether they need
|
||||
/// similar attributes setting.
|
||||
/// Setting the `recursive` argument to `true` will additionally add the specified
|
||||
/// attributes to all contained types recursively.
|
||||
pub fn add_attributes_for_type(
|
||||
&mut self,
|
||||
ty: syn::TypePath,
|
||||
attributes: impl IntoIterator<Item = syn::Attribute>,
|
||||
recursive: bool,
|
||||
) {
|
||||
self.attributes_for_type
|
||||
.entry(ty)
|
||||
.or_default()
|
||||
.extend(attributes);
|
||||
if recursive {
|
||||
self.attributes_for_type_recursive
|
||||
.entry(ty)
|
||||
.or_default()
|
||||
.extend(attributes);
|
||||
} else {
|
||||
self.attributes_for_type
|
||||
.entry(ty)
|
||||
.or_default()
|
||||
.extend(attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/// Substitute a type at the given path with some type at the second path. During codegen,
|
||||
@@ -217,30 +231,39 @@ impl CodegenBuilder {
|
||||
pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
|
||||
let crate_path = self.crate_path;
|
||||
|
||||
let mut derives_registry = if self.use_default_derives {
|
||||
types::DerivesRegistry::with_default_derives(&crate_path)
|
||||
let mut derives_registry: DerivesRegistry = if self.use_default_derives {
|
||||
default_derives(&crate_path)
|
||||
} else {
|
||||
types::DerivesRegistry::new()
|
||||
DerivesRegistry::new()
|
||||
};
|
||||
|
||||
derives_registry.extend_for_all(self.extra_global_derives, self.extra_global_attributes);
|
||||
derives_registry.add_derives_for_all(self.extra_global_derives);
|
||||
derives_registry.add_attributes_for_all(self.extra_global_attributes);
|
||||
|
||||
for (ty, derives) in self.derives_for_type {
|
||||
derives_registry.extend_for_type(ty, derives, vec![]);
|
||||
derives_registry.add_derives_for(ty, derives, false);
|
||||
}
|
||||
for (ty, derives) in self.derives_for_type_recursive {
|
||||
derives_registry.add_derives_for(ty, derives, true);
|
||||
}
|
||||
for (ty, attributes) in self.attributes_for_type {
|
||||
derives_registry.extend_for_type(ty, vec![], attributes);
|
||||
derives_registry.add_attributes_for(ty, attributes, false);
|
||||
}
|
||||
for (ty, attributes) in self.attributes_for_type_recursive {
|
||||
derives_registry.add_attributes_for(ty, attributes, true);
|
||||
}
|
||||
|
||||
let mut type_substitutes = if self.use_default_substitutions {
|
||||
types::TypeSubstitutes::with_default_substitutes(&crate_path)
|
||||
let mut type_substitutes: TypeSubstitutes = if self.use_default_substitutions {
|
||||
default_substitutes(&crate_path)
|
||||
} else {
|
||||
types::TypeSubstitutes::new()
|
||||
TypeSubstitutes::new()
|
||||
};
|
||||
|
||||
for (from, with) in self.type_substitutes {
|
||||
let abs_path = with.try_into()?;
|
||||
type_substitutes.insert(from, abs_path)?;
|
||||
let abs_path = absolute_path(with).map_err(TypegenError::from)?;
|
||||
type_substitutes
|
||||
.insert(from, abs_path)
|
||||
.map_err(TypegenError::from)?;
|
||||
}
|
||||
|
||||
let item_mod = self.item_mod;
|
||||
@@ -266,3 +289,123 @@ impl CodegenBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default [`scale_typegen::TypeGeneratorSettings`], subxt is using for generating code.
|
||||
/// Useful for emulating subxt's code generation settings from e.g. subxt-explorer.
|
||||
pub fn default_subxt_type_gen_settings() -> TypeGeneratorSettings {
|
||||
let crate_path: syn::Path = parse_quote!(::subxt);
|
||||
let derives = default_derives(&crate_path);
|
||||
let substitutes = default_substitutes(&crate_path);
|
||||
subxt_type_gen_settings(derives, substitutes, &crate_path, true)
|
||||
}
|
||||
|
||||
fn subxt_type_gen_settings(
|
||||
derives: scale_typegen::DerivesRegistry,
|
||||
substitutes: scale_typegen::TypeSubstitutes,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> TypeGeneratorSettings {
|
||||
TypeGeneratorSettings {
|
||||
types_mod_ident: parse_quote!(runtime_types),
|
||||
should_gen_docs,
|
||||
derives,
|
||||
substitutes,
|
||||
decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
|
||||
compact_as_type_path: Some(parse_quote!(#crate_path::ext::codec::CompactAs)),
|
||||
compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
|
||||
insert_codec_attributes: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn default_derives(crate_path: &syn::Path) -> DerivesRegistry {
|
||||
let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
|
||||
let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
|
||||
|
||||
let derives: [syn::Path; 5] = [
|
||||
parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
|
||||
parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
|
||||
parse_quote!(#crate_path::ext::codec::Encode),
|
||||
parse_quote!(#crate_path::ext::codec::Decode),
|
||||
parse_quote!(Debug),
|
||||
];
|
||||
|
||||
let attributes: [syn::Attribute; 3] = [
|
||||
parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
|
||||
parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
|
||||
parse_quote!(#[codec(crate = #crate_path::ext::codec)]),
|
||||
];
|
||||
|
||||
let mut derives_registry = DerivesRegistry::new();
|
||||
derives_registry.add_derives_for_all(derives);
|
||||
derives_registry.add_attributes_for_all(attributes);
|
||||
derives_registry
|
||||
}
|
||||
|
||||
fn default_substitutes(crate_path: &syn::Path) -> TypeSubstitutes {
|
||||
let mut type_substitutes = TypeSubstitutes::new();
|
||||
|
||||
let defaults: [(syn::Path, syn::Path); 11] = [
|
||||
(
|
||||
parse_quote!(bitvec::order::Lsb0),
|
||||
parse_quote!(#crate_path::utils::bits::Lsb0),
|
||||
),
|
||||
(
|
||||
parse_quote!(bitvec::order::Msb0),
|
||||
parse_quote!(#crate_path::utils::bits::Msb0),
|
||||
),
|
||||
(
|
||||
parse_quote!(sp_core::crypto::AccountId32),
|
||||
parse_quote!(#crate_path::utils::AccountId32),
|
||||
),
|
||||
(
|
||||
parse_quote!(sp_runtime::multiaddress::MultiAddress),
|
||||
parse_quote!(#crate_path::utils::MultiAddress),
|
||||
),
|
||||
(
|
||||
parse_quote!(primitive_types::H160),
|
||||
parse_quote!(#crate_path::utils::H160),
|
||||
),
|
||||
(
|
||||
parse_quote!(primitive_types::H256),
|
||||
parse_quote!(#crate_path::utils::H256),
|
||||
),
|
||||
(
|
||||
parse_quote!(primitive_types::H512),
|
||||
parse_quote!(#crate_path::utils::H512),
|
||||
),
|
||||
(
|
||||
parse_quote!(frame_support::traits::misc::WrapperKeepOpaque),
|
||||
parse_quote!(#crate_path::utils::WrapperKeepOpaque),
|
||||
),
|
||||
// BTreeMap and BTreeSet impose an `Ord` constraint on their key types. This
|
||||
// can cause an issue with generated code that doesn't impl `Ord` by default.
|
||||
// Decoding them to Vec by default (KeyedVec is just an alias for Vec with
|
||||
// suitable type params) avoids these issues.
|
||||
(
|
||||
parse_quote!(BTreeMap),
|
||||
parse_quote!(#crate_path::utils::KeyedVec),
|
||||
),
|
||||
(parse_quote!(BTreeSet), parse_quote!(::std::vec::Vec)),
|
||||
// The `UncheckedExtrinsic(pub Vec<u8>)` is part of the runtime API calls.
|
||||
// The inner bytes represent the encoded extrinsic, however when deriving the
|
||||
// `EncodeAsType` the bytes would be re-encoded. This leads to the bytes
|
||||
// being altered by adding the length prefix in front of them.
|
||||
|
||||
// Note: Not sure if this is appropriate or not. The most recent polkadot.rs file does not have these.
|
||||
(
|
||||
parse_quote!(sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic),
|
||||
parse_quote!(#crate_path::utils::UncheckedExtrinsic),
|
||||
),
|
||||
];
|
||||
|
||||
let defaults = defaults.into_iter().map(|(from, to)| {
|
||||
(
|
||||
from,
|
||||
absolute_path(to).expect("default substitutes above are absolute paths; qed"),
|
||||
)
|
||||
});
|
||||
type_substitutes
|
||||
.extend(defaults)
|
||||
.expect("default substitutes can always be parsed; qed");
|
||||
type_substitutes
|
||||
}
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::error::CodegenError;
|
||||
|
||||
use super::{Derives, Field, TypeDefParameters, TypeGenerator, TypeParameter, TypePath};
|
||||
use heck::ToUpperCamelCase as _;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use scale_info::{form::PortableForm, Type, TypeDef, TypeDefPrimitive};
|
||||
|
||||
/// Representation of a type which consists of a set of fields. Used to generate Rust code for
|
||||
/// either a standalone `struct` definition, or an `enum` variant.
|
||||
///
|
||||
/// Fields can either be named or unnamed in either case.
|
||||
#[derive(Debug)]
|
||||
pub struct CompositeDef {
|
||||
/// The name of the `struct`, or the name of the `enum` variant.
|
||||
pub name: syn::Ident,
|
||||
/// Generate either a standalone `struct` or an `enum` variant.
|
||||
pub kind: CompositeDefKind,
|
||||
/// The fields of the type, which are either all named or all unnamed.
|
||||
pub fields: CompositeDefFields,
|
||||
/// Documentation of the composite type as presented in metadata.
|
||||
pub docs: Option<TokenStream>,
|
||||
}
|
||||
|
||||
impl CompositeDef {
|
||||
/// Construct a definition which will generate code for a standalone `struct`.
|
||||
///
|
||||
/// This is useful for generating structures from call and enum metadata variants;
|
||||
/// and from all the runtime types of the metadata.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn struct_def(
|
||||
ty: &Type<PortableForm>,
|
||||
ident: &str,
|
||||
type_params: TypeDefParameters,
|
||||
fields_def: CompositeDefFields,
|
||||
field_visibility: Option<syn::Visibility>,
|
||||
type_gen: &TypeGenerator,
|
||||
docs: &[String],
|
||||
crate_path: &syn::Path,
|
||||
alias_module_name: Option<syn::Ident>,
|
||||
) -> Result<Self, CodegenError> {
|
||||
let mut derives = type_gen.type_derives(ty)?;
|
||||
let fields: Vec<_> = fields_def.field_types().collect();
|
||||
|
||||
if fields.len() == 1 {
|
||||
// any single field wrapper struct with a concrete unsigned int type can derive
|
||||
// CompactAs.
|
||||
let field = &fields[0];
|
||||
if !type_params
|
||||
.params()
|
||||
.iter()
|
||||
.any(|tp| Some(tp.original_name.to_string()) == field.type_name)
|
||||
{
|
||||
let ty = type_gen.resolve_type(field.type_id);
|
||||
if matches!(
|
||||
ty.type_def,
|
||||
TypeDef::Primitive(
|
||||
TypeDefPrimitive::U8
|
||||
| TypeDefPrimitive::U16
|
||||
| TypeDefPrimitive::U32
|
||||
| TypeDefPrimitive::U64
|
||||
| TypeDefPrimitive::U128
|
||||
)
|
||||
) {
|
||||
derives.insert_codec_compact_as(crate_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let name = format_ident!("{}", ident);
|
||||
let docs_token = Some(quote! { #( #[doc = #docs ] )* });
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
kind: CompositeDefKind::Struct {
|
||||
derives,
|
||||
type_params,
|
||||
field_visibility,
|
||||
alias_module_name,
|
||||
},
|
||||
fields: fields_def,
|
||||
docs: docs_token,
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a definition which will generate code for an `enum` variant.
|
||||
pub fn enum_variant_def(ident: &str, fields: CompositeDefFields, docs: &[String]) -> Self {
|
||||
let name = format_ident!("{}", ident);
|
||||
let docs_token = Some(quote! { #( #[doc = #docs ] )* });
|
||||
Self {
|
||||
name,
|
||||
kind: CompositeDefKind::EnumVariant,
|
||||
fields,
|
||||
docs: docs_token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for CompositeDef {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let name = &self.name;
|
||||
let docs = &self.docs;
|
||||
|
||||
let decl = match &self.kind {
|
||||
CompositeDefKind::Struct {
|
||||
derives,
|
||||
type_params,
|
||||
field_visibility,
|
||||
alias_module_name,
|
||||
} => {
|
||||
let phantom_data = type_params.unused_params_phantom_data();
|
||||
|
||||
let fields: TokenStream = self.fields.to_struct_field_tokens(
|
||||
phantom_data,
|
||||
field_visibility.as_ref(),
|
||||
alias_module_name.as_ref(),
|
||||
);
|
||||
let trailing_semicolon = matches!(
|
||||
self.fields,
|
||||
CompositeDefFields::NoFields | CompositeDefFields::Unnamed(_)
|
||||
)
|
||||
.then(|| quote!(;));
|
||||
|
||||
quote! {
|
||||
#derives
|
||||
#docs
|
||||
pub struct #name #type_params #fields #trailing_semicolon
|
||||
}
|
||||
}
|
||||
CompositeDefKind::EnumVariant => {
|
||||
let fields = self.fields.to_enum_variant_field_tokens();
|
||||
|
||||
quote! {
|
||||
#docs
|
||||
#name #fields
|
||||
}
|
||||
}
|
||||
};
|
||||
tokens.extend(decl)
|
||||
}
|
||||
}
|
||||
|
||||
/// Which kind of composite type are we generating, either a standalone `struct` or an `enum`
|
||||
/// variant.
|
||||
#[derive(Debug)]
|
||||
pub enum CompositeDefKind {
|
||||
/// Composite type comprising a Rust `struct`.
|
||||
Struct {
|
||||
derives: Derives,
|
||||
type_params: TypeDefParameters,
|
||||
field_visibility: Option<syn::Visibility>,
|
||||
alias_module_name: Option<syn::Ident>,
|
||||
},
|
||||
/// Comprises a variant of a Rust `enum`.
|
||||
EnumVariant,
|
||||
}
|
||||
|
||||
/// Encapsulates the composite fields, keeping the invariant that all fields are either named or
|
||||
/// unnamed.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CompositeDefFields {
|
||||
NoFields,
|
||||
Named(Vec<(syn::Ident, CompositeDefFieldType)>),
|
||||
Unnamed(Vec<CompositeDefFieldType>),
|
||||
}
|
||||
|
||||
impl CompositeDefFields {
|
||||
/// Construct a new set of composite fields from the supplied [`::scale_info::Field`]s.
|
||||
pub fn from_scale_info_fields(
|
||||
name: &str,
|
||||
fields: &[Field],
|
||||
parent_type_params: &[TypeParameter],
|
||||
type_gen: &TypeGenerator,
|
||||
) -> Result<Self, CodegenError> {
|
||||
if fields.is_empty() {
|
||||
return Ok(Self::NoFields);
|
||||
}
|
||||
|
||||
let mut named_fields = Vec::new();
|
||||
let mut unnamed_fields = Vec::new();
|
||||
|
||||
for field in fields {
|
||||
let type_path = type_gen.resolve_field_type_path(
|
||||
field.ty.id,
|
||||
parent_type_params,
|
||||
field.type_name.as_deref(),
|
||||
);
|
||||
let field_type =
|
||||
CompositeDefFieldType::new(field.ty.id, type_path, field.type_name.clone());
|
||||
|
||||
if let Some(name) = &field.name {
|
||||
let field_name = format_ident!("{}", name);
|
||||
named_fields.push((field_name, field_type))
|
||||
} else {
|
||||
unnamed_fields.push(field_type)
|
||||
}
|
||||
}
|
||||
|
||||
if !named_fields.is_empty() && !unnamed_fields.is_empty() {
|
||||
return Err(CodegenError::InvalidFields(name.into()));
|
||||
}
|
||||
|
||||
let res = if !named_fields.is_empty() {
|
||||
Self::Named(named_fields)
|
||||
} else {
|
||||
Self::Unnamed(unnamed_fields)
|
||||
};
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Returns the set of composite fields.
|
||||
pub fn field_types(&self) -> Box<dyn Iterator<Item = &CompositeDefFieldType> + '_> {
|
||||
match self {
|
||||
Self::NoFields => Box::new([].iter()),
|
||||
Self::Named(named_fields) => Box::new(named_fields.iter().map(|(_, f)| f)),
|
||||
Self::Unnamed(unnamed_fields) => Box::new(unnamed_fields.iter()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the code for type aliases which will be used to construct the `struct` or `enum`.
|
||||
pub fn to_type_aliases_tokens(&self, visibility: Option<&syn::Visibility>) -> TokenStream {
|
||||
match self {
|
||||
Self::NoFields => {
|
||||
quote!()
|
||||
}
|
||||
Self::Named(ref fields) => {
|
||||
let fields = fields.iter().map(|(name, ty)| {
|
||||
let alias_name = format_ident!("{}", name.to_string().to_upper_camel_case());
|
||||
// Alias without boxing to have a cleaner call interface.
|
||||
let ty_path = &ty.type_path;
|
||||
quote! ( #visibility type #alias_name = #ty_path; )
|
||||
});
|
||||
quote!( #( #fields )* )
|
||||
}
|
||||
Self::Unnamed(ref fields) => {
|
||||
let fields = fields.iter().enumerate().map(|(idx, ty)| {
|
||||
let alias_name = format_ident!("Field{}", idx);
|
||||
quote! ( #visibility type #alias_name = #ty; )
|
||||
});
|
||||
|
||||
quote!( #( #fields )* )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the code for fields which will compose a `struct`.
|
||||
pub fn to_struct_field_tokens(
|
||||
&self,
|
||||
phantom_data: Option<syn::TypePath>,
|
||||
visibility: Option<&syn::Visibility>,
|
||||
alias_module_name: Option<&syn::Ident>,
|
||||
) -> TokenStream {
|
||||
match self {
|
||||
Self::NoFields => {
|
||||
if let Some(phantom_data) = phantom_data {
|
||||
quote! { ( #phantom_data ) }
|
||||
} else {
|
||||
quote! {}
|
||||
}
|
||||
}
|
||||
Self::Named(ref fields) => {
|
||||
let fields = fields.iter().map(|(name, ty)| {
|
||||
let compact_attr = ty.compact_attr();
|
||||
|
||||
if let Some(alias_module_name) = alias_module_name {
|
||||
let alias_name =
|
||||
format_ident!("{}", name.to_string().to_upper_camel_case());
|
||||
|
||||
let mut path = quote!( #alias_module_name::#alias_name);
|
||||
if ty.is_boxed() {
|
||||
path = quote!( ::std::boxed::Box<#path> );
|
||||
}
|
||||
|
||||
quote! { #compact_attr #visibility #name: #path }
|
||||
} else {
|
||||
quote! { #compact_attr #visibility #name: #ty }
|
||||
}
|
||||
});
|
||||
let marker = phantom_data.map(|phantom_data| {
|
||||
quote!(
|
||||
#[codec(skip)]
|
||||
#visibility __subxt_unused_type_params: #phantom_data
|
||||
)
|
||||
});
|
||||
quote!(
|
||||
{
|
||||
#( #fields, )*
|
||||
#marker
|
||||
}
|
||||
)
|
||||
}
|
||||
Self::Unnamed(ref fields) => {
|
||||
let fields = fields.iter().enumerate().map(|(idx, ty)| {
|
||||
let compact_attr = ty.compact_attr();
|
||||
|
||||
if let Some(alias_module_name) = alias_module_name {
|
||||
let alias_name = format_ident!("Field{}", idx);
|
||||
|
||||
let mut path = quote!( #alias_module_name::#alias_name);
|
||||
if ty.is_boxed() {
|
||||
path = quote!( ::std::boxed::Box<#path> );
|
||||
}
|
||||
|
||||
quote! { #compact_attr #visibility #path }
|
||||
} else {
|
||||
quote! { #compact_attr #visibility #ty }
|
||||
}
|
||||
});
|
||||
let marker = phantom_data.map(|phantom_data| {
|
||||
quote!(
|
||||
#[codec(skip)]
|
||||
#visibility #phantom_data
|
||||
)
|
||||
});
|
||||
quote! {
|
||||
(
|
||||
#( #fields, )*
|
||||
#marker
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the code for fields which will compose an `enum` variant.
|
||||
pub fn to_enum_variant_field_tokens(&self) -> TokenStream {
|
||||
match self {
|
||||
Self::NoFields => quote! {},
|
||||
Self::Named(ref fields) => {
|
||||
let fields = fields.iter().map(|(name, ty)| {
|
||||
let compact_attr = ty.compact_attr();
|
||||
quote! { #compact_attr #name: #ty }
|
||||
});
|
||||
quote!( { #( #fields, )* } )
|
||||
}
|
||||
Self::Unnamed(ref fields) => {
|
||||
let fields = fields.iter().map(|ty| {
|
||||
let compact_attr = ty.compact_attr();
|
||||
quote! { #compact_attr #ty }
|
||||
});
|
||||
quote! { ( #( #fields, )* ) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a field of a composite type to be generated.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompositeDefFieldType {
|
||||
pub type_id: u32,
|
||||
pub type_path: TypePath,
|
||||
pub type_name: Option<String>,
|
||||
}
|
||||
|
||||
impl CompositeDefFieldType {
|
||||
/// Construct a new [`CompositeDefFieldType`].
|
||||
pub fn new(type_id: u32, type_path: TypePath, type_name: Option<String>) -> Self {
|
||||
CompositeDefFieldType {
|
||||
type_id,
|
||||
type_path,
|
||||
type_name,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the field is a [`::std::boxed::Box`].
|
||||
pub fn is_boxed(&self) -> bool {
|
||||
// Use the type name to detect a `Box` field.
|
||||
// Should be updated once `Box` types are no longer erased:
|
||||
// https://github.com/paritytech/scale-info/pull/82
|
||||
matches!(&self.type_name, Some(ty_name) if ty_name.contains("Box<"))
|
||||
}
|
||||
|
||||
/// Returns the `#[codec(compact)]` attribute if the type is compact.
|
||||
fn compact_attr(&self) -> Option<TokenStream> {
|
||||
self.type_path
|
||||
.is_compact()
|
||||
.then(|| quote!( #[codec(compact)] ))
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for CompositeDefFieldType {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let ty_path = &self.type_path;
|
||||
|
||||
if self.is_boxed() {
|
||||
tokens.extend(quote! { ::std::boxed::Box<#ty_path> })
|
||||
} else {
|
||||
tokens.extend(quote! { #ty_path })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use syn::{parse_quote, Path};
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
/// A struct containing the derives that we'll be applying to types;
|
||||
/// a combination of some common derives for all types, plus type
|
||||
/// specific derives.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DerivesRegistry {
|
||||
default_derives: Derives,
|
||||
specific_type_derives: HashMap<syn::TypePath, Derives>,
|
||||
}
|
||||
|
||||
impl Default for DerivesRegistry {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl DerivesRegistry {
|
||||
/// Creates a new `DerivesRegistry` with no default derives.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
default_derives: Derives::new(),
|
||||
specific_type_derives: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `DerivesRegistry` with default derives.
|
||||
///
|
||||
/// The `crate_path` denotes the `subxt` crate access path in the
|
||||
/// generated code.
|
||||
pub fn with_default_derives(crate_path: &syn::Path) -> Self {
|
||||
Self {
|
||||
default_derives: Derives::with_defaults(crate_path),
|
||||
specific_type_derives: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert derives to be applied to all generated types.
|
||||
pub fn extend_for_all(
|
||||
&mut self,
|
||||
derives: impl IntoIterator<Item = syn::Path>,
|
||||
attributes: impl IntoIterator<Item = syn::Attribute>,
|
||||
) {
|
||||
self.default_derives.derives.extend(derives);
|
||||
self.default_derives.attributes.extend(attributes);
|
||||
}
|
||||
|
||||
/// Insert derives to be applied to a specific generated type.
|
||||
pub fn extend_for_type(
|
||||
&mut self,
|
||||
ty: syn::TypePath,
|
||||
derives: impl IntoIterator<Item = syn::Path>,
|
||||
attributes: impl IntoIterator<Item = syn::Attribute>,
|
||||
) {
|
||||
let type_derives = self.specific_type_derives.entry(ty).or_default();
|
||||
type_derives.derives.extend(derives);
|
||||
type_derives.attributes.extend(attributes);
|
||||
}
|
||||
|
||||
/// Returns the derives to be applied to all generated types.
|
||||
pub fn default_derives(&self) -> &Derives {
|
||||
&self.default_derives
|
||||
}
|
||||
|
||||
/// Resolve the derives for a generated type. Includes:
|
||||
/// - The default derives for all types e.g. `scale::Encode, scale::Decode`
|
||||
/// - Any user-defined derives for all types via `generated_type_derives`
|
||||
/// - Any user-defined derives for this specific type
|
||||
pub fn resolve(&self, ty: &syn::TypePath) -> Derives {
|
||||
let mut resolved_derives = self.default_derives.clone();
|
||||
if let Some(specific) = self.specific_type_derives.get(ty) {
|
||||
resolved_derives.extend_from(specific.clone());
|
||||
}
|
||||
resolved_derives
|
||||
}
|
||||
}
|
||||
|
||||
/// A struct storing the set of derives and derive attributes that we'll apply
|
||||
/// to generated types.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Derives {
|
||||
derives: HashSet<syn::Path>,
|
||||
attributes: HashSet<syn::Attribute>,
|
||||
}
|
||||
|
||||
impl Default for Derives {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<syn::Path> for Derives {
|
||||
fn from_iter<T: IntoIterator<Item = Path>>(iter: T) -> Self {
|
||||
let derives = iter.into_iter().collect();
|
||||
Self {
|
||||
derives,
|
||||
attributes: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Derives {
|
||||
/// Creates an empty instance of `Derives` (with no default derives).
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
derives: HashSet::new(),
|
||||
attributes: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new instance of `Derives` with the `crate_path` prepended
|
||||
/// to the set of default derives that reside in `subxt`.
|
||||
pub fn with_defaults(crate_path: &syn::Path) -> Self {
|
||||
let mut derives = HashSet::new();
|
||||
let mut attributes = HashSet::new();
|
||||
|
||||
derives.insert(syn::parse_quote!(#crate_path::ext::scale_encode::EncodeAsType));
|
||||
let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
|
||||
attributes.insert(syn::parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]));
|
||||
|
||||
derives.insert(syn::parse_quote!(#crate_path::ext::scale_decode::DecodeAsType));
|
||||
let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
|
||||
attributes.insert(syn::parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]));
|
||||
|
||||
derives.insert(syn::parse_quote!(#crate_path::ext::codec::Encode));
|
||||
derives.insert(syn::parse_quote!(#crate_path::ext::codec::Decode));
|
||||
attributes.insert(syn::parse_quote!(#[codec(crate = #crate_path::ext::codec)]));
|
||||
|
||||
derives.insert(syn::parse_quote!(Debug));
|
||||
|
||||
Self {
|
||||
derives,
|
||||
attributes,
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend this set of `Derives` from another.
|
||||
pub fn extend_from(&mut self, other: Derives) {
|
||||
self.derives.extend(other.derives);
|
||||
self.attributes.extend(other.attributes);
|
||||
}
|
||||
|
||||
/// Add `#crate_path::ext::codec::CompactAs` to the derives.
|
||||
pub fn insert_codec_compact_as(&mut self, crate_path: &syn::Path) {
|
||||
self.insert_derive(parse_quote!(#crate_path::ext::codec::CompactAs));
|
||||
}
|
||||
|
||||
/// Extend the set of derives by providing an iterator of paths to derive macros.
|
||||
pub fn extend(&mut self, derives: impl Iterator<Item = syn::Path>) {
|
||||
for derive in derives {
|
||||
self.insert_derive(derive)
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a single derive.
|
||||
pub fn insert_derive(&mut self, derive: syn::Path) {
|
||||
self.derives.insert(derive);
|
||||
}
|
||||
|
||||
/// Insert a single attribute to be applied to types.
|
||||
pub fn insert_attribute(&mut self, attribute: syn::Attribute) {
|
||||
self.attributes.insert(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for Derives {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
if !self.derives.is_empty() {
|
||||
let mut sorted = self.derives.iter().cloned().collect::<Vec<_>>();
|
||||
sorted.sort_by(|a, b| {
|
||||
quote::quote!(#a)
|
||||
.to_string()
|
||||
.cmp("e::quote!(#b).to_string())
|
||||
});
|
||||
|
||||
tokens.extend(quote::quote! {
|
||||
#[derive(#( #sorted ),*)]
|
||||
})
|
||||
}
|
||||
if !self.attributes.is_empty() {
|
||||
let mut sorted = self.attributes.iter().cloned().collect::<Vec<_>>();
|
||||
sorted.sort_by(|a, b| {
|
||||
quote::quote!(#a)
|
||||
.to_string()
|
||||
.cmp("e::quote!(#b).to_string())
|
||||
});
|
||||
|
||||
tokens.extend(quote::quote! {
|
||||
#( #sorted )*
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,350 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
mod composite_def;
|
||||
mod derives;
|
||||
mod substitutes;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod type_def;
|
||||
mod type_def_params;
|
||||
mod type_path;
|
||||
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use scale_info::{form::PortableForm, PortableRegistry, Type, TypeDef};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::error::CodegenError;
|
||||
|
||||
pub use self::{
|
||||
composite_def::{CompositeDef, CompositeDefFieldType, CompositeDefFields},
|
||||
derives::{Derives, DerivesRegistry},
|
||||
substitutes::TypeSubstitutes,
|
||||
type_def::TypeDefGen,
|
||||
type_def_params::TypeDefParameters,
|
||||
type_path::{TypeParameter, TypePath, TypePathType},
|
||||
};
|
||||
|
||||
pub type Field = scale_info::Field<PortableForm>;
|
||||
|
||||
/// Generate a Rust module containing all types defined in the supplied [`PortableRegistry`].
|
||||
#[derive(Debug)]
|
||||
pub struct TypeGenerator<'a> {
|
||||
/// The name of the module which will contain the generated types.
|
||||
types_mod_ident: Ident,
|
||||
/// Registry of type definitions to be transformed into Rust type definitions.
|
||||
type_registry: &'a PortableRegistry,
|
||||
/// User defined overrides for generated types.
|
||||
type_substitutes: TypeSubstitutes,
|
||||
/// Set of derives with which to annotate generated types.
|
||||
derives: DerivesRegistry,
|
||||
/// The `subxt` crate access path in the generated code.
|
||||
crate_path: syn::Path,
|
||||
/// True if codegen should generate the documentation for the API.
|
||||
should_gen_docs: bool,
|
||||
}
|
||||
|
||||
impl<'a> TypeGenerator<'a> {
|
||||
/// Construct a new [`TypeGenerator`].
|
||||
pub fn new(
|
||||
type_registry: &'a PortableRegistry,
|
||||
root_mod: &'static str,
|
||||
type_substitutes: TypeSubstitutes,
|
||||
derives: DerivesRegistry,
|
||||
crate_path: syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Self {
|
||||
let root_mod_ident = Ident::new(root_mod, Span::call_site());
|
||||
Self {
|
||||
types_mod_ident: root_mod_ident,
|
||||
type_registry,
|
||||
type_substitutes,
|
||||
derives,
|
||||
crate_path,
|
||||
should_gen_docs,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a module containing all types defined in the supplied type registry.
|
||||
pub fn generate_types_mod(&self) -> Result<Module, CodegenError> {
|
||||
let root_mod_ident = &self.types_mod_ident;
|
||||
let mut root_mod = Module::new(root_mod_ident.clone(), root_mod_ident.clone());
|
||||
|
||||
for ty in &self.type_registry.types {
|
||||
let path = &ty.ty.path;
|
||||
// Don't generate a type if it was substituted - the target type might
|
||||
// not be in the type registry + our resolution already performs the substitution.
|
||||
if self.type_substitutes.contains(path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let namespace = path.namespace();
|
||||
|
||||
// prelude types e.g. Option/Result have no namespace, so we don't generate them
|
||||
if namespace.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Lazily create submodules for the encountered namespace path, if they don't exist
|
||||
let innermost_module = namespace
|
||||
.iter()
|
||||
.map(|segment| Ident::new(segment, Span::call_site()))
|
||||
.fold(&mut root_mod, |module, ident| {
|
||||
module
|
||||
.children
|
||||
.entry(ident.clone())
|
||||
.or_insert_with(|| Module::new(ident, root_mod_ident.clone()))
|
||||
});
|
||||
|
||||
innermost_module
|
||||
.types
|
||||
.insert(path.clone(), TypeDefGen::from_type(&ty.ty, self)?);
|
||||
}
|
||||
|
||||
Ok(root_mod)
|
||||
}
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// If no type with the given id found in the type registry.
|
||||
pub fn resolve_type(&self, id: u32) -> Type<PortableForm> {
|
||||
self.type_registry
|
||||
.resolve(id)
|
||||
.unwrap_or_else(|| panic!("No type with id {id} found"))
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// Get the type path for a field of a struct or an enum variant, providing any generic
|
||||
/// type parameters from the containing type. This is for identifying where a generic type
|
||||
/// parameter is used in a field type e.g.
|
||||
///
|
||||
/// ```rust
|
||||
/// struct S<T> {
|
||||
/// a: T, // `T` is the "parent" type param from the containing type.
|
||||
/// b: Vec<Option<T>>, // nested use of generic type param `T`.
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This allows generating the correct generic field type paths.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If no type with the given id found in the type registry.
|
||||
pub fn resolve_field_type_path(
|
||||
&self,
|
||||
id: u32,
|
||||
parent_type_params: &[TypeParameter],
|
||||
original_name: Option<&str>,
|
||||
) -> TypePath {
|
||||
self.resolve_type_path_recurse(id, true, parent_type_params, original_name)
|
||||
}
|
||||
|
||||
/// Get the type path for the given type identifier.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If no type with the given id found in the type registry.
|
||||
pub fn resolve_type_path(&self, id: u32) -> TypePath {
|
||||
self.resolve_type_path_recurse(id, false, &[], None)
|
||||
}
|
||||
|
||||
/// Visit each node in a possibly nested type definition to produce a type path.
|
||||
///
|
||||
/// e.g `Result<GenericStruct<NestedGenericStruct<T>>, String>`
|
||||
///
|
||||
/// if `original_name` is `Some(original_name)`, the resolved type needs to have the same `original_name`.
|
||||
fn resolve_type_path_recurse(
|
||||
&self,
|
||||
id: u32,
|
||||
is_field: bool,
|
||||
parent_type_params: &[TypeParameter],
|
||||
original_name: Option<&str>,
|
||||
) -> TypePath {
|
||||
if let Some(parent_type_param) = parent_type_params.iter().find(|tp| {
|
||||
tp.concrete_type_id == id
|
||||
&& original_name.map_or(true, |original_name| tp.original_name == original_name)
|
||||
}) {
|
||||
return TypePath::from_parameter(parent_type_param.clone());
|
||||
}
|
||||
|
||||
let mut ty = self.resolve_type(id);
|
||||
|
||||
if ty.path.ident() == Some("Cow".to_string()) {
|
||||
ty = self.resolve_type(
|
||||
ty.type_params[0]
|
||||
.ty
|
||||
.expect("type parameters to Cow are not expected to be skipped; qed")
|
||||
.id,
|
||||
)
|
||||
}
|
||||
|
||||
let params: Vec<_> = ty
|
||||
.type_params
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
f.ty.map(|f| self.resolve_type_path_recurse(f.id, false, parent_type_params, None))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let ty = match &ty.type_def {
|
||||
TypeDef::Composite(_) | TypeDef::Variant(_) => {
|
||||
if let Some(ty) = self
|
||||
.type_substitutes
|
||||
.for_path_with_params(&ty.path, ¶ms)
|
||||
{
|
||||
ty
|
||||
} else {
|
||||
TypePathType::from_type_def_path(&ty.path, self.types_mod_ident.clone(), params)
|
||||
}
|
||||
}
|
||||
TypeDef::Primitive(primitive) => TypePathType::Primitive {
|
||||
def: primitive.clone(),
|
||||
},
|
||||
TypeDef::Array(arr) => TypePathType::Array {
|
||||
len: arr.len as usize,
|
||||
of: Box::new(self.resolve_type_path_recurse(
|
||||
arr.type_param.id,
|
||||
false,
|
||||
parent_type_params,
|
||||
None,
|
||||
)),
|
||||
},
|
||||
TypeDef::Sequence(seq) => TypePathType::Vec {
|
||||
of: Box::new(self.resolve_type_path_recurse(
|
||||
seq.type_param.id,
|
||||
false,
|
||||
parent_type_params,
|
||||
None,
|
||||
)),
|
||||
},
|
||||
TypeDef::Tuple(tuple) => TypePathType::Tuple {
|
||||
elements: tuple
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| self.resolve_type_path_recurse(f.id, false, parent_type_params, None))
|
||||
.collect(),
|
||||
},
|
||||
TypeDef::Compact(compact) => TypePathType::Compact {
|
||||
inner: Box::new(self.resolve_type_path_recurse(
|
||||
compact.type_param.id,
|
||||
false,
|
||||
parent_type_params,
|
||||
None,
|
||||
)),
|
||||
is_field,
|
||||
crate_path: self.crate_path.clone(),
|
||||
},
|
||||
TypeDef::BitSequence(bitseq) => TypePathType::BitVec {
|
||||
bit_order_type: Box::new(self.resolve_type_path_recurse(
|
||||
bitseq.bit_order_type.id,
|
||||
false,
|
||||
parent_type_params,
|
||||
None,
|
||||
)),
|
||||
bit_store_type: Box::new(self.resolve_type_path_recurse(
|
||||
bitseq.bit_store_type.id,
|
||||
false,
|
||||
parent_type_params,
|
||||
None,
|
||||
)),
|
||||
crate_path: self.crate_path.clone(),
|
||||
},
|
||||
};
|
||||
|
||||
TypePath::from_type(ty)
|
||||
}
|
||||
|
||||
/// Returns the derives to be applied to all generated types.
|
||||
pub fn default_derives(&self) -> &Derives {
|
||||
self.derives.default_derives()
|
||||
}
|
||||
|
||||
/// Returns the type registry.
|
||||
pub fn types(&self) -> &PortableRegistry {
|
||||
self.type_registry
|
||||
}
|
||||
|
||||
/// Returns the derives to be applied to a generated type.
|
||||
pub fn type_derives(&self, ty: &Type<PortableForm>) -> Result<Derives, CodegenError> {
|
||||
let joined_path = ty.path.segments.join("::");
|
||||
let ty_path: syn::TypePath = syn::parse_str(&joined_path)
|
||||
.map_err(|e| CodegenError::InvalidTypePath(joined_path, e))?;
|
||||
Ok(self.derives.resolve(&ty_path))
|
||||
}
|
||||
|
||||
/// The name of the module which will contain the generated types.
|
||||
pub fn types_mod_ident(&self) -> &Ident {
|
||||
&self.types_mod_ident
|
||||
}
|
||||
|
||||
/// The `subxt` crate access path in the generated code.
|
||||
pub fn crate_path(&self) -> &syn::Path {
|
||||
&self.crate_path
|
||||
}
|
||||
|
||||
/// True if codegen should generate the documentation for the API.
|
||||
pub fn should_gen_docs(&self) -> bool {
|
||||
self.should_gen_docs
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a Rust `mod`, containing generated types and child `mod`s.
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
name: Ident,
|
||||
root_mod: Ident,
|
||||
children: BTreeMap<Ident, Module>,
|
||||
types: BTreeMap<scale_info::Path<PortableForm>, TypeDefGen>,
|
||||
}
|
||||
|
||||
impl ToTokens for Module {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let name = &self.name;
|
||||
let root_mod = &self.root_mod;
|
||||
let modules = self.children.values();
|
||||
let types = self.types.values().clone();
|
||||
|
||||
tokens.extend(quote! {
|
||||
pub mod #name {
|
||||
use super::#root_mod;
|
||||
|
||||
#( #modules )*
|
||||
#( #types )*
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// Create a new [`Module`], with a reference to the root `mod` for resolving type paths.
|
||||
pub(crate) fn new(name: Ident, root_mod: Ident) -> Self {
|
||||
Self {
|
||||
name,
|
||||
root_mod,
|
||||
children: BTreeMap::new(),
|
||||
types: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the module ident.
|
||||
pub fn ident(&self) -> &Ident {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Returns this `Module`s child `mod`s.
|
||||
pub fn children(&self) -> impl Iterator<Item = (&Ident, &Module)> {
|
||||
self.children.iter()
|
||||
}
|
||||
|
||||
/// Returns the generated types.
|
||||
pub fn types(&self) -> impl Iterator<Item = (&scale_info::Path<PortableForm>, &TypeDefGen)> {
|
||||
self.types.iter()
|
||||
}
|
||||
|
||||
/// Returns the root `mod` used for resolving type paths.
|
||||
pub fn root_mod(&self) -> &Ident {
|
||||
&self.root_mod
|
||||
}
|
||||
}
|
||||
@@ -1,529 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::error::TypeSubstitutionError;
|
||||
use std::{borrow::Borrow, collections::HashMap};
|
||||
use syn::{parse_quote, spanned::Spanned as _};
|
||||
|
||||
use super::{TypePath, TypePathType};
|
||||
|
||||
/// A map of type substitutes. We match on the paths to generated types in order
|
||||
/// to figure out when to swap said type with some provided substitute.
|
||||
#[derive(Debug)]
|
||||
pub struct TypeSubstitutes {
|
||||
substitutes: HashMap<PathSegments, Substitute>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Substitute {
|
||||
path: syn::Path,
|
||||
param_mapping: TypeParamMapping,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TypeParamMapping {
|
||||
// Pass any generics from source to target type
|
||||
PassThrough,
|
||||
// Replace any ident seen in the path with the input generic type at this index
|
||||
Specified(Vec<(syn::Ident, usize)>),
|
||||
}
|
||||
|
||||
macro_rules! path_segments {
|
||||
($($ident: ident)::*) => {
|
||||
PathSegments(
|
||||
[$(stringify!($ident)),*].into_iter().map(String::from).collect::<Vec<_>>()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TypeSubstitutes {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeSubstitutes {
|
||||
/// Creates a new `TypeSubstitutes` with no default derives.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
substitutes: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `TypeSubstitutes` with some default substitutions in place.
|
||||
///
|
||||
/// The `crate_path` denotes the `subxt` crate access path in the
|
||||
/// generated code.
|
||||
pub fn with_default_substitutes(crate_path: &syn::Path) -> Self {
|
||||
// Some hardcoded default type substitutes, can be overridden by user
|
||||
let defaults = [
|
||||
(
|
||||
path_segments!(bitvec::order::Lsb0),
|
||||
parse_quote!(#crate_path::utils::bits::Lsb0),
|
||||
),
|
||||
(
|
||||
path_segments!(bitvec::order::Msb0),
|
||||
parse_quote!(#crate_path::utils::bits::Msb0),
|
||||
),
|
||||
(
|
||||
path_segments!(sp_core::crypto::AccountId32),
|
||||
parse_quote!(#crate_path::utils::AccountId32),
|
||||
),
|
||||
(
|
||||
path_segments!(sp_runtime::multiaddress::MultiAddress),
|
||||
parse_quote!(#crate_path::utils::MultiAddress),
|
||||
),
|
||||
(
|
||||
path_segments!(primitive_types::H160),
|
||||
parse_quote!(#crate_path::utils::H160),
|
||||
),
|
||||
(
|
||||
path_segments!(primitive_types::H256),
|
||||
parse_quote!(#crate_path::utils::H256),
|
||||
),
|
||||
(
|
||||
path_segments!(primitive_types::H512),
|
||||
parse_quote!(#crate_path::utils::H512),
|
||||
),
|
||||
(
|
||||
path_segments!(frame_support::traits::misc::WrapperKeepOpaque),
|
||||
parse_quote!(#crate_path::utils::WrapperKeepOpaque),
|
||||
),
|
||||
// BTreeMap and BTreeSet impose an `Ord` constraint on their key types. This
|
||||
// can cause an issue with generated code that doesn't impl `Ord` by default.
|
||||
// Decoding them to Vec by default (KeyedVec is just an alias for Vec with
|
||||
// suitable type params) avoids these issues.
|
||||
(
|
||||
path_segments!(BTreeMap),
|
||||
parse_quote!(#crate_path::utils::KeyedVec),
|
||||
),
|
||||
(path_segments!(BTreeSet), parse_quote!(::std::vec::Vec)),
|
||||
// The `UncheckedExtrinsic(pub Vec<u8>)` is part of the runtime API calls.
|
||||
// The inner bytes represent the encoded extrinsic, however when deriving the
|
||||
// `EncodeAsType` the bytes would be re-encoded. This leads to the bytes
|
||||
// being altered by adding the length prefix in front of them.
|
||||
(
|
||||
path_segments!(sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic),
|
||||
parse_quote!(#crate_path::utils::UncheckedExtrinsic),
|
||||
),
|
||||
];
|
||||
|
||||
let default_substitutes = defaults
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
k,
|
||||
Substitute {
|
||||
path: v,
|
||||
param_mapping: TypeParamMapping::PassThrough,
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
substitutes: default_substitutes,
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert the given substitution, overwriting any other with the same path.
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
source: syn::Path,
|
||||
target: AbsolutePath,
|
||||
) -> Result<(), TypeSubstitutionError> {
|
||||
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
|
||||
self.substitutes.insert(key, val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Only insert the given substitution if a substitution at that path doesn't
|
||||
/// already exist.
|
||||
pub fn insert_if_not_exists(
|
||||
&mut self,
|
||||
source: syn::Path,
|
||||
target: AbsolutePath,
|
||||
) -> Result<(), TypeSubstitutionError> {
|
||||
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
|
||||
self.substitutes.entry(key).or_insert(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a bunch of source to target type substitutions.
|
||||
pub fn extend(
|
||||
&mut self,
|
||||
elems: impl IntoIterator<Item = (syn::Path, AbsolutePath)>,
|
||||
) -> Result<(), TypeSubstitutionError> {
|
||||
for (source, target) in elems.into_iter() {
|
||||
let (key, val) = TypeSubstitutes::parse_path_substitution(source, target.0)?;
|
||||
self.substitutes.insert(key, val);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Given a source and target path, parse the type params to work out the mapping from
|
||||
/// source to target, and output the source => substitution mapping that we work out from this.
|
||||
fn parse_path_substitution(
|
||||
src_path: syn::Path,
|
||||
target_path: syn::Path,
|
||||
) -> Result<(PathSegments, Substitute), TypeSubstitutionError> {
|
||||
let param_mapping = Self::parse_path_param_mapping(&src_path, &target_path)?;
|
||||
|
||||
Ok((
|
||||
PathSegments::from(&src_path),
|
||||
Substitute {
|
||||
// Note; at this point, target_path might have some generics still. These
|
||||
// might be hardcoded types that we want to keep, so leave them here for now.
|
||||
path: target_path,
|
||||
param_mapping,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
/// Given a source and target path, parse the type params to work out the mapping from
|
||||
/// source to target, and return it.
|
||||
fn parse_path_param_mapping(
|
||||
src_path: &syn::Path,
|
||||
target_path: &syn::Path,
|
||||
) -> Result<TypeParamMapping, TypeSubstitutionError> {
|
||||
let Some(syn::PathSegment {
|
||||
arguments: src_path_args,
|
||||
..
|
||||
}) = src_path.segments.last()
|
||||
else {
|
||||
return Err(TypeSubstitutionError::EmptySubstitutePath(src_path.span()));
|
||||
};
|
||||
let Some(syn::PathSegment {
|
||||
arguments: target_path_args,
|
||||
..
|
||||
}) = target_path.segments.last()
|
||||
else {
|
||||
return Err(TypeSubstitutionError::EmptySubstitutePath(
|
||||
target_path.span(),
|
||||
));
|
||||
};
|
||||
|
||||
// Get hold of the generic args for the "from" type, erroring if they aren't valid.
|
||||
let source_args = match src_path_args {
|
||||
syn::PathArguments::None => {
|
||||
// No generics defined on the source type:
|
||||
Vec::new()
|
||||
}
|
||||
syn::PathArguments::AngleBracketed(args) => {
|
||||
// We have generics like <A,B> defined on the source type (error for any non-ident type):
|
||||
args.args
|
||||
.iter()
|
||||
.map(|arg| match get_valid_from_substitution_type(arg) {
|
||||
Some(ident) => Ok(ident),
|
||||
None => Err(TypeSubstitutionError::InvalidFromType(arg.span())),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
}
|
||||
syn::PathArguments::Parenthesized(args) => {
|
||||
// Generics like (A,B) -> defined; not allowed:
|
||||
return Err(TypeSubstitutionError::ExpectedAngleBracketGenerics(
|
||||
args.span(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// Get hold of the generic args for the "to" type, erroring if they aren't valid.
|
||||
let target_args = match target_path_args {
|
||||
syn::PathArguments::None => {
|
||||
// No generics on target.
|
||||
Vec::new()
|
||||
}
|
||||
syn::PathArguments::AngleBracketed(args) => {
|
||||
// We have generics like <A,B> defined on the target type.
|
||||
args.args
|
||||
.iter()
|
||||
.map(|arg| match get_valid_to_substitution_type(arg) {
|
||||
Some(arg) => Ok(arg),
|
||||
None => Err(TypeSubstitutionError::InvalidToType(arg.span())),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
}
|
||||
syn::PathArguments::Parenthesized(args) => {
|
||||
// Generics like (A,B) -> defined; not allowed:
|
||||
return Err(TypeSubstitutionError::ExpectedAngleBracketGenerics(
|
||||
args.span(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// If no generics defined on source or target, we just apply any concrete generics
|
||||
// to the substitute type.
|
||||
if source_args.is_empty() && target_args.is_empty() {
|
||||
return Ok(TypeParamMapping::PassThrough);
|
||||
}
|
||||
|
||||
// Make a note of the idents in the source args and their indexes.
|
||||
let mapping = source_args
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, ident)| (ident.clone(), idx))
|
||||
.collect();
|
||||
|
||||
Ok(TypeParamMapping::Specified(mapping))
|
||||
}
|
||||
|
||||
/// Given a source type path, return whether a substitute exists for it.
|
||||
pub fn contains(&self, path: impl Into<PathSegments>) -> bool {
|
||||
self.substitutes.contains_key(&path.into())
|
||||
}
|
||||
|
||||
/// Given a source type path and the resolved, supplied type parameters,
|
||||
/// return a new path and optionally overwritten type parameters.
|
||||
pub fn for_path_with_params(
|
||||
&self,
|
||||
path: impl Into<PathSegments>,
|
||||
params: &[TypePath],
|
||||
) -> Option<TypePathType> {
|
||||
// If we find a substitute type, we'll take the substitute path, and
|
||||
// swap any idents with their new concrete types.
|
||||
fn replace_params(
|
||||
mut substitute_path: syn::Path,
|
||||
params: &[TypePath],
|
||||
mapping: &TypeParamMapping,
|
||||
) -> TypePathType {
|
||||
match mapping {
|
||||
// We need to map the input params to the output params somehow:
|
||||
TypeParamMapping::Specified(mapping) => {
|
||||
// A map from ident name to replacement path.
|
||||
let replacement_map: Vec<(&syn::Ident, &TypePath)> = mapping
|
||||
.iter()
|
||||
.filter_map(|(ident, idx)| params.get(*idx).map(|param| (ident, param)))
|
||||
.collect();
|
||||
|
||||
// Replace params in our substitute path with the incoming ones as needed.
|
||||
// No need if no replacements given.
|
||||
if !replacement_map.is_empty() {
|
||||
replace_path_params_recursively(&mut substitute_path, &replacement_map);
|
||||
}
|
||||
|
||||
TypePathType::Path {
|
||||
path: substitute_path,
|
||||
params: Vec::new(),
|
||||
}
|
||||
}
|
||||
// No mapping; just hand back the substitute path and input params.
|
||||
TypeParamMapping::PassThrough => TypePathType::Path {
|
||||
path: substitute_path,
|
||||
params: params.to_vec(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let path = path.into();
|
||||
|
||||
self.substitutes
|
||||
.get(&path)
|
||||
.map(|sub| replace_params(sub.path.clone(), params, &sub.param_mapping))
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifiers joined by the `::` separator.
|
||||
///
|
||||
/// We use this as a common denominator, since we need a consistent keys for both
|
||||
/// `syn::TypePath` and `scale_info::ty::path::Path` types.
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
pub struct PathSegments(Vec<String>);
|
||||
|
||||
impl From<&syn::Path> for PathSegments {
|
||||
fn from(path: &syn::Path) -> Self {
|
||||
PathSegments(path.segments.iter().map(|x| x.ident.to_string()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: scale_info::form::Form> From<&scale_info::Path<T>> for PathSegments {
|
||||
fn from(path: &scale_info::Path<T>) -> Self {
|
||||
PathSegments(
|
||||
path.segments
|
||||
.iter()
|
||||
.map(|x| x.as_ref().to_owned())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dig through a `syn::TypePath` (this is provided by the user in a type substitution definition as the "to" type) and
|
||||
/// swap out any type params which match the idents given in the "from" type with the corresponding concrete types.
|
||||
///
|
||||
/// eg if we have:
|
||||
///
|
||||
/// ```text
|
||||
/// from = sp_runtime::MultiAddress<A, B>,
|
||||
/// to = ::subxt::utils::Static<::sp_runtime::MultiAddress<A, B>>
|
||||
/// ```
|
||||
///
|
||||
/// And we encounter a `sp_runtime::MultiAddress<Foo, Bar>`, then we will pass the `::sp_runtime::MultiAddress<A, B>`
|
||||
/// type param value into this call to turn it into `::sp_runtime::MultiAddress<Foo, Bar>`.
|
||||
fn replace_path_params_recursively<I: Borrow<syn::Ident>, P: Borrow<TypePath>>(
|
||||
path: &mut syn::Path,
|
||||
params: &Vec<(I, P)>,
|
||||
) {
|
||||
for segment in &mut path.segments {
|
||||
let syn::PathArguments::AngleBracketed(args) = &mut segment.arguments else {
|
||||
continue;
|
||||
};
|
||||
for arg in &mut args.args {
|
||||
let syn::GenericArgument::Type(ty) = arg else {
|
||||
continue;
|
||||
};
|
||||
let syn::Type::Path(path) = ty else {
|
||||
continue;
|
||||
};
|
||||
if let Some(ident) = get_ident_from_type_path(path) {
|
||||
if let Some((_, replacement)) = params.iter().find(|(i, _)| ident == i.borrow()) {
|
||||
*ty = replacement.borrow().to_syn_type();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
replace_path_params_recursively(&mut path.path, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a "to" type in a type substitution, return the TypePath inside or None if
|
||||
/// it's not a valid "to" type.
|
||||
fn get_valid_to_substitution_type(arg: &syn::GenericArgument) -> Option<&syn::TypePath> {
|
||||
let syn::GenericArgument::Type(syn::Type::Path(type_path)) = arg else {
|
||||
// We are looking for a type, not a lifetime or anything else
|
||||
return None;
|
||||
};
|
||||
Some(type_path)
|
||||
}
|
||||
|
||||
/// Given a "from" type in a type substitution, return the Ident inside or None if
|
||||
/// it's not a valid "from" type.
|
||||
fn get_valid_from_substitution_type(arg: &syn::GenericArgument) -> Option<&syn::Ident> {
|
||||
let syn::GenericArgument::Type(syn::Type::Path(type_path)) = arg else {
|
||||
// We are looking for a type, not a lifetime or anything else
|
||||
return None;
|
||||
};
|
||||
get_ident_from_type_path(type_path)
|
||||
}
|
||||
|
||||
/// Given a type path, return the single ident representing it if that's all it is.
|
||||
fn get_ident_from_type_path(type_path: &syn::TypePath) -> Option<&syn::Ident> {
|
||||
if type_path.qself.is_some() {
|
||||
// No "<Foo as Bar>" type thing
|
||||
return None;
|
||||
}
|
||||
if type_path.path.leading_colon.is_some() {
|
||||
// No leading "::"
|
||||
return None;
|
||||
}
|
||||
if type_path.path.segments.len() > 1 {
|
||||
// The path should just be a single ident, not multiple
|
||||
return None;
|
||||
}
|
||||
let Some(segment) = type_path.path.segments.last() else {
|
||||
// Get the single ident (should be infallible)
|
||||
return None;
|
||||
};
|
||||
if !segment.arguments.is_empty() {
|
||||
// The ident shouldn't have any of it's own generic args like A<B, C>
|
||||
return None;
|
||||
}
|
||||
Some(&segment.ident)
|
||||
}
|
||||
|
||||
/// Whether a path is absolute - starts with `::` or `crate`.
|
||||
fn is_absolute(path: &syn::Path) -> bool {
|
||||
path.leading_colon.is_some()
|
||||
|| path
|
||||
.segments
|
||||
.first()
|
||||
.map_or(false, |segment| segment.ident == "crate")
|
||||
}
|
||||
|
||||
pub struct AbsolutePath(pub syn::Path);
|
||||
|
||||
impl TryFrom<syn::Path> for AbsolutePath {
|
||||
type Error = TypeSubstitutionError;
|
||||
fn try_from(value: syn::Path) -> Result<Self, Self::Error> {
|
||||
if is_absolute(&value) {
|
||||
Ok(AbsolutePath(value))
|
||||
} else {
|
||||
Err(TypeSubstitutionError::ExpectedAbsolutePath(value.span()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
macro_rules! syn_path {
|
||||
($path:path) => {{
|
||||
let path: syn::Path = syn::parse_quote!($path);
|
||||
path
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! type_path {
|
||||
($path:path) => {{
|
||||
let path: syn::Path = syn::parse_quote!($path);
|
||||
TypePath::from_syn_path(path)
|
||||
}};
|
||||
}
|
||||
|
||||
fn ident(name: &'static str) -> syn::Ident {
|
||||
syn::Ident::new(name, proc_macro2::Span::call_site())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn replacing_nested_type_params_works() {
|
||||
// Original path, replacement ident->paths, expected output path
|
||||
let paths = [
|
||||
// Works ok if nothing to replace
|
||||
(
|
||||
syn_path!(::some::path::Foo<::other::Path<A, B>>),
|
||||
vec![],
|
||||
syn_path!(::some::path::Foo<::other::Path<A, B>>),
|
||||
),
|
||||
// Simple top level replacing
|
||||
(
|
||||
syn_path!(::some::path::Foo<A>),
|
||||
vec![(ident("A"), type_path!(::new::Value))],
|
||||
syn_path!(::some::path::Foo<::new::Value>),
|
||||
),
|
||||
// More deeply nested replacing works too
|
||||
(
|
||||
syn_path!(::some::path::Foo<::other::Path<A, B>>),
|
||||
vec![(ident("A"), type_path!(::new::Value))],
|
||||
syn_path!(::some::path::Foo<::other::Path<::new::Value, B>>),
|
||||
),
|
||||
(
|
||||
syn_path!(::some::path::Foo<::other::Path<A, B>>),
|
||||
vec![
|
||||
(ident("A"), type_path!(::new::A)),
|
||||
(ident("B"), type_path!(::new::B)),
|
||||
],
|
||||
syn_path!(::some::path::Foo<::other::Path<::new::A, ::new::B>>),
|
||||
),
|
||||
(
|
||||
syn_path!(::some::path::Foo<::other::Path<A, ::more::path::to<::something::Argh<B>>>, C>),
|
||||
vec![
|
||||
(ident("A"), type_path!(::new::A)),
|
||||
(ident("B"), type_path!(::new::B)),
|
||||
],
|
||||
syn_path!(::some::path::Foo<::other::Path<::new::A, ::more::path::to<::something::Argh<::new::B>>>,C>),
|
||||
),
|
||||
// The same ident will be replaced as many times as needed:
|
||||
(
|
||||
syn_path!(::some::path::Foo<::other::Path<A, ::foo::Argh<A, B>, A>>),
|
||||
vec![(ident("A"), type_path!(::new::Value))],
|
||||
syn_path!(::some::path::Foo<::other::Path<::new::Value, ::foo::Argh<::new::Value, B>, ::new::Value>>),
|
||||
),
|
||||
];
|
||||
|
||||
for (mut path, replacements, expected) in paths {
|
||||
replace_path_params_recursively(&mut path, &replacements);
|
||||
assert_eq!(path, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use crate::error::CodegenError;
|
||||
|
||||
use super::{
|
||||
CompositeDef, CompositeDefFields, Derives, TypeDefParameters, TypeGenerator, TypeParameter,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use scale_info::{form::PortableForm, Type, TypeDef};
|
||||
use syn::parse_quote;
|
||||
|
||||
/// Generates a Rust `struct` or `enum` definition based on the supplied [`scale-info::Type`].
|
||||
///
|
||||
/// Field type paths are resolved via the `TypeGenerator`, which contains the registry of all
|
||||
/// generated types in the module.
|
||||
#[derive(Debug)]
|
||||
pub struct TypeDefGen {
|
||||
/// The type parameters of the type to be generated
|
||||
type_params: TypeDefParameters,
|
||||
/// The derives with which to annotate the generated type.
|
||||
derives: Derives,
|
||||
/// The kind of type to be generated.
|
||||
ty_kind: TypeDefGenKind,
|
||||
/// Type documentation.
|
||||
ty_docs: TokenStream,
|
||||
}
|
||||
|
||||
impl TypeDefGen {
|
||||
/// Construct a type definition for codegen from the given [`scale_info::Type`].
|
||||
pub fn from_type(
|
||||
ty: &Type<PortableForm>,
|
||||
type_gen: &TypeGenerator,
|
||||
) -> Result<Self, CodegenError> {
|
||||
let derives = type_gen.type_derives(ty)?;
|
||||
let crate_path = type_gen.crate_path();
|
||||
let should_gen_docs = type_gen.should_gen_docs();
|
||||
|
||||
let type_params = ty
|
||||
.type_params
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, tp)| match &tp.ty {
|
||||
Some(ty) => {
|
||||
let tp_name = format_ident!("_{}", i);
|
||||
Some(TypeParameter {
|
||||
concrete_type_id: ty.id,
|
||||
original_name: tp.name.clone(),
|
||||
name: tp_name,
|
||||
})
|
||||
}
|
||||
None => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut type_params = TypeDefParameters::new(type_params);
|
||||
|
||||
let ty_kind = match &ty.type_def {
|
||||
TypeDef::Composite(composite) => {
|
||||
let type_name = ty.path.ident().expect("structs should have a name");
|
||||
let fields = CompositeDefFields::from_scale_info_fields(
|
||||
&type_name,
|
||||
&composite.fields,
|
||||
type_params.params(),
|
||||
type_gen,
|
||||
)?;
|
||||
type_params.update_unused(fields.field_types());
|
||||
let docs = should_gen_docs.then_some(&*ty.docs).unwrap_or_default();
|
||||
let composite_def = CompositeDef::struct_def(
|
||||
ty,
|
||||
&type_name,
|
||||
type_params.clone(),
|
||||
fields,
|
||||
Some(parse_quote!(pub)),
|
||||
type_gen,
|
||||
docs,
|
||||
crate_path,
|
||||
None,
|
||||
)?;
|
||||
TypeDefGenKind::Struct(composite_def)
|
||||
}
|
||||
TypeDef::Variant(variant) => {
|
||||
let type_name = ty.path.ident().expect("variants should have a name");
|
||||
|
||||
let variants = variant
|
||||
.variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let fields = CompositeDefFields::from_scale_info_fields(
|
||||
&v.name,
|
||||
&v.fields,
|
||||
type_params.params(),
|
||||
type_gen,
|
||||
)?;
|
||||
type_params.update_unused(fields.field_types());
|
||||
let docs = should_gen_docs.then_some(&*v.docs).unwrap_or_default();
|
||||
let variant_def = CompositeDef::enum_variant_def(&v.name, fields, docs);
|
||||
Ok((v.index, variant_def))
|
||||
})
|
||||
.collect::<Result<Vec<_>, CodegenError>>()?;
|
||||
|
||||
TypeDefGenKind::Enum(type_name, variants)
|
||||
}
|
||||
_ => TypeDefGenKind::BuiltIn,
|
||||
};
|
||||
|
||||
let docs = &ty.docs;
|
||||
let ty_docs = should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(Self {
|
||||
type_params,
|
||||
derives,
|
||||
ty_kind,
|
||||
ty_docs,
|
||||
})
|
||||
}
|
||||
|
||||
/// are there unused type params?
|
||||
pub fn has_unused_type_params(&self) -> bool {
|
||||
self.type_params.has_unused_type_params()
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for TypeDefGen {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match &self.ty_kind {
|
||||
TypeDefGenKind::Struct(composite) => composite.to_tokens(tokens),
|
||||
TypeDefGenKind::Enum(type_name, variants) => {
|
||||
let mut variants = variants
|
||||
.iter()
|
||||
.map(|(index, def)| {
|
||||
let index = proc_macro2::Literal::u8_unsuffixed(*index);
|
||||
quote! {
|
||||
#[codec(index = #index)]
|
||||
#def
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(phantom) = self.type_params.unused_params_phantom_data() {
|
||||
variants.push(quote! {
|
||||
__Ignore(#phantom)
|
||||
})
|
||||
}
|
||||
|
||||
let enum_ident = format_ident!("{}", type_name);
|
||||
let type_params = &self.type_params;
|
||||
let derives = &self.derives;
|
||||
let docs = &self.ty_docs;
|
||||
let ty_toks = quote! {
|
||||
#derives
|
||||
#docs
|
||||
pub enum #enum_ident #type_params {
|
||||
#( #variants, )*
|
||||
}
|
||||
};
|
||||
tokens.extend(ty_toks);
|
||||
}
|
||||
TypeDefGenKind::BuiltIn => (), /* all built-in types should already be in scope */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug)]
|
||||
pub enum TypeDefGenKind {
|
||||
Struct(CompositeDef),
|
||||
Enum(String, Vec<(u8, CompositeDef)>),
|
||||
BuiltIn,
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use super::TypeParameter;
|
||||
use crate::types::CompositeDefFieldType;
|
||||
use quote::quote;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
/// Represents the set of generic type parameters for generating a type definition e.g. the `T` in
|
||||
/// `Foo<T>`.
|
||||
///
|
||||
/// Additionally this allows generating a `PhantomData` type for any type params which are unused
|
||||
/// in the type definition itself.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TypeDefParameters {
|
||||
params: Vec<TypeParameter>,
|
||||
unused: BTreeSet<TypeParameter>,
|
||||
}
|
||||
|
||||
impl TypeDefParameters {
|
||||
/// Create a new [`TypeDefParameters`] instance.
|
||||
pub fn new(params: Vec<TypeParameter>) -> Self {
|
||||
let unused = params.iter().cloned().collect();
|
||||
Self { params, unused }
|
||||
}
|
||||
|
||||
/// Update the set of unused type parameters by removing those that are used in the given
|
||||
/// fields.
|
||||
pub fn update_unused<'a>(&mut self, fields: impl Iterator<Item = &'a CompositeDefFieldType>) {
|
||||
let mut used_type_params = BTreeSet::new();
|
||||
for field in fields {
|
||||
field.type_path.parent_type_params(&mut used_type_params)
|
||||
}
|
||||
for used_type_param in &used_type_params {
|
||||
self.unused.remove(used_type_param);
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a [`core::marker::PhantomData`] for the type unused type params.
|
||||
pub fn unused_params_phantom_data(&self) -> Option<syn::TypePath> {
|
||||
if self.unused.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let params = if self.unused.len() == 1 {
|
||||
let param = self
|
||||
.unused
|
||||
.iter()
|
||||
.next()
|
||||
.expect("Checked for exactly one unused param");
|
||||
quote! { #param }
|
||||
} else {
|
||||
let params = self.unused.iter();
|
||||
quote! { ( #( #params ), * ) }
|
||||
};
|
||||
Some(syn::parse_quote! { ::core::marker::PhantomData<#params> })
|
||||
}
|
||||
|
||||
/// Returns the set of type parameters.
|
||||
pub fn params(&self) -> &[TypeParameter] {
|
||||
&self.params
|
||||
}
|
||||
|
||||
/// Returns true if there are any unused type params
|
||||
pub fn has_unused_type_params(&self) -> bool {
|
||||
!self.unused.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl quote::ToTokens for TypeDefParameters {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
if !self.params.is_empty() {
|
||||
let params = &self.params;
|
||||
tokens.extend(quote! { < #( #params ),* > })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
||||
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
||||
// see LICENSE for license details.
|
||||
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::format_ident;
|
||||
use scale_info::{form::PortableForm, Path, TypeDefPrimitive};
|
||||
use std::collections::BTreeSet;
|
||||
use syn::parse_quote;
|
||||
|
||||
/// An opaque struct representing a type path. The main usage of this is
|
||||
/// to spit out as tokens in some `quote!{ ... }` macro; the inner structure
|
||||
/// should be unimportant.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TypePath(TypePathInner);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TypePathInner {
|
||||
Parameter(TypeParameter),
|
||||
Type(TypePathType),
|
||||
}
|
||||
|
||||
impl quote::ToTokens for TypePath {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let syn_type = self.to_syn_type();
|
||||
syn_type.to_tokens(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
impl TypePath {
|
||||
/// Construct a [`TypePath`] from a [`TypeParameter`]
|
||||
pub fn from_parameter(param: TypeParameter) -> TypePath {
|
||||
TypePath(TypePathInner::Parameter(param))
|
||||
}
|
||||
|
||||
/// Construct a [`TypePath`] from a [`TypeParameter`]
|
||||
pub fn from_type(ty: TypePathType) -> TypePath {
|
||||
TypePath(TypePathInner::Type(ty))
|
||||
}
|
||||
|
||||
/// Construct a [`TypePath`] from a [`syn::TypePath`]
|
||||
pub fn from_syn_path(path: syn::Path) -> TypePath {
|
||||
// Note; this doesn't parse the parameters or anything, but since nothing external
|
||||
// can inspect this structure, and the ToTokens impl works either way, it should be ok.
|
||||
TypePath(TypePathInner::Type(TypePathType::Path {
|
||||
path,
|
||||
params: Vec::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn to_syn_type(&self) -> syn::Type {
|
||||
match &self.0 {
|
||||
TypePathInner::Parameter(ty_param) => syn::Type::Path(parse_quote! { #ty_param }),
|
||||
TypePathInner::Type(ty) => ty.to_syn_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_compact(&self) -> bool {
|
||||
matches!(&self.0, TypePathInner::Type(ty) if ty.is_compact())
|
||||
}
|
||||
|
||||
pub(crate) fn is_string(&self) -> bool {
|
||||
matches!(&self.0, TypePathInner::Type(ty) if ty.is_string())
|
||||
}
|
||||
|
||||
/// Returns the type parameters in a path which are inherited from the containing type.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// struct S<T> {
|
||||
/// a: Vec<Option<T>>, // the parent type param here is `T`
|
||||
/// }
|
||||
/// ```
|
||||
pub fn parent_type_params(&self, acc: &mut BTreeSet<TypeParameter>) {
|
||||
match &self.0 {
|
||||
TypePathInner::Parameter(type_parameter) => {
|
||||
acc.insert(type_parameter.clone());
|
||||
}
|
||||
TypePathInner::Type(type_path) => type_path.parent_type_params(acc),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the vector type parameter if the data is represented as `TypeDef::Sequence`.
|
||||
///
|
||||
/// **Note:** Utilized for transforming `std::vec::Vec<T>` into slices `&[T]` for the storage API.
|
||||
pub fn vec_type_param(&self) -> Option<&TypePath> {
|
||||
let ty = match &self.0 {
|
||||
TypePathInner::Type(ty) => ty,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
match ty {
|
||||
TypePathType::Vec { of } => Some(of),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TypePathType {
|
||||
Path {
|
||||
path: syn::Path,
|
||||
params: Vec<TypePath>,
|
||||
},
|
||||
Vec {
|
||||
of: Box<TypePath>,
|
||||
},
|
||||
Array {
|
||||
len: usize,
|
||||
of: Box<TypePath>,
|
||||
},
|
||||
Tuple {
|
||||
elements: Vec<TypePath>,
|
||||
},
|
||||
Primitive {
|
||||
def: TypeDefPrimitive,
|
||||
},
|
||||
Compact {
|
||||
inner: Box<TypePath>,
|
||||
is_field: bool,
|
||||
crate_path: syn::Path,
|
||||
},
|
||||
BitVec {
|
||||
bit_order_type: Box<TypePath>,
|
||||
bit_store_type: Box<TypePath>,
|
||||
crate_path: syn::Path,
|
||||
},
|
||||
}
|
||||
|
||||
impl TypePathType {
|
||||
pub fn from_type_def_path(
|
||||
path: &Path<PortableForm>,
|
||||
root_mod_ident: Ident,
|
||||
params: Vec<TypePath>,
|
||||
) -> Self {
|
||||
let path_segments = &*path.segments;
|
||||
|
||||
let path: syn::Path = match path_segments {
|
||||
[] => panic!("Type has no ident"),
|
||||
[ident] => {
|
||||
// paths to prelude types
|
||||
match ident.as_str() {
|
||||
"Option" => parse_quote!(::core::option::Option),
|
||||
"Result" => parse_quote!(::core::result::Result),
|
||||
"Cow" => parse_quote!(::std::borrow::Cow),
|
||||
"BTreeMap" => parse_quote!(::std::collections::BTreeMap),
|
||||
"BTreeSet" => parse_quote!(::std::collections::BTreeSet),
|
||||
"Range" => parse_quote!(::core::ops::Range),
|
||||
"RangeInclusive" => parse_quote!(::core::ops::RangeInclusive),
|
||||
"NonZeroI8" => parse_quote!(::core::num::NonZeroI8),
|
||||
"NonZeroU8" => parse_quote!(::core::num::NonZeroU8),
|
||||
"NonZeroI16" => parse_quote!(::core::num::NonZeroI16),
|
||||
"NonZeroU16" => parse_quote!(::core::num::NonZeroU16),
|
||||
"NonZeroI32" => parse_quote!(::core::num::NonZeroI32),
|
||||
"NonZeroU32" => parse_quote!(::core::num::NonZeroU32),
|
||||
"NonZeroI64" => parse_quote!(::core::num::NonZeroI64),
|
||||
"NonZeroU64" => parse_quote!(::core::num::NonZeroU64),
|
||||
"NonZeroI128" => parse_quote!(::core::num::NonZeroI128),
|
||||
"NonZeroU128" => parse_quote!(::core::num::NonZeroU128),
|
||||
"NonZeroIsize" => parse_quote!(::core::num::NonZeroIsize),
|
||||
"NonZeroUsize" => parse_quote!(::core::num::NonZeroUsize),
|
||||
ident => panic!("Unknown prelude type '{ident}'"),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// paths to generated types in the root types module
|
||||
let mut ty_path = path_segments
|
||||
.iter()
|
||||
.map(|s| syn::PathSegment::from(format_ident!("{}", s)))
|
||||
.collect::<syn::punctuated::Punctuated<syn::PathSegment, syn::Token![::]>>();
|
||||
ty_path.insert(0, syn::PathSegment::from(root_mod_ident));
|
||||
parse_quote!( #ty_path )
|
||||
}
|
||||
};
|
||||
Self::Path { path, params }
|
||||
}
|
||||
|
||||
/// Visits a type path, collecting all the generic type parameters from the containing type.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// struct S<T> {
|
||||
/// a: Vec<Option<T>>, // the parent type param here is `T`
|
||||
/// }
|
||||
/// ```
|
||||
fn parent_type_params(&self, acc: &mut BTreeSet<TypeParameter>) {
|
||||
match self {
|
||||
TypePathType::Path { params, .. } => {
|
||||
for p in params {
|
||||
p.parent_type_params(acc)
|
||||
}
|
||||
}
|
||||
TypePathType::Vec { of } => of.parent_type_params(acc),
|
||||
TypePathType::Array { of, .. } => of.parent_type_params(acc),
|
||||
TypePathType::Tuple { elements } => {
|
||||
for e in elements {
|
||||
e.parent_type_params(acc)
|
||||
}
|
||||
}
|
||||
TypePathType::Primitive { .. } => (),
|
||||
TypePathType::Compact { inner, .. } => inner.parent_type_params(acc),
|
||||
TypePathType::BitVec {
|
||||
bit_order_type,
|
||||
bit_store_type,
|
||||
crate_path: _,
|
||||
} => {
|
||||
bit_order_type.parent_type_params(acc);
|
||||
bit_store_type.parent_type_params(acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_compact(&self) -> bool {
|
||||
matches!(self, TypePathType::Compact { .. })
|
||||
}
|
||||
|
||||
pub(crate) fn is_string(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
TypePathType::Primitive {
|
||||
def: TypeDefPrimitive::Str
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn to_syn_type(&self) -> syn::Type {
|
||||
match &self {
|
||||
TypePathType::Path { path, params } => {
|
||||
let path = if params.is_empty() {
|
||||
parse_quote! { #path }
|
||||
} else {
|
||||
parse_quote! { #path< #( #params ),* > }
|
||||
};
|
||||
syn::Type::Path(path)
|
||||
}
|
||||
TypePathType::Vec { of } => {
|
||||
let type_path = parse_quote! { ::std::vec::Vec<#of> };
|
||||
syn::Type::Path(type_path)
|
||||
}
|
||||
TypePathType::Array { len, of } => {
|
||||
let array = parse_quote! { [#of; #len] };
|
||||
syn::Type::Array(array)
|
||||
}
|
||||
TypePathType::Tuple { elements } => {
|
||||
let tuple = parse_quote! { (#( # elements, )* ) };
|
||||
syn::Type::Tuple(tuple)
|
||||
}
|
||||
TypePathType::Primitive { def } => syn::Type::Path(match def {
|
||||
TypeDefPrimitive::Bool => parse_quote!(::core::primitive::bool),
|
||||
TypeDefPrimitive::Char => parse_quote!(::core::primitive::char),
|
||||
TypeDefPrimitive::Str => parse_quote!(::std::string::String),
|
||||
TypeDefPrimitive::U8 => parse_quote!(::core::primitive::u8),
|
||||
TypeDefPrimitive::U16 => parse_quote!(::core::primitive::u16),
|
||||
TypeDefPrimitive::U32 => parse_quote!(::core::primitive::u32),
|
||||
TypeDefPrimitive::U64 => parse_quote!(::core::primitive::u64),
|
||||
TypeDefPrimitive::U128 => parse_quote!(::core::primitive::u128),
|
||||
TypeDefPrimitive::U256 => unimplemented!("not a rust primitive"),
|
||||
TypeDefPrimitive::I8 => parse_quote!(::core::primitive::i8),
|
||||
TypeDefPrimitive::I16 => parse_quote!(::core::primitive::i16),
|
||||
TypeDefPrimitive::I32 => parse_quote!(::core::primitive::i32),
|
||||
TypeDefPrimitive::I64 => parse_quote!(::core::primitive::i64),
|
||||
TypeDefPrimitive::I128 => parse_quote!(::core::primitive::i128),
|
||||
TypeDefPrimitive::I256 => unimplemented!("not a rust primitive"),
|
||||
}),
|
||||
TypePathType::Compact {
|
||||
inner,
|
||||
is_field,
|
||||
crate_path,
|
||||
} => {
|
||||
let path = if *is_field {
|
||||
// compact fields can use the inner compact type directly and be annotated with
|
||||
// the `compact` attribute e.g. `#[codec(compact)] my_compact_field: u128`
|
||||
parse_quote! ( #inner )
|
||||
} else {
|
||||
parse_quote! ( #crate_path::ext::codec::Compact<#inner> )
|
||||
};
|
||||
syn::Type::Path(path)
|
||||
}
|
||||
TypePathType::BitVec {
|
||||
bit_order_type,
|
||||
bit_store_type,
|
||||
crate_path,
|
||||
} => {
|
||||
let type_path = parse_quote! { #crate_path::utils::bits::DecodedBits<#bit_store_type, #bit_order_type> };
|
||||
syn::Type::Path(type_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct TypeParameter {
|
||||
pub(super) concrete_type_id: u32,
|
||||
pub(super) original_name: String,
|
||||
pub(super) name: Ident,
|
||||
}
|
||||
|
||||
impl quote::ToTokens for TypeParameter {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.name.to_tokens(tokens)
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -61,12 +61,16 @@ struct RuntimeMetadataArgs {
|
||||
struct DeriveForType {
|
||||
path: syn::TypePath,
|
||||
derive: Punctuated<syn::Path, syn::Token![,]>,
|
||||
#[darling(default)]
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromMeta)]
|
||||
struct AttributesForType {
|
||||
path: syn::TypePath,
|
||||
attributes: Punctuated<OuterAttribute, syn::Token![,]>,
|
||||
#[darling(default)]
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromMeta)]
|
||||
@@ -123,7 +127,7 @@ pub fn subxt(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
.collect(),
|
||||
);
|
||||
for d in args.derive_for_type {
|
||||
codegen.add_derives_for_type(d.path, d.derive.into_iter());
|
||||
codegen.add_derives_for_type(d.path, d.derive.into_iter(), d.recursive);
|
||||
}
|
||||
|
||||
// Configure attributes:
|
||||
@@ -135,7 +139,7 @@ pub fn subxt(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
.collect(),
|
||||
);
|
||||
for d in args.attributes_for_type {
|
||||
codegen.add_attributes_for_type(d.path, d.attributes.into_iter().map(|a| a.0))
|
||||
codegen.add_attributes_for_type(d.path, d.attributes.into_iter().map(|a| a.0), d.recursive)
|
||||
}
|
||||
|
||||
// Insert type substitutions:
|
||||
|
||||
@@ -6,15 +6,10 @@ use subxt_signer::sr25519::dev;
|
||||
|
||||
#[subxt::subxt(
|
||||
runtime_metadata_path = "../artifacts/polkadot_metadata_full.scale",
|
||||
derive_for_type(path = "xcm::v2::multilocation::MultiLocation", derive = "Clone"),
|
||||
derive_for_type(path = "xcm::v2::multilocation::Junctions", derive = "Clone"),
|
||||
derive_for_type(path = "xcm::v2::junction::Junction", derive = "Clone"),
|
||||
derive_for_type(path = "xcm::v2::NetworkId", derive = "Clone"),
|
||||
derive_for_type(path = "xcm::v2::BodyId", derive = "Clone"),
|
||||
derive_for_type(path = "xcm::v2::BodyPart", derive = "Clone"),
|
||||
derive_for_type(
|
||||
path = "bounded_collections::weak_bounded_vec::WeakBoundedVec",
|
||||
derive = "Clone"
|
||||
path = "xcm::v2::multilocation::MultiLocation",
|
||||
derive = "Clone",
|
||||
recursive
|
||||
)
|
||||
)]
|
||||
pub mod runtime {}
|
||||
|
||||
@@ -213,7 +213,7 @@ impl ModuleError {
|
||||
|
||||
/// Details about the module error.
|
||||
pub struct ModuleErrorDetails<'a> {
|
||||
/// The pallet that the error came from
|
||||
/// The pallet that the error is in
|
||||
pub pallet: crate::metadata::types::PalletMetadata<'a>,
|
||||
/// The variant representing the error
|
||||
pub variant: &'a scale_info::Variant<scale_info::form::PortableForm>,
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ pub mod ext {
|
||||
/// ```
|
||||
///
|
||||
/// The `subxt` macro will populate the annotated module with all of the methods and types required
|
||||
/// for interacting with the runtime that the metadata came from via Subxt.
|
||||
/// for interacting with the runtime that the metadata is in via Subxt.
|
||||
///
|
||||
/// # Configuration
|
||||
///
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
error: Type substitution error: `substitute_type(with = <path>)` must be a path prefixed with 'crate::' or '::'
|
||||
error: Type Generation failed: Type substitution error: `substitute_type(with = <path>)` must be a path prefixed with 'crate::' or '::'
|
||||
--> src/incorrect/substitute_path_not_absolute.rs:5:16
|
||||
|
|
||||
5 | with = "sp_runtime::Perbill"
|
||||
|
||||
Reference in New Issue
Block a user