diff --git a/Cargo.lock b/Cargo.lock index a72cba82c..2ae04279b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1086,11 +1086,21 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -1364,9 +1374,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "syn" -version = "2.0.53" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -2426,8 +2436,10 @@ dependencies = [ "clap", "heck 0.5.0", "indexmap", + "prettyplease", "serde", "serde_json", + "syn", "test-helpers", "wasm-metadata", "wit-bindgen", @@ -2440,6 +2452,7 @@ name = "wit-bindgen-rust-macro" version = "0.26.0" dependencies = [ "anyhow", + "prettyplease", "proc-macro2", "quote", "syn", diff --git a/Cargo.toml b/Cargo.toml index a0b22e44b..a53c5af83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ heck = { version = "0.5" } pulldown-cmark = { version = "0.9", default-features = false } clap = { version = "4.3.19", features = ["derive"] } indexmap = "2.0.0" +prettyplease = "0.2.20" +syn = { version = "2.0", features = ["printing"] } wasmparser = "0.209.0" wasm-encoder = "0.209.0" diff --git a/crates/core/src/source.rs b/crates/core/src/source.rs index f86080d46..fb2bfd2e7 100644 --- a/crates/core/src/source.rs +++ b/crates/core/src/source.rs @@ -118,6 +118,10 @@ impl Source { pub fn as_mut_string(&mut self) -> &mut String { &mut self.s } + + pub fn as_str(&self) -> &str { + &self.s + } } impl Write for Source { diff --git a/crates/guest-rust/macro/Cargo.toml b/crates/guest-rust/macro/Cargo.toml index e44fbe532..5d56c3c82 100644 --- a/crates/guest-rust/macro/Cargo.toml +++ b/crates/guest-rust/macro/Cargo.toml @@ -17,8 +17,10 @@ test = false [dependencies] proc-macro2 = "1.0" -syn = { version = "2.0", features = ["printing"] } quote = "1" wit-bindgen-core = { workspace = true } wit-bindgen-rust = { workspace = true } anyhow = { workspace = true } +syn = { workspace = true } +prettyplease = { workspace = true } + diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index 1ab323f6e..bbc9eb5b5 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -191,15 +191,12 @@ impl Config { let n = INVOCATION.fetch_add(1, Relaxed); let path = root.join(format!("{world_name}{n}.rs")); - std::fs::write(&path, &src).unwrap(); - // optimistically format the code but don't require success - drop( - std::process::Command::new("rustfmt") - .arg(&path) - .arg("--edition=2021") - .output(), - ); + let contents = match fmt(&src) { + Ok(formatted) => formatted, + Err(_) => src.clone(), + }; + std::fs::write(&path, contents.as_bytes()).unwrap(); src = format!("include!({path:?});"); } @@ -472,3 +469,9 @@ fn with_field_parse(input: ParseStream<'_>) -> Result<(String, String)> { Ok((interface, buf)) } + +/// Format a valid Rust string +fn fmt(input: &str) -> Result { + let syntax_tree = syn::parse_file(&input)?; + Ok(prettyplease::unparse(&syntax_tree)) +} diff --git a/crates/rust/Cargo.toml b/crates/rust/Cargo.toml index b585d3d5f..82925a3bd 100644 --- a/crates/rust/Cargo.toml +++ b/crates/rust/Cargo.toml @@ -23,6 +23,8 @@ wasm-metadata = { workspace = true } heck = { workspace = true } clap = { workspace = true, optional = true } indexmap = { workspace = true } +syn = { workspace = true } +prettyplease = { workspace = true } [dev-dependencies] wit-bindgen = { path = '../guest-rust' } diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index f57202614..e4d79e0fd 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -4,9 +4,7 @@ use heck::*; use indexmap::IndexSet; use std::collections::{BTreeMap, HashMap, HashSet}; use std::fmt::{self, Write as _}; -use std::io::{Read, Write}; use std::mem; -use std::process::{Command, Stdio}; use std::str::FromStr; use wit_bindgen_core::abi::{Bitcast, WasmType}; use wit_bindgen_core::{ @@ -86,9 +84,9 @@ fn parse_with(s: &str) -> Result<(String, String), String> { #[derive(Default, Debug, Clone)] #[cfg_attr(feature = "clap", derive(clap::Args))] pub struct Opts { - /// Whether or not `rustfmt` is executed to format generated code. + /// Whether or not a formatter is executed to format generated code. #[cfg_attr(feature = "clap", arg(long))] - pub rustfmt: bool, + pub format: bool, /// If true, code generation should qualify any features that depend on /// `std` with `cfg(feature = "std")`. @@ -1022,28 +1020,9 @@ impl WorldGenerator for RustWasm { } let mut src = mem::take(&mut self.src); - if self.opts.rustfmt { - let mut child = Command::new("rustfmt") - .arg("--edition=2018") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect("failed to spawn `rustfmt`"); - child - .stdin - .take() - .unwrap() - .write_all(src.as_bytes()) - .unwrap(); - src.as_mut_string().truncate(0); - child - .stdout - .take() - .unwrap() - .read_to_string(src.as_mut_string()) - .unwrap(); - let status = child.wait().unwrap(); - assert!(status.success()); + if self.opts.format { + let syntax_tree = syn::parse_file(src.as_str()).unwrap(); + *src.as_mut_string() = prettyplease::unparse(&syntax_tree); } let module_name = name.to_snake_case();