diff --git a/Cargo.lock b/Cargo.lock index afc846c84..9019e3fe2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "auditable-serde" @@ -93,9 +93,9 @@ checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bitmaps" @@ -108,15 +108,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" @@ -126,9 +126,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.54" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "codegen-macro" @@ -201,9 +201,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", "regex", @@ -211,9 +211,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", @@ -252,9 +252,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -289,9 +289,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -314,15 +314,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -331,15 +331,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -348,21 +348,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -372,7 +372,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -551,9 +550,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jiff" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +checksum = "b3e3d65f018c6ae946ab16e80944b97096ed73c35b221d1c478a6c81d8f57940" dependencies = [ "jiff-static", "log", @@ -564,9 +563,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +checksum = "a17c2b211d863c7fde02cbea8a3c1a439b98e109286554f2860bdded7ff83818" dependencies = [ "proc-macro2", "quote", @@ -587,9 +586,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libtest-mimic" @@ -605,9 +604,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -656,9 +655,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miette" @@ -717,27 +716,21 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" dependencies = [ "portable-atomic", ] @@ -763,9 +756,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -783,9 +776,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -807,9 +800,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -819,9 +812,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -830,9 +823,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rustc-std-workspace-alloc" @@ -848,9 +841,9 @@ checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955" [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", @@ -861,9 +854,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "semver" @@ -958,9 +951,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -991,9 +984,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1123,9 +1116,9 @@ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-width" @@ -1153,9 +1146,9 @@ checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -1244,8 +1237,7 @@ checksum = "6545ca20bba2f220430c4a97f6b60c48ef14eaa432b04e6b31be547037b4c9ab" [[package]] name = "wasm-compose" version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd23d12cc95c451c1306db5bc63075fbebb612bb70c53b4237b1ce5bc178343" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "anyhow", "heck", @@ -1275,8 +1267,7 @@ dependencies = [ [[package]] name = "wasm-encoder" version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "leb128fmt", "wasmparser 0.245.1", @@ -1304,8 +1295,7 @@ dependencies = [ [[package]] name = "wasm-metadata" version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da55e60097e8b37b475a0fa35c3420dd71d9eb7bd66109978ab55faf56a57efb" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "anyhow", "indexmap", @@ -1329,8 +1319,7 @@ dependencies = [ [[package]] name = "wasmparser" version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "bitflags", "hashbrown 0.16.1", @@ -1342,8 +1331,7 @@ dependencies = [ [[package]] name = "wast" version = "245.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "bumpalo", "leb128fmt", @@ -1355,8 +1343,7 @@ dependencies = [ [[package]] name = "wat" version = "1.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "wast", ] @@ -1641,8 +1628,7 @@ dependencies = [ [[package]] name = "wit-component" version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4894f10d2d5cbc17c77e91f86a1e48e191a788da4425293b55c98b44ba3fcac9" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "anyhow", "bitflags", @@ -1661,8 +1647,7 @@ dependencies = [ [[package]] name = "wit-parser" version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330698718e82983499419494dd1e3d7811a457a9bf9f69734e8c5f07a2547929" +source = "git+https://github.com/ricochet/wasm-tools.git?branch=wasmparser-implements#6944e34563bdc5f320cb83e1e224967fd09648fd" dependencies = [ "anyhow", "hashbrown 0.16.1", @@ -1762,6 +1747,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.12" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 86e224127..e56c2b747 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,13 +46,13 @@ prettyplease = "0.2.20" syn = { version = "2.0.89", features = ["printing"] } futures = "0.3.31" -wat = "1.245.1" -wasmparser = "0.245.1" -wasm-encoder = "0.245.1" -wasm-metadata = { version = "0.245.1", default-features = false } -wit-parser = "0.245.1" -wit-component = "0.245.1" -wasm-compose = "0.245.1" +wat = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" } +wasmparser = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" } +wasm-encoder = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" } +wasm-metadata = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements", default-features = false } +wit-parser = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" } +wit-component = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" } +wasm-compose = { git = "https://github.com/ricochet/wasm-tools.git", branch = "wasmparser-implements" } wit-bindgen-core = { path = 'crates/core', version = '0.53.1' } wit-bindgen-c = { path = 'crates/c', version = '0.53.1' } diff --git a/crates/c/src/lib.rs b/crates/c/src/lib.rs index 2d53d23dd..5007cf605 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -211,18 +211,27 @@ impl WorldGenerator for C { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> Result<()> { - let wasm_import_module = resolve.name_world_key(name); + let wasm_import_module = + wit_bindgen_core::wasm_import_module_name(resolve, name, implements); let mut r#gen = self.interface(resolve, true, Some(&wasm_import_module)); r#gen.interface = Some((id, name)); + r#gen.implements = implements; r#gen.define_interface_types(id); for (i, (_name, func)) in resolve.interfaces[id].functions.iter().enumerate() { if i == 0 { - let name = resolve.name_world_key(name); - uwriteln!(r#gen.src.h_fns, "\n// Imported Functions from `{name}`"); - uwriteln!(r#gen.src.c_fns, "\n// Imported Functions from `{name}`"); + let display_name = resolve.name_world_key(name); + uwriteln!( + r#gen.src.h_fns, + "\n// Imported Functions from `{display_name}`" + ); + uwriteln!( + r#gen.src.c_fns, + "\n// Imported Functions from `{display_name}`" + ); } r#gen.import(Some(name), func); } @@ -259,17 +268,25 @@ impl WorldGenerator for C { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> Result<()> { let mut r#gen = self.interface(resolve, false, None); r#gen.interface = Some((id, name)); + r#gen.implements = implements; r#gen.define_interface_types(id); for (i, (_name, func)) in resolve.interfaces[id].functions.iter().enumerate() { if i == 0 { - let name = resolve.name_world_key(name); - uwriteln!(r#gen.src.h_fns, "\n// Exported Functions from `{name}`"); - uwriteln!(r#gen.src.c_fns, "\n// Exported Functions from `{name}`"); + let display_name = resolve.name_world_key(name); + uwriteln!( + r#gen.src.h_fns, + "\n// Exported Functions from `{display_name}`" + ); + uwriteln!( + r#gen.src.c_fns, + "\n// Exported Functions from `{display_name}`" + ); } r#gen.export(func, Some(name)); } @@ -601,6 +618,7 @@ impl C { interface: None, in_import, wasm_import_module, + implements: None, } } @@ -1297,6 +1315,7 @@ struct InterfaceGenerator<'a> { resolve: &'a Resolve, interface: Option<(InterfaceId, &'a WorldKey)>, wasm_import_module: Option<&'a str>, + implements: Option, } impl C { @@ -1893,6 +1912,10 @@ pub fn gen_type_name(resolve: &Resolve, ty: TypeId) -> (CTypeNameInfo<'_>, Strin } impl InterfaceGenerator<'_> { + fn wasm_name_world_key(&self, key: &WorldKey) -> String { + wit_bindgen_core::wasm_import_module_name(self.resolve, key, self.implements) + } + fn define_interface_types(&mut self, id: InterfaceId) { let mut live = LiveTypes::default(); live.add_interface(self.resolve, id); @@ -2122,7 +2145,7 @@ impl InterfaceGenerator<'_> { self.src.c_fns, "__attribute__((__import_module__(\"{}\"), __import_name__(\"{import_prefix}{}\")))", match interface_name { - Some(name) => self.resolve.name_world_key(name), + Some(name) => self.wasm_name_world_key(name), None => "$root".to_string(), }, func.name @@ -2282,7 +2305,7 @@ impl InterfaceGenerator<'_> { self.src.c_fns("\n"); - let core_module_name = interface_name.map(|s| self.resolve.name_world_key(s)); + let core_module_name = interface_name.map(|s| self.wasm_name_world_key(s)); let export_name = func.legacy_core_export_name(core_module_name.as_deref()); // Print the actual header for this function into the header file, and @@ -2368,7 +2391,7 @@ impl InterfaceGenerator<'_> { ); uwriteln!(self.src.h_helpers, "void {name}_return({return_ty});"); let import_module = match interface_name { - Some(name) => self.resolve.name_world_key(name), + Some(name) => self.wasm_name_world_key(name), None => "$root".to_string(), }; uwriteln!( @@ -2755,7 +2778,7 @@ void {name}_return({return_ty}) {{ let module = format!( "{prefix}{}", interface - .map(|name| self.resolve.name_world_key(name)) + .map(|name| self.wasm_name_world_key(name)) .unwrap_or_else(|| "$root".into()) ); for (index, ty) in func diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 15a2ad824..0b25ed868 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -22,6 +22,28 @@ pub enum Direction { Export, } +/// Compute the wasm-level import/export module name for an interface, +/// accounting for `implements` items. +/// +/// For `implements` items, this produces the `[implements=]label` encoding +/// required by the component model binary format. Otherwise delegates to +/// `resolve.name_world_key(name)`. +pub fn wasm_import_module_name( + resolve: &Resolve, + name: &WorldKey, + implements: Option, +) -> String { + match (name, implements) { + (WorldKey::Name(label), Some(impl_id)) => { + let iface_name = resolve + .id_of(impl_id) + .expect("unexpected anonymous interface"); + format!("[implements=<{iface_name}>]{label}") + } + _ => resolve.name_world_key(name), + } +} + pub trait WorldGenerator { fn generate(&mut self, resolve: &mut Resolve, id: WorldId, files: &mut Files) -> Result<()> { if self.uses_nominal_type_ids() { @@ -42,8 +64,8 @@ pub trait WorldGenerator { for (name, import) in world.imports.iter() { match import { WorldItem::Function(f) => funcs.push((unwrap_name(name), f)), - WorldItem::Interface { id, .. } => { - self.import_interface(resolve, name, *id, files)? + WorldItem::Interface { id, implements, .. } => { + self.import_interface(resolve, name, *id, *implements, files)? } WorldItem::Type { id, .. } => types.push((unwrap_name(name), *id)), } @@ -68,7 +90,9 @@ pub trait WorldGenerator { for (name, export) in world.exports.iter() { match export { WorldItem::Function(f) => funcs.push((unwrap_name(name), f)), - WorldItem::Interface { id, .. } => interfaces.push((name, id)), + WorldItem::Interface { id, implements, .. } => { + interfaces.push((name, id, implements)) + } WorldItem::Type { .. } => unreachable!(), } } @@ -78,8 +102,8 @@ pub trait WorldGenerator { self.pre_export_interface(resolve, files)?; - for (name, id) in interfaces { - self.export_interface(resolve, name, *id, files)?; + for (name, id, implements) in interfaces { + self.export_interface(resolve, name, *id, *implements, files)?; } self.finish(resolve, id, files) } @@ -104,6 +128,7 @@ pub trait WorldGenerator { resolve: &Resolve, name: &WorldKey, iface: InterfaceId, + implements: Option, files: &mut Files, ) -> Result<()>; @@ -118,6 +143,7 @@ pub trait WorldGenerator { resolve: &Resolve, name: &WorldKey, iface: InterfaceId, + implements: Option, files: &mut Files, ) -> Result<()>; fn import_funcs( diff --git a/crates/cpp/src/lib.rs b/crates/cpp/src/lib.rs index 271c4fe30..62e278388 100644 --- a/crates/cpp/src/lib.rs +++ b/crates/cpp/src/lib.rs @@ -108,6 +108,8 @@ struct Cpp { // needed for symmetric disambiguation interface_prefixes: HashMap<(Direction, WorldKey), String>, import_prefix: Option, + /// Tracks InterfaceIds whose types have already been generated (for implements dedup). + implements_types_generated: HashSet, } #[cfg(feature = "clap")] @@ -330,6 +332,7 @@ impl Cpp { sizes, in_guest_import, wasm_import_module, + implements_label: None, } } @@ -513,6 +516,7 @@ impl WorldGenerator for Cpp { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> anyhow::Result<()> { self.imported_interfaces.insert(id); @@ -528,13 +532,19 @@ impl WorldGenerator for Cpp { } let store = self.start_new_file(None); - let wasm_import_module = resolve.name_world_key(name); + let wasm_import_module = + wit_bindgen_core::wasm_import_module_name(resolve, name, implements); let binding = Some(name); + let should_gen_types = self.implements_types_generated.insert(id); let mut r#gen = self.interface(resolve, binding, true, Some(wasm_import_module)); r#gen.interface = Some(id); - r#gen.types(id); - let namespace = - namespace(resolve, &TypeOwner::Interface(id), false, &r#gen.r#gen.opts); + if let (WorldKey::Name(label), Some(_)) = (name, implements) { + r#gen.implements_label = Some((label.clone(), false)); + } + if should_gen_types { + r#gen.types(id); + } + let namespace = r#gen.freestanding_namespace(id, false); for (_name, func) in resolve.interfaces[id].functions.iter() { if matches!(func.kind, FunctionKind::Freestanding) { @@ -564,6 +574,7 @@ impl WorldGenerator for Cpp { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> anyhow::Result<()> { let old_prefix = self.opts.export_prefix.clone(); @@ -579,12 +590,19 @@ impl WorldGenerator for Cpp { .src .push_str(&format!("// export_interface {name:?}\n")); self.imported_interfaces.remove(&id); - let wasm_import_module = resolve.name_world_key(name); + let wasm_import_module = + wit_bindgen_core::wasm_import_module_name(resolve, name, implements); let binding = Some(name); + let should_gen_types = self.implements_types_generated.insert(id); let mut r#gen = self.interface(resolve, binding, false, Some(wasm_import_module)); r#gen.interface = Some(id); - r#gen.types(id); - let namespace = namespace(resolve, &TypeOwner::Interface(id), true, &r#gen.r#gen.opts); + if let (WorldKey::Name(label), Some(_)) = (name, implements) { + r#gen.implements_label = Some((label.clone(), true)); + } + if should_gen_types { + r#gen.types(id); + } + let namespace = r#gen.freestanding_namespace(id, true); for (_name, func) in resolve.interfaces[id].functions.iter() { if matches!(func.kind, FunctionKind::Freestanding) { @@ -762,7 +780,6 @@ impl WorldGenerator for Cpp { } } -// determine namespace (for the lifted C++ function) fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, opts: &Opts) -> Vec { let mut result = Vec::default(); if let Some(prefix) = &opts.internal_prefix { @@ -850,9 +867,35 @@ struct CppInterfaceGenerator<'a> { sizes: SizeAlign, in_guest_import: bool, pub wasm_import_module: Option, + /// When generating for an implements item, the label and whether it's an export. + implements_label: Option<(String, bool)>, } impl CppInterfaceGenerator<'_> { + /// Compute the namespace for freestanding functions in an interface. + /// Uses `implements_label` when set, otherwise falls back to the standard + /// namespace computation. + fn freestanding_namespace(&self, iface: InterfaceId, guest_export: bool) -> Vec { + if let Some((label, is_export)) = &self.implements_label { + let mut ns = Vec::new(); + if let Some(prefix) = &self.r#gen.opts.internal_prefix { + ns.push(prefix.clone()); + } + if *is_export { + ns.push(String::from("exports")); + } + ns.push(to_c_ident(label)); + ns + } else { + namespace( + self.resolve, + &TypeOwner::Interface(iface), + guest_export, + &self.r#gen.opts, + ) + } + } + fn types(&mut self, iface: InterfaceId) { let iface_data = &self.resolve().interfaces[iface]; @@ -923,7 +966,20 @@ impl CppInterfaceGenerator<'_> { .map(TypeOwner::Interface) .unwrap_or(TypeOwner::World(self.r#gen.world_id.unwrap())), )); - let mut namespace = namespace(self.resolve, &owner, guest_export, &self.r#gen.opts); + let mut namespace = if let Some((label, is_export)) = &self.implements_label { + // For implements items, use the label as namespace + let mut ns = Vec::new(); + if let Some(prefix) = &self.r#gen.opts.internal_prefix { + ns.push(prefix.clone()); + } + if *is_export { + ns.push(String::from("exports")); + } + ns.push(to_c_ident(label)); + ns + } else { + namespace(self.resolve, &owner, guest_export, &self.r#gen.opts) + }; let is_drop = is_special_method(func); let func_name_h = if !matches!(&func.kind, FunctionKind::Freestanding) { namespace.push(object.clone()); diff --git a/crates/csharp/src/interface.rs b/crates/csharp/src/interface.rs index 9c9e982bc..17124b1a3 100644 --- a/crates/csharp/src/interface.rs +++ b/crates/csharp/src/interface.rs @@ -832,7 +832,8 @@ var {async_status_var} = {raw_name}({wasm_params}); let wasm_func_name = func.name.clone(); let interop_name = format!("wasmExport{}", wasm_func_name.to_upper_camel_case()); - let core_module_name = interface_key.map(|s| self.resolve.name_world_key(s)); + let core_module_name = + interface_key.map(|s| self.csharp_gen.wasm_name_world_key(self.resolve, s)); let export_name = func.legacy_core_export_name(core_module_name.as_deref()); let export_name = if async_ { @@ -935,7 +936,8 @@ var {async_status_var} = {raw_name}({wasm_params}); let (_import_module_prefix, import_module) = match interface_key { Some(world_key) => { - let interface_world = self.resolve.name_world_key(world_key); + let interface_world = + self.csharp_gen.wasm_name_world_key(self.resolve, world_key); (format!("{interface_world}#"), interface_world) } None => (String::new(), "$root".to_string()), @@ -1228,7 +1230,7 @@ var {async_status_var} = {raw_name}({wasm_params}); match self.direction { Direction::Import => { let module_name = key - .map(|key| self.resolve.name_world_key(key)) + .map(|key| self.csharp_gen.wasm_name_world_key(self.resolve, key)) .unwrap_or_else(|| "$root".into()); // As of this writing, we cannot safely drop a handle to an imported resource from a .NET finalizer @@ -1266,7 +1268,7 @@ var {async_status_var} = {raw_name}({wasm_params}); } Direction::Export => { let prefix = key - .map(|s| format!("{}#", self.resolve.name_world_key(s))) + .map(|s| format!("{}#", self.csharp_gen.wasm_name_world_key(self.resolve, s))) .unwrap_or_else(String::new); uwrite!( @@ -1284,7 +1286,12 @@ var {async_status_var} = {raw_name}({wasm_params}); ); let module_name = key - .map(|key| format!("[export]{}", self.resolve.name_world_key(key))) + .map(|key| { + format!( + "[export]{}", + self.csharp_gen.wasm_name_world_key(self.resolve, key) + ) + }) .unwrap_or_else(|| "[export]$root".into()); // The ergonomics of exported resources are not ideal, currently. Implementing such a resource diff --git a/crates/csharp/src/world_generator.rs b/crates/csharp/src/world_generator.rs index 05a9f9e58..4c119c9bd 100644 --- a/crates/csharp/src/world_generator.rs +++ b/crates/csharp/src/world_generator.rs @@ -45,9 +45,14 @@ pub struct CSharp { pub(crate) generated_future_types: HashSet, // Top level types that are bidirectional like enums, to save code size and not duplicate whene unnecessary. pub(crate) bidirectional_types_src: HashSet, + pub(crate) current_implements: Option, } impl CSharp { + pub(crate) fn wasm_name_world_key(&self, resolve: &Resolve, key: &WorldKey) -> String { + wit_bindgen_core::wasm_import_module_name(resolve, key, self.current_implements) + } + pub(crate) fn access_modifier(&self) -> &'static str { if self.opts.internal { "internal" @@ -153,10 +158,13 @@ impl WorldGenerator for CSharp { resolve: &Resolve, key: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> anyhow::Result<()> { + self.current_implements = implements; let name = interface_name(self, resolve, key, Direction::Import); self.interface_names.insert(id, name.clone()); + let import_module_name = self.wasm_name_world_key(resolve, key); let mut r#gen = self.interface(resolve, &name, Direction::Import, false); let mut old_resources = mem::take(&mut r#gen.csharp_gen.all_resources); @@ -164,7 +172,6 @@ impl WorldGenerator for CSharp { let new_resources = mem::take(&mut r#gen.csharp_gen.all_resources); old_resources.extend(new_resources.clone()); r#gen.csharp_gen.all_resources = old_resources; - let import_module_name = &resolve.name_world_key(key); for (resource, funcs) in by_resource( resolve.interfaces[id] .functions @@ -177,7 +184,7 @@ impl WorldGenerator for CSharp { } for func in funcs { - r#gen.import(import_module_name, func); + r#gen.import(&import_module_name, func); } if resource.is_some() { @@ -188,12 +195,13 @@ impl WorldGenerator for CSharp { // for anonymous types r#gen.define_interface_types(id); - r#gen.add_futures_or_streams(import_module_name, false, true); + r#gen.add_futures_or_streams(&import_module_name, false, true); - r#gen.add_futures_or_streams(import_module_name, false, false); + r#gen.add_futures_or_streams(&import_module_name, false, false); r#gen.add_interface_fragment(false); + self.current_implements = None; Ok(()) } @@ -236,10 +244,13 @@ impl WorldGenerator for CSharp { resolve: &Resolve, key: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> anyhow::Result<()> { + self.current_implements = implements; let name = interface_name(self, resolve, key, Direction::Export); self.interface_names.insert(id, name.clone()); + let import_module_name = self.wasm_name_world_key(resolve, key); let mut r#gen = self.interface(resolve, &name, Direction::Export, false); let mut old_resources = mem::take(&mut r#gen.csharp_gen.all_resources); @@ -270,12 +281,12 @@ impl WorldGenerator for CSharp { // for anonymous types r#gen.define_interface_types(id); - let import_module_name = &resolve.name_world_key(key); r#gen.add_futures_or_streams(&format!("[export]{import_module_name}"), true, true); r#gen.add_futures_or_streams(&format!("[export]{import_module_name}"), true, false); r#gen.add_interface_fragment(true); + self.current_implements = None; Ok(()) } diff --git a/crates/go/src/lib.rs b/crates/go/src/lib.rs index c8d01269c..e8c9abb98 100644 --- a/crates/go/src/lib.rs +++ b/crates/go/src/lib.rs @@ -206,9 +206,15 @@ struct Go { types: HashSet, resources: HashMap, futures_and_streams: HashMap<(TypeId, bool), Option>, + /// The current `implements` value being processed. + current_implements: Option, } impl Go { + fn wasm_name_world_key(&self, resolve: &Resolve, key: &WorldKey) -> String { + wit_bindgen_core::wasm_import_module_name(resolve, key, self.current_implements) + } + /// Adds the bindings module prefix to a package name. fn mod_pkg(&self, name: &str) -> String { let prefix = self.opts.pkg_name.as_deref().unwrap_or("wit_component"); @@ -397,7 +403,7 @@ impl Go { "{prefix}{}", interface .as_ref() - .map(|name| resolve.name_world_key(name)) + .map(|name| self.wasm_name_world_key(resolve, name)) .unwrap_or_else(|| "$root".into()) ); @@ -701,12 +707,15 @@ impl WorldGenerator for Go { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> Result<()> { if let WorldKey::Name(_) = name { self.interface_names.insert(id, name.clone()); } + self.current_implements = implements; + let mut data = { let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), true); for (name, ty) in resolve.interfaces[id].types.iter() { @@ -726,6 +735,7 @@ impl WorldGenerator for Go { .or_default() .extend(data); + self.current_implements = None; Ok(()) } @@ -751,12 +761,15 @@ impl WorldGenerator for Go { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> Result<()> { if let WorldKey::Name(_) = name { self.interface_names.insert(id, name.clone()); } + self.current_implements = implements; + for (type_name, ty) in &resolve.interfaces[id].types { let exported = matches!(resolve.types[*ty].kind, TypeDefKind::Resource) || self.has_exported_resource(resolve, Type::Id(*ty)); @@ -785,6 +798,7 @@ impl WorldGenerator for Go { self.src.push_str(&code); } + self.current_implements = None; Ok(()) } @@ -986,7 +1000,7 @@ impl Go { let (camel, has_self) = func_declaration(resolve, func); let module = match interface { - Some(name) => resolve.name_world_key(name), + Some(name) => self.wasm_name_world_key(resolve, name), None => "$root".to_string(), }; @@ -1205,7 +1219,7 @@ func {camel}({go_params}) {go_results} {{ }; let sig = resolve.wasm_signature(variant, func); - let core_module_name = interface.map(|v| resolve.name_world_key(v)); + let core_module_name = interface.map(|v| self.wasm_name_world_key(resolve, v)); let export_name = func.legacy_core_export_name(core_module_name.as_deref()); let name = func_name(resolve, interface, func); @@ -1256,7 +1270,7 @@ func {camel}({go_params}) {go_results} {{ self.imports.insert(remote_pkg("async")); let module = match interface { - Some(name) => resolve.name_world_key(name), + Some(name) => self.wasm_name_world_key(resolve, name), None => "$root".to_string(), }; @@ -2565,7 +2579,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> { let camel = name.to_upper_camel_case(); let module = self .interface - .map(|(_, key)| self.resolve.name_world_key(key)) + .map(|(_, key)| self.generator.wasm_name_world_key(self.resolve, key)) .unwrap_or_else(|| "$root".into()); if self.in_import { diff --git a/crates/markdown/src/lib.rs b/crates/markdown/src/lib.rs index cfc2ed3d5..477fd39af 100644 --- a/crates/markdown/src/lib.rs +++ b/crates/markdown/src/lib.rs @@ -116,6 +116,7 @@ impl WorldGenerator for Markdown { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + _implements: Option, _files: &mut Files, ) -> Result<()> { let name = resolve.name_world_key(name); @@ -155,6 +156,7 @@ impl WorldGenerator for Markdown { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + _implements: Option, _files: &mut Files, ) -> Result<()> { let name = resolve.name_world_key(name); diff --git a/crates/moonbit/src/lib.rs b/crates/moonbit/src/lib.rs index 3f0d13b0a..60c0790a4 100644 --- a/crates/moonbit/src/lib.rs +++ b/crates/moonbit/src/lib.rs @@ -132,9 +132,14 @@ pub struct MoonBit { return_area_align: Alignment, async_support: AsyncSupport, + current_implements: Option, } impl MoonBit { + fn wasm_name_world_key(&self, resolve: &Resolve, key: &WorldKey) -> String { + wit_bindgen_core::wasm_import_module_name(resolve, key, self.current_implements) + } + fn interface<'a>( &'a mut self, resolve: &'a Resolve, @@ -170,8 +175,10 @@ impl WorldGenerator for MoonBit { resolve: &Resolve, key: &WorldKey, id: InterfaceId, + implements: Option, files: &mut Files, ) -> Result<()> { + self.current_implements = implements; let name = PkgResolver::interface_name(resolve, key); let name = self.interface_ns.tmp(&name); self.pkg_resolver @@ -187,7 +194,7 @@ impl WorldGenerator for MoonBit { } } - let module = &resolve.name_world_key(key); + let module = &self.wasm_name_world_key(resolve, key); let mut r#gen = self.interface(resolve, &name, module, Direction::Import); r#gen.types(id); @@ -199,6 +206,7 @@ impl WorldGenerator for MoonBit { self.import_interface_fragments .insert(name.to_owned(), result); + self.current_implements = None; Ok(()) } @@ -225,8 +233,10 @@ impl WorldGenerator for MoonBit { resolve: &Resolve, key: &WorldKey, id: InterfaceId, + implements: Option, files: &mut Files, ) -> Result<()> { + self.current_implements = implements; let name = format!( "{}.{}", self.opts.r#gen_dir, @@ -246,7 +256,7 @@ impl WorldGenerator for MoonBit { } } - let module = &resolve.name_world_key(key); + let module = &self.wasm_name_world_key(resolve, key); let mut r#gen = self.interface(resolve, &name, module, Direction::Export); r#gen.types(id); @@ -258,6 +268,7 @@ impl WorldGenerator for MoonBit { self.export_interface_fragments .insert(name.to_owned(), result); + self.current_implements = None; Ok(()) } @@ -594,8 +605,12 @@ impl InterfaceGenerator<'_> { self.r#gen.async_support.mark_async(); } + let interface_name_owned; let interface_name = match module { - Some(key) => &self.resolve.name_world_key(key), + Some(key) => { + interface_name_owned = self.r#gen.wasm_name_world_key(self.resolve, key); + &interface_name_owned + } None => "$root", }; let mut bindgen = FunctionBindgen::new( @@ -663,7 +678,7 @@ impl InterfaceGenerator<'_> { let sig = self.sig_string(&mbt_sig, async_); let module = match module { - Some(key) => self.resolve.name_world_key(key), + Some(key) => self.r#gen.wasm_name_world_key(self.resolve, key), None => "$root".into(), }; @@ -775,7 +790,7 @@ impl InterfaceGenerator<'_> { let async_export_prefix = if async_ { "[async-lift]" } else { "" }; // Async functions return type let interface_name = match interface { - Some(key) => Some(self.resolve.name_world_key(key)), + Some(key) => Some(self.r#gen.wasm_name_world_key(self.resolve, key)), None => None, }; @@ -811,7 +826,9 @@ impl InterfaceGenerator<'_> { unreachable!() }; let func_name = func.name.clone(); - let import_module = self.resolve.name_world_key(interface.unwrap()); + let import_module = self + .r#gen + .wasm_name_world_key(self.resolve, interface.unwrap()); self.r#gen.export.insert( export_func_name.clone(), format!("[callback]{async_export_prefix}{export_name}"), diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index 4f4f00471..5d52f8338 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -25,6 +25,9 @@ pub struct InterfaceGenerator<'a> { pub return_pointer_area_size: ArchitectureSize, pub return_pointer_area_align: Alignment, pub(super) needs_runtime_module: bool, + /// When `Some`, this interface is an `implements` item. The `InterfaceId` + /// identifies the interface being implemented. + pub implements: Option, } /// A description of the "mode" in which a type is printed. @@ -134,6 +137,12 @@ enum PayloadFor { } impl<'i> InterfaceGenerator<'i> { + /// Compute the wasm-level module name for a world key, accounting for + /// `implements` items. + fn wasm_name_world_key(&self, key: &WorldKey) -> String { + wit_bindgen_core::wasm_import_module_name(self.resolve, key, self.implements) + } + pub(super) fn generate_exports<'a>( &mut self, interface: Option<(InterfaceId, &WorldKey)>, @@ -201,7 +210,7 @@ impl<'i> InterfaceGenerator<'i> { let resource = resource.unwrap(); let resource_name = self.resolve.types[resource].name.as_ref().unwrap(); let (_, interface_name) = interface.unwrap(); - let module = self.resolve.name_world_key(interface_name); + let module = self.wasm_name_world_key(interface_name); let wasm_import_module = format!("[export]{module}"); let import_new = crate::declare_import( &wasm_import_module, @@ -298,7 +307,7 @@ macro_rules! {macro_name} {{ let export_prefix = self.r#gen.opts.export_prefix.as_deref().unwrap_or(""); for name in resources_to_drop { let module = match self.identifier { - Identifier::Interface(_, key) => self.resolve.name_world_key(key), + Identifier::Interface(_, key) => self.wasm_name_world_key(key), Identifier::World(_) | Identifier::StreamOrFuturePayload => { unreachable!() } @@ -484,7 +493,7 @@ macro_rules! {macro_name} {{ let module = format!( "{prefix}{}", interface - .map(|name| self.resolve.name_world_key(name)) + .map(|name| self.wasm_name_world_key(name)) .unwrap_or_else(|| "$root".into()) ); let func_name = &func.name; @@ -1209,7 +1218,7 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8) ) { let name_snake = func.name.to_snake_case().replace('.', "_"); let wasm_module_export_name = match self.identifier { - Identifier::Interface(_, key) => Some(self.resolve.name_world_key(key)), + Identifier::Interface(_, key) => Some(self.wasm_name_world_key(key)), Identifier::World(_) => None, Identifier::StreamOrFuturePayload => unreachable!(), }; @@ -1313,6 +1322,7 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8) &mut self, interface: Option<(InterfaceId, &WorldKey)>, funcs: impl Iterator + Clone, + path_override: Option<&str>, ) { let mut funcs = super::group_by_resource(funcs.clone()); @@ -1321,7 +1331,10 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8) let mut extra_trait_items = String::new(); let guest_trait = match interface { Some((id, _)) => { - let path = self.path_to_interface(id).unwrap(); + let path = match path_override { + Some(p) => p.to_string(), + None => self.path_to_interface(id).unwrap(), + }; for (name, id) in self.resolve.interfaces[id].types.iter() { match self.resolve.types[*id].kind { TypeDefKind::Resource => {} @@ -2659,7 +2672,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> { self.wasm_import_module.to_string() } else { let module = match self.identifier { - Identifier::Interface(_, key) => self.resolve.name_world_key(key), + Identifier::Interface(_, key) => self.wasm_name_world_key(key), Identifier::World(_) => unimplemented!("resource exports from worlds"), Identifier::StreamOrFuturePayload => unreachable!(), }; diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index 3df749648..804aafd1e 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -52,6 +52,12 @@ pub struct RustWasm { future_payloads: IndexMap, String>, stream_payloads: IndexMap, String>, + + /// Tracks InterfaceIds already seen as imports via `implements`. + /// Maps InterfaceId -> snake_case module name of first import. + implements_import_first_seen: HashMap, + /// Tracks InterfaceIds already seen as exports via `implements`. + implements_export_first_seen: HashSet, } #[derive(Default)] @@ -362,6 +368,7 @@ impl RustWasm { return_pointer_area_size: Default::default(), return_pointer_area_align: Default::default(), needs_runtime_module: false, + implements: None, } } @@ -470,8 +477,11 @@ impl RustWasm { }; let remapped = entry.remapped; - let prev = self.interface_names.insert(id, entry); - assert!(prev.is_none()); + // Allow duplicate InterfaceId entries for `implements` items — + // the first entry wins for type lookups. + if !self.interface_names.contains_key(&id) { + self.interface_names.insert(id, entry); + } Ok(remapped) } @@ -1186,7 +1196,8 @@ impl WorldGenerator for RustWasm { let TypeDefKind::Resource = &resolve.types[id].kind else { continue; }; - assert!(self.exported_resources.insert(id)); + // Allow duplicate resource IDs from `implements` items + self.exported_resources.insert(id); } } @@ -1211,43 +1222,80 @@ impl WorldGenerator for RustWasm { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> Result<()> { + // Check if this is a duplicate implements import (same InterfaceId + // seen before). + let is_duplicate_implements = + implements.is_some() && self.implements_import_first_seen.contains_key(&id); + let mut to_define = Vec::new(); - for (name, ty_id) in resolve.interfaces[id].types.iter() { - let full_name = full_wit_type_name(resolve, *ty_id); - if let Some(type_gen) = self.with.get(&full_name) { - // skip type definition generation for remapped types - if type_gen.generated() { + if !is_duplicate_implements { + for (name, ty_id) in resolve.interfaces[id].types.iter() { + let full_name = full_wit_type_name(resolve, *ty_id); + if let Some(type_gen) = self.with.get(&full_name) { + // skip type definition generation for remapped types + if type_gen.generated() { + to_define.push((name, ty_id)); + } + } else { to_define.push((name, ty_id)); } - } else { - to_define.push((name, ty_id)); + self.generated_types.insert(full_name); } - self.generated_types.insert(full_name); } - let wasm_import_module = resolve.name_world_key(name); + let wasm_import_module = + wit_bindgen_core::wasm_import_module_name(resolve, name, implements); let mut r#gen = self.interface( Identifier::Interface(id, name), &wasm_import_module, resolve, true, ); + r#gen.implements = implements; let (snake, module_path) = r#gen.start_append_submodule(name); if r#gen.r#gen.interface_names[&id].remapped { return Ok(()); } - for (name, ty_id) in to_define { - r#gen.define_type(&name, *ty_id); - } + if is_duplicate_implements { + // For duplicate implements imports, re-export types from the + // first module and only generate function imports. + let first_snake = self.implements_import_first_seen[&id].clone(); + let mut r#gen = self.interface( + Identifier::Interface(id, name), + &wasm_import_module, + resolve, + true, + ); + r#gen.implements = implements; + + // Re-export all types from the first module + uwriteln!(r#gen.src, "pub use super::{first_snake}::*;"); + + // Generate function imports with the new wasm import module + r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name)); + + let docs = &resolve.interfaces[id].docs; + r#gen.finish_append_submodule(&snake, module_path, docs); + } else { + for (name, ty_id) in to_define { + r#gen.define_type(&name, *ty_id); + } + + r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name)); - r#gen.generate_imports(resolve.interfaces[id].functions.values(), Some(name)); + let docs = &resolve.interfaces[id].docs; - let docs = &resolve.interfaces[id].docs; + r#gen.finish_append_submodule(&snake, module_path, docs); - r#gen.finish_append_submodule(&snake, module_path, docs); + // Record this as the first seen for implements dedup + if implements.is_some() { + self.implements_import_first_seen.insert(id, snake.clone()); + } + } Ok(()) } @@ -1274,39 +1322,84 @@ impl WorldGenerator for RustWasm { resolve: &Resolve, name: &WorldKey, id: InterfaceId, + implements: Option, _files: &mut Files, ) -> Result<()> { + let is_duplicate_implements = + implements.is_some() && self.implements_export_first_seen.contains(&id); + let mut to_define = Vec::new(); - for (ty_name, ty_id) in resolve.interfaces[id].types.iter() { - let full_name = full_wit_type_name(resolve, *ty_id); - to_define.push((ty_name, ty_id)); - self.generated_types.insert(full_name); + if !is_duplicate_implements { + for (ty_name, ty_id) in resolve.interfaces[id].types.iter() { + let full_name = full_wit_type_name(resolve, *ty_id); + to_define.push((ty_name, ty_id)); + self.generated_types.insert(full_name); + } } - let wasm_import_module = format!("[export]{}", resolve.name_world_key(name)); + let wasm_import_module = format!( + "[export]{}", + wit_bindgen_core::wasm_import_module_name(resolve, name, implements) + ); let mut r#gen = self.interface( Identifier::Interface(id, name), &wasm_import_module, resolve, false, ); + r#gen.implements = implements; let (snake, module_path) = r#gen.start_append_submodule(name); if r#gen.r#gen.interface_names[&id].remapped { return Ok(()); } - for (ty_name, ty_id) in to_define { - r#gen.define_type(&ty_name, *ty_id); - } + if is_duplicate_implements { + // For duplicate implements exports, generate fresh exports. + // Types are referenced via path_to_interface() automatically. + + let mut r#gen = self.interface( + Identifier::Interface(id, name), + &wasm_import_module, + resolve, + false, + ); + r#gen.implements = implements; + + // Don't re-export types from the first module — generate_exports + // references types via path_to_interface() which handles + // cross-module type resolution automatically. - let macro_name = - r#gen.generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?; + let macro_name = r#gen + .generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?; - let docs = &resolve.interfaces[id].docs; + let docs = &resolve.interfaces[id].docs; + r#gen.finish_append_submodule(&snake, module_path, docs); - r#gen.finish_append_submodule(&snake, module_path, docs); - self.export_macros - .push((macro_name, self.interface_names[&id].path.clone())); + let export_path = compute_module_path(name, resolve, true).join("::"); + self.export_macros.push((macro_name, export_path)); + } else { + for (ty_name, ty_id) in to_define { + r#gen.define_type(&ty_name, *ty_id); + } + + let macro_name = r#gen + .generate_exports(Some((id, name)), resolve.interfaces[id].functions.values())?; + + let docs = &resolve.interfaces[id].docs; + + r#gen.finish_append_submodule(&snake, module_path, docs); + + let export_path = if implements.is_some() { + compute_module_path(name, resolve, true).join("::") + } else { + self.interface_names[&id].path.clone() + }; + self.export_macros.push((macro_name, export_path)); + + if implements.is_some() { + self.implements_export_first_seen.insert(id); + } + } if self.opts.stubs { let world_id = self.world.unwrap(); @@ -1316,7 +1409,17 @@ impl WorldGenerator for RustWasm { resolve, false, ); - r#gen.generate_stub(Some((id, name)), resolve.interfaces[id].functions.values()); + r#gen.implements = implements; + // For implements items, interface_names may point to a different + // path (e.g. an import path for this InterfaceId), so compute + // the correct export path from the label. + let path_override = + implements.map(|_| compute_module_path(name, resolve, true).join("::")); + r#gen.generate_stub( + Some((id, name)), + resolve.interfaces[id].functions.values(), + path_override.as_deref(), + ); let stub = r#gen.finish(); self.src.push_str(&stub); } @@ -1339,7 +1442,7 @@ impl WorldGenerator for RustWasm { if self.opts.stubs { let mut r#gen = self.interface(Identifier::World(world), "[export]$root", resolve, false); - r#gen.generate_stub(None, funcs.iter().map(|f| f.1)); + r#gen.generate_stub(None, funcs.iter().map(|f| f.1), None); let stub = r#gen.finish(); self.src.push_str(&stub); } diff --git a/tests/codegen/implements-export.wit b/tests/codegen/implements-export.wit new file mode 100644 index 000000000..65c5affd8 --- /dev/null +++ b/tests/codegen/implements-export.wit @@ -0,0 +1,15 @@ +package foo:foo; + +interface store { + record item { + key: string, + value: string, + } + get: func(key: string) -> option; + set: func(key: string, value: string); +} + +world implements-export { + export primary: store; + export backup: store; +} diff --git a/tests/codegen/implements-mixed.wit b/tests/codegen/implements-mixed.wit new file mode 100644 index 000000000..81e8779be --- /dev/null +++ b/tests/codegen/implements-mixed.wit @@ -0,0 +1,17 @@ +package foo:foo; + +interface store { + record item { + key: string, + value: string, + } + get: func(key: string) -> option; + set: func(key: string, value: string); +} + +world implements-mixed { + import primary: store; + import backup: store; + export read-primary: store; + export read-backup: store; +} diff --git a/tests/codegen/implements.wit b/tests/codegen/implements.wit new file mode 100644 index 000000000..e0dd3147a --- /dev/null +++ b/tests/codegen/implements.wit @@ -0,0 +1,15 @@ +package foo:foo; + +interface store { + record item { + key: string, + value: string, + } + get: func(key: string) -> option; + set: func(key: string, value: string); +} + +world implements-import { + import primary: store; + import backup: store; +}