diff --git a/Cargo.lock b/Cargo.lock index 9851750..e50f958 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "arrayvec" version = "0.7.6" @@ -111,26 +117,6 @@ dependencies = [ "wesl", ] -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -176,12 +162,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] -name = "cexpr" -version = "0.6.0" +name = "cbindgen" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ - "nom", + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml 0.9.12+spec-1.1.0", ] [[package]] @@ -196,17 +191,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.6.0" @@ -371,12 +355,28 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "escape8259" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + [[package]] name = "fixedbitset" version = "0.5.7" @@ -389,6 +389,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foldhash" version = "0.2.0" @@ -405,6 +411,19 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" @@ -423,13 +442,22 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "foldhash", + "foldhash 0.2.0", ] [[package]] @@ -444,6 +472,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "indexmap" version = "2.13.0" @@ -451,7 +485,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -460,15 +496,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -512,7 +539,7 @@ dependencies = [ "ascii-canvas", "bit-set", "ena", - "itertools 0.14.0", + "itertools", "lalrpop-util", "petgraph", "regex", @@ -534,6 +561,12 @@ dependencies = [ "rustversion", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "lexical" version = "7.0.5" @@ -606,16 +639,6 @@ version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - [[package]] name = "libm" version = "0.2.16" @@ -634,6 +657,12 @@ dependencies = [ "escape8259", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "lock_api" version = "0.4.14" @@ -687,12 +716,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "naga" version = "28.0.0" @@ -706,14 +729,14 @@ dependencies = [ "cfg_aliases", "codespan-reporting", "half", - "hashbrown", + "hashbrown 0.16.1", "hexf-parse", "indexmap", "libm", "log", "num-traits", "once_cell", - "rustc-hash 1.1.0", + "rustc-hash", "thiserror 2.0.18", "unicode-ident", ] @@ -724,16 +747,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -854,6 +867,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "random_wgsl" version = "0.3.2" @@ -913,12 +932,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.4.1" @@ -928,6 +941,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1039,6 +1065,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + [[package]] name = "sha3" version = "0.10.8" @@ -1049,12 +1084,6 @@ dependencies = [ "keccak", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "siphasher" version = "1.0.2" @@ -1096,6 +1125,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + [[package]] name = "term" version = "1.2.1" @@ -1167,7 +1209,7 @@ dependencies = [ name = "tokrepr-derive" version = "0.1.0" dependencies = [ - "itertools 0.14.0", + "itertools", "proc-macro2", "quote", "syn", @@ -1180,11 +1222,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit", ] +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -1194,6 +1251,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" @@ -1202,10 +1268,19 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", - "winnow", + "winnow 0.7.15", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow 1.0.1", ] [[package]] @@ -1214,6 +1289,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + [[package]] name = "tsify" version = "0.5.6" @@ -1290,6 +1371,24 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.114" @@ -1335,6 +1434,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.91" @@ -1353,13 +1486,13 @@ dependencies = [ "derive_more", "glob", "half", - "itertools 0.14.0", + "itertools", "num-traits", "proc-macro2", "quote", "serde", "thiserror 2.0.18", - "toml", + "toml 0.8.23", "wesl-macros", "wesl-quote", "wgsl-parse", @@ -1370,7 +1503,7 @@ dependencies = [ name = "wesl-c" version = "0.3.2" dependencies = [ - "bindgen", + "cbindgen", "wesl", ] @@ -1389,7 +1522,7 @@ dependencies = [ name = "wesl-macros" version = "0.3.2" dependencies = [ - "itertools 0.14.0", + "itertools", "proc-macro2", "quote", "syn", @@ -1399,7 +1532,7 @@ dependencies = [ name = "wesl-quote" version = "0.3.2" dependencies = [ - "itertools 0.14.0", + "itertools", "proc-macro-error2", "proc-macro2", "quote", @@ -1446,7 +1579,7 @@ version = "0.3.2" dependencies = [ "annotate-snippets", "derive_more", - "itertools 0.14.0", + "itertools", "lalrpop", "lalrpop-util", "lexical", @@ -1462,7 +1595,7 @@ name = "wgsl-types" version = "0.3.2" dependencies = [ "half", - "itertools 0.14.0", + "itertools", "num-traits", "serde", "tokrepr", @@ -1501,6 +1634,100 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "zerocopy" version = "0.8.42" diff --git a/crates/wesl-c/Cargo.toml b/crates/wesl-c/Cargo.toml index ae8ecdb..16bd708 100644 --- a/crates/wesl-c/Cargo.toml +++ b/crates/wesl-c/Cargo.toml @@ -14,7 +14,7 @@ crate-type = ["cdylib", "staticlib"] wesl = { workspace = true } [build-dependencies] -bindgen = "0.72" +cbindgen = { version = "0.29.2", default-features = false } [features] eval = ["wesl/eval"] diff --git a/crates/wesl-c/build.rs b/crates/wesl-c/build.rs index 6e563e7..f990516 100644 --- a/crates/wesl-c/build.rs +++ b/crates/wesl-c/build.rs @@ -1,27 +1,13 @@ use std::env; -use std::path::PathBuf; fn main() { - let handles = ["WeslCompiler", "WeslTranslationUnit"]; - - let mut builder = bindgen::Builder::default() - .header("include/wesl.h") - .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) - .allowlist_item("wesl.*") - .allowlist_item("Wesl.*") - .prepend_enum_name(false) - .ignore_functions(); - - for handle in handles { - builder = builder - .blocklist_item(handle) - .raw_line(format!("type {handle} = crate::{handle};")); - } - - let bindings = builder.generate().expect("Unable to generate bindings"); - - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + + cbindgen::Builder::new() + .with_crate(crate_dir) + .with_language(cbindgen::Language::C) + .with_cpp_compat(true) + .generate() + .expect("Unable to generate bindings") + .write_to_file("include/wesl.h"); } diff --git a/crates/wesl-c/include/wesl.h b/crates/wesl-c/include/wesl.h index ebb6045..0f4b925 100644 --- a/crates/wesl-c/include/wesl.h +++ b/crates/wesl-c/include/wesl.h @@ -1,208 +1,221 @@ -#ifndef WESL_H -#define WESL_H - -#include +#include #include -#include +#include +#include +enum WeslManglerKind #ifdef __cplusplus -extern "C" { -#endif + : uint8_t +#endif // __cplusplus + { + WESL_MANGLER_ESCAPE = 0, + WESL_MANGLER_HASH = 1, + WESL_MANGLER_NONE = 2, +}; +#ifndef __cplusplus +typedef uint8_t WeslManglerKind; +#endif // __cplusplus + +enum WeslBindingType +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + WESL_BINDING_UNIFORM = 0, + WESL_BINDING_STORAGE = 1, + WESL_BINDING_READ_ONLY_STORAGE = 2, + WESL_BINDING_FILTERING = 3, + WESL_BINDING_NON_FILTERING = 4, + WESL_BINDING_COMPARISON = 5, + WESL_BINDING_FLOAT = 6, + WESL_BINDING_UNFILTERABLE_FLOAT = 7, + WESL_BINDING_SINT = 8, + WESL_BINDING_UINT = 9, + WESL_BINDING_DEPTH = 10, + WESL_BINDING_WRITE_ONLY = 11, + WESL_BINDING_READ_WRITE = 12, + WESL_BINDING_READ_ONLY = 13, +}; +#ifndef __cplusplus +typedef uint8_t WeslBindingType; +#endif // __cplusplus -// -- handles typedef struct WeslCompiler WeslCompiler; + typedef struct WeslTranslationUnit WeslTranslationUnit; -// -- enums -typedef enum WeslManglerKind { - WESL_MANGLER_ESCAPE = 0, - WESL_MANGLER_HASH = 1, - WESL_MANGLER_NONE = 2 -} WeslManglerKind; - -typedef enum WeslBindingType { - WESL_BINDING_UNIFORM = 0, - WESL_BINDING_STORAGE = 1, - WESL_BINDING_READ_ONLY_STORAGE = 2, - WESL_BINDING_FILTERING = 3, - WESL_BINDING_NON_FILTERING = 4, - WESL_BINDING_COMPARISON = 5, - WESL_BINDING_FLOAT = 6, - WESL_BINDING_UNFILTERABLE_FLOAT = 7, - WESL_BINDING_SINT = 8, - WESL_BINDING_UINT = 9, - WESL_BINDING_DEPTH = 10, - WESL_BINDING_WRITE_ONLY = 11, - WESL_BINDING_READ_WRITE = 12, - WESL_BINDING_READ_ONLY = 13 -} WeslBindingType; - -// -- structs -typedef struct WeslBinding { - unsigned int group; - unsigned int binding; - WeslBindingType kind; - const uint8_t* data; - size_t data_len; -} WeslBinding; +typedef struct WeslDiagnostic { + const char *file; + uintptr_t span_start; + uintptr_t span_end; + const char *title; +} WeslDiagnostic; + +typedef struct WeslError { + const char *source; + const char *message; + const struct WeslDiagnostic *diagnostics; + uintptr_t diagnostics_len; +} WeslError; + +typedef struct WeslResult { + bool success; + const char *data; + struct WeslError error; +} WeslResult; + +typedef struct WeslStringMap { + const char *const *keys; + const char *const *values; + uintptr_t len; +} WeslStringMap; typedef struct WeslResolveSourceResult { - bool success; - const char* source; + bool success; + const char *source; } WeslResolveSourceResult; +typedef struct WeslResolveSourceResult *(*WeslResolveSourceFunction)(const char *path, + void *userdata); + +typedef void (*WeslResolveSourceFreeFunction)(const struct WeslResolveSourceResult *result, + void *userdata); + typedef struct WeslResolveModuleResult { - bool success; - WeslTranslationUnit* module; + bool success; + struct WeslTranslationUnit *module; } WeslResolveModuleResult; -typedef const WeslResolveSourceResult* (*WeslResolveSourceFunction)(const char* path, void* userdata); -typedef const WeslResolveModuleResult* (*WeslResolveModuleFunction)(const char* path, void* userdata); -typedef void (*WeslResolveSourceFreeFunction)(const WeslResolveSourceResult* result, void* userdata); -typedef void (*WeslResolveModuleFreeFunction)(const WeslResolveModuleResult* result, void* userdata); -typedef const char* (*WeslResolveStringFunction)(const char* path, void* userdata); -typedef void (*WeslResolveFreeStringFunction)(const char* string, void* userdata); +typedef struct WeslResolveModuleResult *(*WeslResolveModuleFunctionOption)(const char *path, + void *userdata); + +typedef void (*WeslResolveModuleFreeFunctionOption)(const struct WeslResolveModuleResult *result, + void *userdata); + +typedef const char *(*WeslResolveStringFunctionOption)(const char *path, void *userdata); + +typedef void (*WeslResolveFreeStringFunctionOption)(const char *result, void *userdata); typedef struct WeslResolverOptions { - void* userdata; - WeslResolveSourceFunction resolve_source; - WeslResolveSourceFreeFunction resolve_source_free; - WeslResolveModuleFunction resolve_module; - WeslResolveModuleFreeFunction resolve_module_free; - WeslResolveStringFunction display_name; - WeslResolveFreeStringFunction free_display_name; - WeslResolveStringFunction fs_path; - WeslResolveFreeStringFunction free_fs_path; + void *userdata; + WeslResolveSourceFunction resolve_source; + WeslResolveSourceFreeFunction resolve_source_free; + WeslResolveModuleFunctionOption resolve_module; + WeslResolveModuleFreeFunctionOption resolve_module_free; + WeslResolveStringFunctionOption display_name; + WeslResolveFreeStringFunctionOption free_display_name; + WeslResolveStringFunctionOption fs_path; + WeslResolveFreeStringFunctionOption free_fs_path; } WeslResolverOptions; typedef struct WeslCompileOptions { - WeslManglerKind mangler; - bool sourcemap; - bool imports; - bool condcomp; - bool generics; - bool strip; - bool lower; - bool validate; - bool naga; - bool lazy; - bool keep_root; - bool mangle_root; - WeslResolverOptions* resolver; + WeslManglerKind mangler; + bool sourcemap; + bool imports; + bool condcomp; + bool generics; + bool strip; + bool lower; + bool validate; + bool naga; + bool lazy; + bool keep_root; + bool mangle_root; + const struct WeslResolverOptions *resolver; } WeslCompileOptions; -typedef struct WeslStringMap { - const char* const* keys; - const char* const* values; - size_t len; -} WeslStringMap; +typedef struct WeslStringArray { + const char *const *items; + uintptr_t len; +} WeslStringArray; typedef struct WeslBoolMap { - const char* const* keys; - const bool* values; - size_t len; + const char *const *keys; + const bool *values; + uintptr_t len; } WeslBoolMap; -typedef struct WeslStringArray { - const char* const* items; - size_t len; -} WeslStringArray; +typedef struct WeslParseResult { + bool success; + const struct WeslTranslationUnit *data; + struct WeslError error; +} WeslParseResult; + +typedef struct WeslBinding { + uint32_t group; + uint32_t binding; + WeslBindingType kind; + uintptr_t data_len; + const uint8_t *data; +} WeslBinding; typedef struct WeslBindingArray { - const WeslBinding* items; - size_t len; + const struct WeslBinding *items; + uintptr_t len; } WeslBindingArray; -typedef struct WeslDiagnostic { - const char* file; - unsigned int span_start; - unsigned int span_end; - const char* title; -} WeslDiagnostic; +typedef struct WeslExecResult { + bool success; + const struct WeslBindingArray *resources; + struct WeslError error; +} WeslExecResult; -typedef struct WeslError { - const char* source; - const char* message; - const WeslDiagnostic* diagnostics; - size_t diagnostics_len; -} WeslError; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus -typedef struct WeslResult { - bool success; - const char* data; - WeslError error; -} WeslResult; +struct WeslCompiler *wesl_create_compiler(void); -typedef struct WeslParseResult { - bool success; - WeslTranslationUnit* data; - WeslError error; -} WeslParseResult; +void wesl_destroy_compiler(struct WeslCompiler *compiler); -typedef struct WeslExecOptions { - WeslCompileOptions compile; - const char* entrypoint; - const WeslBindingArray* resources; - const WeslStringMap* overrides; -} WeslExecOptions; +struct WeslResult wesl_compile(const struct WeslStringMap *files, + const char *root, + const struct WeslCompileOptions *options, + const struct WeslStringArray *keep, + const struct WeslBoolMap *features); -typedef struct WeslExecResult { - bool success; - const WeslBindingArray* resources; - WeslError error; -} WeslExecResult; +struct WeslParseResult wesl_parse(const char *source); -// -- main API -WeslCompiler* wesl_create_compiler(void); -void wesl_destroy_compiler(WeslCompiler* compiler); - -WeslResult wesl_compile( - const WeslStringMap* files, - const char* root, - const WeslCompileOptions* options, - const WeslStringArray* keep, - const WeslBoolMap* features -); - -WeslParseResult wesl_parse( - const char* source -); - -WeslResult wesl_eval( - const WeslStringMap* files, - const char* root, - const char* expression, - const WeslCompileOptions* options, - const WeslBoolMap* features -); - -WeslExecResult wesl_exec( - const WeslStringMap* files, - const char* root, - const char* entrypoint, - const WeslCompileOptions* options, - const WeslBindingArray* resources, - const WeslStringMap* overrides, - const WeslBoolMap* features -); - -// -- memory -void wesl_free_string(const char* ptr); -void wesl_free_result(WeslResult* result); -void wesl_free_exec_result(WeslExecResult* result); - -// Free a WeslParseResult filled by wesl_parse. -// This does NOT free the WeslTranslationUnit* inside the result, if the parsing succeeded! -void wesl_free_parse_result(WeslParseResult* result); -void wesl_free_translation_unit(WeslTranslationUnit* unit); - -// -- utility - -// note: results from this function must not be freed -const char* wesl_version(void); +struct WeslResult wesl_eval(const struct WeslStringMap *files, + const char *root, + const char *expression, + const struct WeslCompileOptions *options, + const struct WeslBoolMap *features); -#ifdef __cplusplus -} -#endif +struct WeslResult wesl_eval(const struct WeslStringMap *_files, + const char *_root, + const char *_expression, + const struct WeslCompileOptions *_options, + const struct WeslBoolMap *_features); + +struct WeslExecResult wesl_exec(const struct WeslStringMap *files, + const char *root, + const char *entrypoint, + const struct WeslCompileOptions *options, + const struct WeslBindingArray *resources, + const struct WeslStringMap *overrides, + const struct WeslBoolMap *features); + +struct WeslExecResult wesl_exec(const struct WeslStringMap *_files, + const char *_root, + const char *_entrypoint, + const struct WeslCompileOptions *_options, + const struct WeslBindingArray *_resources, + const struct WeslStringMap *_overrides, + const struct WeslBoolMap *_features); -#endif // WESL_H +void wesl_free_string(const char *ptr); + +void wesl_free_result(struct WeslResult *result); + +void wesl_free_exec_result(struct WeslExecResult *result); + +void wesl_free_parse_result(struct WeslParseResult *result); + +void wesl_free_translation_unit(struct WeslTranslationUnit *unit); + +const char *wesl_version(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/crates/wesl-c/src/lib.rs b/crates/wesl-c/src/lib.rs index 1e36953..23cc76b 100644 --- a/crates/wesl-c/src/lib.rs +++ b/crates/wesl-c/src/lib.rs @@ -17,14 +17,6 @@ use wesl::{ syntax::{AccessMode, AddressSpace}, }; -pub mod native { - #![allow(non_upper_case_globals)] - #![allow(non_camel_case_types)] - #![allow(non_snake_case)] - #![allow(dead_code)] - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -} - // TODO: this seems unfinished. only wesl_create/destroy_compiler is implemented. #[allow(unused)] pub struct WeslCompiler { @@ -35,27 +27,204 @@ pub struct WeslTranslationUnit { unit: TranslationUnit, } -fn map_mangler_kind(value: native::WeslManglerKind) -> Option { +/// cbindgen:rename-all=ScreamingSnakeCase +#[repr(u8)] +#[derive(Copy, Clone)] +pub enum WeslManglerKind { + WeslManglerEscape = 0, + WeslManglerHash = 1, + WeslManglerNone = 2, +} + +/// cbindgen:rename-all=ScreamingSnakeCase +#[repr(u8)] +#[derive(Copy, Clone)] +pub enum WeslBindingType { + WeslBindingUniform = 0, + WeslBindingStorage = 1, + WeslBindingReadOnlyStorage = 2, + WeslBindingFiltering = 3, + WeslBindingNonFiltering = 4, + WeslBindingComparison = 5, + WeslBindingFloat = 6, + WeslBindingUnfilterableFloat = 7, + WeslBindingSint = 8, + WeslBindingUint = 9, + WeslBindingDepth = 10, + WeslBindingWriteOnly = 11, + WeslBindingReadWrite = 12, + WeslBindingReadOnly = 13, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct WeslBinding { + pub group: u32, + pub binding: u32, + pub kind: WeslBindingType, + pub data_len: usize, + pub data: *const u8, +} + +#[repr(C)] +pub struct WeslResolveSourceResult { + pub success: bool, + pub source: *const c_char, +} + +#[repr(C)] +pub struct WeslResolveModuleResult { + pub success: bool, + pub module: *mut WeslTranslationUnit, +} + +pub type WeslResolveSourceFunction = unsafe extern "C" fn( + path: *const c_char, + userdata: *mut c_void, +) -> *mut WeslResolveSourceResult; + +pub type WeslResolveSourceFreeFunction = + unsafe extern "C" fn(result: *const WeslResolveSourceResult, userdata: *mut c_void); + +pub type WeslResolveModuleFunction = unsafe extern "C" fn( + path: *const c_char, + userdata: *mut c_void, +) -> *mut WeslResolveModuleResult; +pub type WeslResolveModuleFreeFunction = + unsafe extern "C" fn(result: *const WeslResolveModuleResult, userdata: *mut c_void); + +// Workaround for https://github.com/mozilla/cbindgen/issues/326 + +pub type WeslResolveModuleFunctionOption = Option< + unsafe extern "C" fn( + path: *const c_char, + userdata: *mut c_void, + ) -> *mut WeslResolveModuleResult, +>; +pub type WeslResolveModuleFreeFunctionOption = + Option; + +pub type WeslResolveStringFunction = + unsafe extern "C" fn(path: *const c_char, userdata: *mut c_void) -> *const c_char; +pub type WeslResolveFreeStringFunction = + unsafe extern "C" fn(result: *const c_char, userdata: *mut c_void); + +pub type WeslResolveStringFunctionOption = + Option *const c_char>; +pub type WeslResolveFreeStringFunctionOption = + Option; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct WeslResolverOptions { + pub userdata: *mut std::ffi::c_void, + + pub resolve_source: WeslResolveSourceFunction, + pub resolve_source_free: WeslResolveSourceFreeFunction, + + pub resolve_module: WeslResolveModuleFunctionOption, + pub resolve_module_free: WeslResolveModuleFreeFunctionOption, + + pub display_name: WeslResolveStringFunctionOption, + pub free_display_name: WeslResolveFreeStringFunctionOption, + + pub fs_path: WeslResolveStringFunctionOption, + pub free_fs_path: WeslResolveFreeStringFunctionOption, +} + +#[repr(C)] +pub struct WeslCompileOptions { + pub mangler: WeslManglerKind, + pub sourcemap: bool, + pub imports: bool, + pub condcomp: bool, + pub generics: bool, + pub strip: bool, + pub lower: bool, + pub validate: bool, + pub naga: bool, + pub lazy: bool, + pub keep_root: bool, + pub mangle_root: bool, + pub resolver: *const WeslResolverOptions, +} +#[repr(C)] +pub struct WeslStringMap { + pub keys: *const *const c_char, + pub values: *const *const c_char, + pub len: usize, +} + +#[repr(C)] +pub struct WeslBoolMap { + pub keys: *const *const c_char, + pub values: *const bool, + pub len: usize, +} +#[repr(C)] +pub struct WeslStringArray { + pub items: *const *const c_char, + pub len: usize, +} + +#[repr(C)] +pub struct WeslBindingArray { + pub items: *const WeslBinding, + pub len: usize, +} + +#[repr(C)] +pub struct WeslDiagnostic { + pub file: *const c_char, + pub span_start: usize, + pub span_end: usize, + pub title: *const c_char, +} + +#[repr(C)] +pub struct WeslError { + pub source: *const c_char, + pub message: *const c_char, + pub diagnostics: *const WeslDiagnostic, + pub diagnostics_len: usize, +} + +#[repr(C)] +pub struct WeslResult { + pub success: bool, + pub data: *const c_char, + pub error: WeslError, +} + +#[repr(C)] +pub struct WeslParseResult { + pub success: bool, + pub data: *const WeslTranslationUnit, + pub error: WeslError, +} + +#[repr(C)] +pub struct WeslExecResult { + pub success: bool, + pub resources: *const WeslBindingArray, + pub error: WeslError, +} + +fn map_mangler_kind(value: WeslManglerKind) -> Option { match value { - native::WESL_MANGLER_NONE => Some(wesl::ManglerKind::None), - native::WESL_MANGLER_HASH => Some(wesl::ManglerKind::Hash), - native::WESL_MANGLER_ESCAPE => Some(wesl::ManglerKind::Escape), - _ => None, + WeslManglerKind::WeslManglerNone => Some(wesl::ManglerKind::None), + WeslManglerKind::WeslManglerHash => Some(wesl::ManglerKind::Hash), + WeslManglerKind::WeslManglerEscape => Some(wesl::ManglerKind::Escape), } } // -- helpers -unsafe fn string_map_to_hashmap(map: *const native::WeslStringMap) -> HashMap { - if map.is_null() { - return HashMap::new(); - } - - unsafe { - let map = &*map; - let mut result = HashMap::new(); +unsafe fn string_map_to_hashmap(map: &WeslStringMap) -> HashMap { + let mut result = HashMap::new(); - for i in 0..map.len { + for i in 0..map.len { + unsafe { let key_ptr = *map.keys.add(i); let value_ptr = *map.values.add(i); @@ -65,21 +234,16 @@ unsafe fn string_map_to_hashmap(map: *const native::WeslStringMap) -> HashMap HashMap { - if map.is_null() { - return HashMap::new(); - } +unsafe fn bool_map_to_hashmap(map: &WeslBoolMap) -> HashMap { + let mut result = HashMap::new(); - unsafe { - let map = &*map; - let mut result = HashMap::new(); - - for i in 0..map.len { + for i in 0..map.len { + unsafe { let key_ptr = *map.keys.add(i); let value = *map.values.add(i); @@ -88,30 +252,25 @@ unsafe fn bool_map_to_hashmap(map: *const native::WeslBoolMap) -> HashMap Option> { - if array.is_null() { - return None; - } + result +} - unsafe { - let array = &*array; - let mut result = Vec::new(); +unsafe fn string_array_to_vec(array: &WeslStringArray) -> Option> { + let mut result = Vec::new(); - for i in 0..array.len { + for i in 0..array.len { + unsafe { let item_ptr = *array.items.add(i); if !item_ptr.is_null() { let item = CStr::from_ptr(item_ptr).to_string_lossy().into_owned(); result.push(item); } } - - Some(result) } + + Some(result) } fn create_c_string(s: &str) -> *const c_char { @@ -125,14 +284,14 @@ fn create_c_string(s: &str) -> *const c_char { } } -fn wesl_error_to_c(e: wesl::Error) -> native::WeslError { +fn wesl_error_to_c(e: wesl::Error) -> WeslError { let d = wesl::Diagnostic::from(e); let diagnostics = if let (Some(span), Some(res)) = (&d.detail.span, &d.detail.module_path) { - let diag = native::WeslDiagnostic { + let diag = WeslDiagnostic { file: create_c_string(&res.components.join("/")), - span_start: span.start as u32, - span_end: span.end as u32, + span_start: span.start, + span_end: span.end, title: create_c_string(&d.error.to_string()), }; @@ -143,7 +302,7 @@ fn wesl_error_to_c(e: wesl::Error) -> native::WeslError { ptr::null() }; - native::WeslError { + WeslError { source: d .detail .output @@ -160,33 +319,22 @@ fn wesl_error_to_c(e: wesl::Error) -> native::WeslError { } #[cfg(feature = "eval")] -unsafe fn binding_array_to_vec(array: *const native::WeslBindingArray) -> Vec { - if array.is_null() { - return Vec::new(); - } +unsafe fn binding_array_to_vec(array: &WeslBindingArray) -> Vec { + let mut result = Vec::new(); - unsafe { - let array = &*array; - let mut result = Vec::new(); - - for i in 0..array.len { - let binding = *array.items.add(i); - result.push(binding); - } - - result + for i in 0..array.len { + let binding = unsafe { *array.items.add(i) }; + result.push(binding); } + + result } #[cfg(feature = "eval")] fn parse_c_binding( - b: &native::WeslBinding, + b: &WeslBinding, wgsl: &wesl::syntax::TranslationUnit, ) -> Result<((u32, u32), RefInstance), wesl::Error> { - use crate::native::{ - WESL_BINDING_READ_ONLY_STORAGE, WESL_BINDING_STORAGE, WESL_BINDING_UNIFORM, - }; - let mut ctx = wesl::eval::Context::new(wgsl); let ty_expr = wgsl @@ -214,9 +362,9 @@ fn parse_c_binding( .map_err(|e| wesl::Error::Custom(format!("Failed to evaluate type: {e}")))?; let (storage, access) = match b.kind { - WESL_BINDING_UNIFORM => (AddressSpace::Uniform, AccessMode::Read), - WESL_BINDING_STORAGE => (AddressSpace::Storage, AccessMode::ReadWrite), - WESL_BINDING_READ_ONLY_STORAGE => (AddressSpace::Storage, AccessMode::Read), + WeslBindingType::WeslBindingUniform => (AddressSpace::Uniform, AccessMode::Read), + WeslBindingType::WeslBindingStorage => (AddressSpace::Storage, AccessMode::ReadWrite), + WeslBindingType::WeslBindingReadOnlyStorage => (AddressSpace::Storage, AccessMode::Read), _ => return Err(wesl::Error::Custom("Unsupported binding type".to_string())), }; @@ -238,16 +386,16 @@ fn parse_c_binding( } #[cfg(feature = "eval")] -fn create_c_binding_array(bindings: Vec) -> *const native::WeslBindingArray { +fn create_c_binding_array(bindings: Vec) -> *const WeslBindingArray { if bindings.is_empty() { return ptr::null(); } let items = bindings.into_boxed_slice(); let len = items.len(); - let items_ptr = Box::into_raw(items) as *const native::WeslBinding; + let items_ptr = Box::into_raw(items) as *const WeslBinding; - let array = Box::new(native::WeslBindingArray { + let array = Box::new(WeslBindingArray { items: items_ptr, len, }); @@ -269,8 +417,8 @@ pub unsafe extern "C" fn wesl_destroy_compiler(compiler: *mut WeslCompiler) { } } -fn error_from_str(s: &str) -> native::WeslError { - native::WeslError { +fn error_from_str(s: &str) -> WeslError { + WeslError { source: ptr::null(), message: create_c_string(s), diagnostics: ptr::null(), @@ -278,19 +426,19 @@ fn error_from_str(s: &str) -> native::WeslError { } } -fn result_from_str(s: &str) -> native::WeslResult { - native::WeslResult { +fn result_from_str(s: &str) -> WeslResult { + WeslResult { success: false, data: ptr::null(), error: error_from_str(s), } } -fn result_invalid_parameters() -> native::WeslResult { +fn result_invalid_parameters() -> WeslResult { result_from_str("Invalid parameters") } -const NO_ERROR: native::WeslError = native::WeslError { +const NO_ERROR: WeslError = WeslError { source: ptr::null(), message: ptr::null(), diagnostics: ptr::null(), @@ -298,7 +446,7 @@ const NO_ERROR: native::WeslError = native::WeslError { }; struct CustomResolver { - pub options: native::WeslResolverOptions, + pub options: WeslResolverOptions, } struct FreeGuard { @@ -323,7 +471,7 @@ impl Deref for FreeGuard { } } -impl FreeGuard { +impl FreeGuard { unsafe fn c_str(&self) -> &CStr { unsafe { CStr::from_ptr(self.data) } } @@ -338,8 +486,8 @@ fn mod_path_to_cstring(path: &ModulePath) -> CString { unsafe fn resolver_path_to_string) -> T>( path: &ModulePath, transform: F, - get_func: native::WeslResolveStringFunction, - free_func: native::WeslResolveFreeStringFunction, + get_func: Option, + free_func: Option, userdata: *mut c_void, ) -> Option { let get_func = get_func?; @@ -383,9 +531,8 @@ impl wesl::Resolver for CustomResolver { ) -> Result, ResolveError> { let cstring = mod_path_to_cstring(path); - let result = unsafe { - self.options.resolve_source.unwrap()(cstring.as_ptr(), self.options.userdata) - }; + let result = + unsafe { (self.options.resolve_source)(cstring.as_ptr(), self.options.userdata) }; if result.is_null() { return Err(ResolveError::Error( @@ -395,7 +542,7 @@ impl wesl::Resolver for CustomResolver { let result = FreeGuard { data: result, - free_function: self.options.resolve_source_free.unwrap(), + free_function: self.options.resolve_source_free, free_userdata: self.options.userdata, }; @@ -472,11 +619,7 @@ impl wesl::Resolver for CustomResolver { } } -fn validate_resolver_options(options: &native::WeslResolverOptions) -> Result<(), &'static str> { - if options.resolve_source.is_none() || options.resolve_source_free.is_none() { - return Err("resolve_source and resolve_source_free must be provided"); - } - +fn validate_resolver_options(options: &WeslResolverOptions) -> Result<(), &'static str> { if options.resolve_module.is_none() ^ options.resolve_module_free.is_none() { return Err("resolve_module and resolve_module_free must both be provide if either is"); } @@ -494,18 +637,17 @@ fn validate_resolver_options(options: &native::WeslResolverOptions) -> Result<() #[unsafe(no_mangle)] pub unsafe extern "C" fn wesl_compile( - files: *const native::WeslStringMap, + files: Option<&WeslStringMap>, root: *const c_char, - options: *const native::WeslCompileOptions, - keep: *const native::WeslStringArray, - features: *const native::WeslBoolMap, -) -> native::WeslResult { - if root.is_null() || options.is_null() { + options: &WeslCompileOptions, + keep: &WeslStringArray, + features: &WeslBoolMap, +) -> WeslResult { + if root.is_null() { return result_invalid_parameters(); } let root_str = unsafe { CStr::from_ptr(root).to_string_lossy() }; - let opts = unsafe { &*options }; let keep_vec = unsafe { string_array_to_vec(keep) }; let features_map = unsafe { bool_map_to_hashmap(features) }; @@ -514,8 +656,8 @@ pub unsafe extern "C" fn wesl_compile( Err(e) => return result_from_str(&format!("Invalid root path: {e}")), }; - let resolver: Box = match (files.is_null(), opts.resolver.is_null()) { - (false, true) => { + let resolver: Box = match (files, options.resolver.is_null()) { + (Some(files), true) => { let files_map = unsafe { string_map_to_hashmap(files) }; let mut resolver = VirtualResolver::new(); for (path, source) in files_map { @@ -526,8 +668,8 @@ pub unsafe extern "C" fn wesl_compile( Box::new(resolver) } - (true, false) => { - let resolver_options = unsafe { &*opts.resolver }; + (None, false) => { + let resolver_options = unsafe { &*options.resolver }; if let Err(msg) = validate_resolver_options(resolver_options) { return result_from_str(msg); } @@ -536,27 +678,27 @@ pub unsafe extern "C" fn wesl_compile( options: *resolver_options, }) } - (false, false) => { + (Some(_), false) => { return result_from_str("Files and custom resolver cannot be specified at once"); } _ => return result_from_str("Files or custom resolver must be specified"), }; - let Some(mangler) = map_mangler_kind(opts.mangler) else { + let Some(mangler) = map_mangler_kind(options.mangler) else { return result_from_str("Invalid mangler kind specified"); }; let mut compiler = Wesl::new_barebones().set_custom_resolver(resolver); let compiler = compiler .set_options(wesl::CompileOptions { - imports: opts.imports, - condcomp: opts.condcomp, - generics: opts.generics, - strip: opts.strip, - lower: opts.lower, - validate: opts.validate, - lazy: opts.lazy, - mangle_root: opts.mangle_root, + imports: options.imports, + condcomp: options.condcomp, + generics: options.generics, + strip: options.strip, + lower: options.lower, + validate: options.validate, + lazy: options.lazy, + mangle_root: options.mangle_root, keep: keep_vec, features: wesl::Features { default: wesl::Feature::Disable, @@ -565,21 +707,21 @@ pub unsafe extern "C" fn wesl_compile( .map(|(k, v)| (k, v.into())) .collect(), }, - keep_root: opts.keep_root, + keep_root: options.keep_root, }) - .use_sourcemap(opts.sourcemap) + .use_sourcemap(options.sourcemap) .set_mangler(mangler); match compiler.compile(&root_path) { Ok(result) => { let output = result.to_string(); - native::WeslResult { + WeslResult { success: true, data: create_c_string(&output), error: NO_ERROR, } } - Err(e) => native::WeslResult { + Err(e) => WeslResult { success: false, data: ptr::null(), error: wesl_error_to_c(e), @@ -588,9 +730,9 @@ pub unsafe extern "C" fn wesl_compile( } #[unsafe(no_mangle)] -pub unsafe extern "C" fn wesl_parse(source: *const c_char) -> native::WeslParseResult { +pub unsafe extern "C" fn wesl_parse(source: *const c_char) -> WeslParseResult { if source.is_null() { - return native::WeslParseResult { + return WeslParseResult { success: false, data: ptr::null_mut(), error: error_from_str("Invalid parameters"), @@ -599,7 +741,7 @@ pub unsafe extern "C" fn wesl_parse(source: *const c_char) -> native::WeslParseR let cstr = unsafe { CStr::from_ptr(source) }; let Ok(str) = cstr.to_str() else { - return native::WeslParseResult { + return WeslParseResult { success: false, data: ptr::null_mut(), error: error_from_str("Source is not valid UTF-8"), @@ -609,13 +751,13 @@ pub unsafe extern "C" fn wesl_parse(source: *const c_char) -> native::WeslParseR match str.parse::() { Ok(unit) => { let ptr = Box::into_raw(Box::new(WeslTranslationUnit { unit })); - native::WeslParseResult { + WeslParseResult { success: true, data: ptr, error: NO_ERROR, } } - Err(e) => native::WeslParseResult { + Err(e) => WeslParseResult { success: false, data: ptr::null_mut(), error: wesl_error_to_c(wesl::Error::ParseError(e)), @@ -626,38 +768,26 @@ pub unsafe extern "C" fn wesl_parse(source: *const c_char) -> native::WeslParseR #[cfg(feature = "eval")] #[unsafe(no_mangle)] pub unsafe extern "C" fn wesl_eval( - files: *const native::WeslStringMap, + files: &WeslStringMap, root: *const c_char, expression: *const c_char, - options: *const native::WeslCompileOptions, - features: *const native::WeslBoolMap, -) -> native::WeslResult { - if files.is_null() || root.is_null() || expression.is_null() || options.is_null() { - return native::WeslResult { - success: false, - data: ptr::null(), - error: native::WeslError { - source: ptr::null(), - message: create_c_string("Invalid parameters"), - diagnostics: ptr::null(), - diagnostics_len: 0, - }, - }; - } - + options: &WeslCompileOptions, + features: Option<&WeslBoolMap>, +) -> WeslResult { let files_map = unsafe { string_map_to_hashmap(files) }; let root_str = unsafe { CStr::from_ptr(root).to_string_lossy() }; let expr_str = unsafe { CStr::from_ptr(expression).to_string_lossy() }; - let opts = unsafe { &*options }; - let features_map = unsafe { bool_map_to_hashmap(features) }; + let features_map = features + .map(|features| unsafe { bool_map_to_hashmap(features) }) + .unwrap_or_default(); let root_path = match root_str.parse() { Ok(path) => path, Err(e) => { - return native::WeslResult { + return WeslResult { success: false, data: ptr::null(), - error: native::WeslError { + error: WeslError { source: ptr::null(), message: create_c_string(&format!("Invalid root path: {e}")), diagnostics: ptr::null(), @@ -677,14 +807,14 @@ pub unsafe extern "C" fn wesl_eval( let mut compiler = Wesl::new_barebones().set_custom_resolver(resolver); let compiler = compiler .set_options(wesl::CompileOptions { - imports: opts.imports, - condcomp: opts.condcomp, - generics: opts.generics, - strip: opts.strip, - lower: opts.lower, - validate: opts.validate, - lazy: opts.lazy, - mangle_root: opts.mangle_root, + imports: options.imports, + condcomp: options.condcomp, + generics: options.generics, + strip: options.strip, + lower: options.lower, + validate: options.validate, + lazy: options.lazy, + mangle_root: options.mangle_root, keep: None, features: wesl::Features { default: wesl::Feature::Disable, @@ -693,30 +823,30 @@ pub unsafe extern "C" fn wesl_eval( .map(|(k, v)| (k, v.into())) .collect(), }, - keep_root: opts.keep_root, + keep_root: options.keep_root, }) - .use_sourcemap(opts.sourcemap) - .set_mangler(map_mangler_kind(opts.mangler).expect("invalid mangler kind")); + .use_sourcemap(options.sourcemap) + .set_mangler(map_mangler_kind(options.mangler).expect("invalid mangler kind")); match compiler.compile(&root_path) { Ok(result) => match result.eval(&expr_str) { - Ok(eval_result) => native::WeslResult { + Ok(eval_result) => WeslResult { success: true, data: create_c_string(&eval_result.inst.to_string()), - error: native::WeslError { + error: WeslError { source: ptr::null(), message: ptr::null(), diagnostics: ptr::null(), diagnostics_len: 0, }, }, - Err(e) => native::WeslResult { + Err(e) => WeslResult { success: false, data: ptr::null(), error: wesl_error_to_c(e), }, }, - Err(e) => native::WeslResult { + Err(e) => WeslResult { success: false, data: ptr::null(), error: wesl_error_to_c(e), @@ -727,54 +857,46 @@ pub unsafe extern "C" fn wesl_eval( #[cfg(not(feature = "eval"))] #[unsafe(no_mangle)] pub unsafe extern "C" fn wesl_eval( - _files: *const native::WeslStringMap, + _files: *const WeslStringMap, _root: *const c_char, _expression: *const c_char, - _options: *const native::WeslCompileOptions, - _features: *const native::WeslBoolMap, -) -> native::WeslResult { + _options: *const WeslCompileOptions, + _features: *const WeslBoolMap, +) -> WeslResult { result_from_str("wesl_eval requires the 'eval' feature to be enabled") } #[cfg(feature = "eval")] #[unsafe(no_mangle)] pub unsafe extern "C" fn wesl_exec( - files: *const native::WeslStringMap, - root: *const c_char, - entrypoint: *const c_char, - options: *const native::WeslCompileOptions, - resources: *const native::WeslBindingArray, - overrides: *const native::WeslStringMap, - features: *const native::WeslBoolMap, -) -> native::WeslExecResult { - if files.is_null() || root.is_null() || entrypoint.is_null() || options.is_null() { - return native::WeslExecResult { - success: false, - resources: ptr::null(), - error: native::WeslError { - source: ptr::null(), - message: create_c_string("Invalid parameters"), - diagnostics: ptr::null(), - diagnostics_len: 0, - }, - }; - } - + files: &WeslStringMap, + root: &c_char, + entrypoint: &c_char, + options: &WeslCompileOptions, + resources: Option<&WeslBindingArray>, + overrides: Option<&WeslStringMap>, + features: Option<&WeslBoolMap>, +) -> WeslExecResult { let files_map = unsafe { string_map_to_hashmap(files) }; let root_str = unsafe { CStr::from_ptr(root).to_string_lossy() }; let entrypoint_str = unsafe { CStr::from_ptr(entrypoint).to_string_lossy() }; - let opts = unsafe { &*options }; - let resources_vec = unsafe { binding_array_to_vec(resources) }; - let overrides_map = unsafe { string_map_to_hashmap(overrides) }; - let features_map = unsafe { bool_map_to_hashmap(features) }; + let resources_vec = resources + .map(|resources| unsafe { binding_array_to_vec(resources) }) + .unwrap_or_default(); + let overrides_map = overrides + .map(|overrides| unsafe { string_map_to_hashmap(overrides) }) + .unwrap_or_default(); + let features_map: HashMap = features + .map(|features| unsafe { bool_map_to_hashmap(features) }) + .unwrap_or_default(); let root_path = match root_str.parse() { Ok(path) => path, Err(e) => { - return native::WeslExecResult { + return WeslExecResult { success: false, resources: ptr::null(), - error: native::WeslError { + error: WeslError { source: ptr::null(), message: create_c_string(&format!("Invalid root path: {e}")), diagnostics: ptr::null(), @@ -794,14 +916,14 @@ pub unsafe extern "C" fn wesl_exec( let mut compiler = Wesl::new_barebones().set_custom_resolver(resolver); let compiler = compiler .set_options(wesl::CompileOptions { - imports: opts.imports, - condcomp: opts.condcomp, - generics: opts.generics, - strip: opts.strip, - lower: opts.lower, - validate: opts.validate, - lazy: opts.lazy, - mangle_root: opts.mangle_root, + imports: options.imports, + condcomp: options.condcomp, + generics: options.generics, + strip: options.strip, + lower: options.lower, + validate: options.validate, + lazy: options.lazy, + mangle_root: options.mangle_root, keep: None, features: wesl::Features { default: wesl::Feature::Disable, @@ -810,10 +932,10 @@ pub unsafe extern "C" fn wesl_exec( .map(|(k, v)| (k, v.into())) .collect(), }, - keep_root: opts.keep_root, + keep_root: options.keep_root, }) - .use_sourcemap(opts.sourcemap) - .set_mangler(map_mangler_kind(opts.mangler).expect("invalid mangler kind")); + .use_sourcemap(options.sourcemap) + .set_mangler(map_mangler_kind(options.mangler).expect("invalid mangler kind")); match compiler.compile(&root_path) { Ok(result) => { @@ -827,7 +949,7 @@ pub unsafe extern "C" fn wesl_exec( let parsed_resources = match parsed_resources { Ok(resources) => resources, Err(e) => { - return native::WeslExecResult { + return WeslExecResult { success: false, resources: ptr::null(), error: wesl_error_to_c(e), @@ -853,7 +975,7 @@ pub unsafe extern "C" fn wesl_exec( let parsed_overrides = match parsed_overrides { Ok(overrides) => overrides, Err(e) => { - return native::WeslExecResult { + return WeslExecResult { success: false, resources: ptr::null(), error: wesl_error_to_c(e), @@ -866,7 +988,7 @@ pub unsafe extern "C" fn wesl_exec( match result.exec(&entrypoint_str, inputs, parsed_resources, parsed_overrides) { Ok(exec_result) => { // convert resources back to C format - let output_resources: Vec = resources_vec + let output_resources: Vec = resources_vec .iter() .filter_map(|r| { let resource = exec_result.resource(r.group, r.binding)?; @@ -881,10 +1003,10 @@ pub unsafe extern "C" fn wesl_exec( }) .collect(); - native::WeslExecResult { + WeslExecResult { success: true, resources: create_c_binding_array(output_resources), - error: native::WeslError { + error: WeslError { source: ptr::null(), message: ptr::null(), diagnostics: ptr::null(), @@ -892,14 +1014,14 @@ pub unsafe extern "C" fn wesl_exec( }, } } - Err(e) => native::WeslExecResult { + Err(e) => WeslExecResult { success: false, resources: ptr::null(), error: wesl_error_to_c(e), }, } } - Err(e) => native::WeslExecResult { + Err(e) => WeslExecResult { success: false, resources: ptr::null(), error: wesl_error_to_c(e), @@ -910,15 +1032,15 @@ pub unsafe extern "C" fn wesl_exec( #[cfg(not(feature = "eval"))] #[unsafe(no_mangle)] pub unsafe extern "C" fn wesl_exec( - _files: *const native::WeslStringMap, + _files: *const WeslStringMap, _root: *const c_char, _entrypoint: *const c_char, - _options: *const native::WeslCompileOptions, - _resources: *const native::WeslBindingArray, - _overrides: *const native::WeslStringMap, - _features: *const native::WeslBoolMap, -) -> native::WeslExecResult { - native::WeslExecResult { + _options: *const WeslCompileOptions, + _resources: *const WeslBindingArray, + _overrides: *const WeslStringMap, + _features: *const WeslBoolMap, +) -> WeslExecResult { + WeslExecResult { success: false, resources: ptr::null(), error: error_from_str("wesl_exec requires the 'eval' feature to be enabled"), @@ -934,7 +1056,7 @@ pub unsafe extern "C" fn wesl_free_string(ptr: *const c_char) { } } -unsafe fn free_error(error: &native::WeslError) { +unsafe fn free_error(error: &WeslError) { unsafe { if !error.source.is_null() { wesl_free_string(error.source); @@ -952,13 +1074,13 @@ unsafe fn free_error(error: &native::WeslError) { if !diag.title.is_null() { wesl_free_string(diag.title); } - let _ = Box::from_raw(error.diagnostics as *mut native::WeslDiagnostic); + let _ = Box::from_raw(error.diagnostics as *mut WeslDiagnostic); } } } #[unsafe(no_mangle)] -pub unsafe extern "C" fn wesl_free_result(result: *mut native::WeslResult) { +pub unsafe extern "C" fn wesl_free_result(result: *mut WeslResult) { if !result.is_null() { unsafe { let result = &mut *result; @@ -971,7 +1093,7 @@ pub unsafe extern "C" fn wesl_free_result(result: *mut native::WeslResult) { } #[unsafe(no_mangle)] -pub unsafe extern "C" fn wesl_free_exec_result(result: *mut native::WeslExecResult) { +pub unsafe extern "C" fn wesl_free_exec_result(result: *mut WeslExecResult) { if !result.is_null() { unsafe { let result = &mut *result; @@ -991,11 +1113,11 @@ pub unsafe extern "C" fn wesl_free_exec_result(result: *mut native::WeslExecResu } let _ = Box::from_raw(std::ptr::slice_from_raw_parts_mut( - resources.items as *mut native::WeslBinding, + resources.items as *mut WeslBinding, resources.len, )); - let _ = Box::from_raw(result.resources as *mut native::WeslBindingArray); + let _ = Box::from_raw(result.resources as *mut WeslBindingArray); } free_error(&result.error); @@ -1004,7 +1126,7 @@ pub unsafe extern "C" fn wesl_free_exec_result(result: *mut native::WeslExecResu } #[unsafe(no_mangle)] -pub unsafe extern "C" fn wesl_free_parse_result(result: *mut native::WeslParseResult) { +pub unsafe extern "C" fn wesl_free_parse_result(result: *mut WeslParseResult) { if !result.is_null() { unsafe { let result = &*result; diff --git a/crates/wesl-cli/src/main.rs b/crates/wesl-cli/src/main.rs index c4866d6..0120539 100644 --- a/crates/wesl-cli/src/main.rs +++ b/crates/wesl-cli/src/main.rs @@ -1,6 +1,6 @@ //! The Command-line interface for `wesl-rs`. -use clap::{Args, Parser, Subcommand, ValueEnum, command}; +use clap::{Args, Parser, Subcommand, ValueEnum}; use std::{ convert::Infallible, error::Error, diff --git a/deny.toml b/deny.toml index c7aaf71..9421e59 100644 --- a/deny.toml +++ b/deny.toml @@ -17,6 +17,7 @@ allow = [ "ISC", "MIT", "MIT-0", + "MPL-2.0", "Unlicense", "Zlib", ]