diff --git a/Cargo.lock b/Cargo.lock index 68d6fd3..4b605bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,6 +35,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "dylo" version = "1.0.1" @@ -45,7 +57,9 @@ version = "1.0.3" dependencies = [ "camino", "fs-err", + "insta", "pico-args", + "prettyplease", "proc-macro2", "quote", "rustfmt-wrapper", @@ -63,6 +77,12 @@ dependencies = [ "rubicon", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "equivalent" version = "1.0.1" @@ -119,6 +139,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "insta" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "similar", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -131,6 +163,12 @@ version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -189,6 +227,16 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -335,6 +383,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + [[package]] name = "smallvec" version = "1.13.2" diff --git a/Justfile b/Justfile index f95548b..992bff0 100644 --- a/Justfile +++ b/Justfile @@ -1,3 +1,3 @@ test: - cargo build --release -p dylo-runtime + cargo t diff --git a/dylo-cli/Cargo.toml b/dylo-cli/Cargo.toml index b97a58c..f138658 100644 --- a/dylo-cli/Cargo.toml +++ b/dylo-cli/Cargo.toml @@ -27,3 +27,7 @@ toml_edit = "0.22.22" camino = "1.1.9" pico-args = "0.5.0" tracing = "0.1.41" +prettyplease = "0.2.25" + +[dev-dependencies] +insta = "1.41.1" diff --git a/dylo-cli/src/main.rs b/dylo-cli/src/main.rs index b0a4b4d..5fb9cb3 100644 --- a/dylo-cli/src/main.rs +++ b/dylo-cli/src/main.rs @@ -490,28 +490,29 @@ fn process_mod(mod_info: ModInfo, force: bool) -> std::io::Result<()> { Ok(()) } -fn item_attributes(item: &Item) -> Option<&Vec> { +fn item_attributes(item: &mut Item) -> Option<&mut Vec> { match item { - Item::Const(item) => Some(&item.attrs), - Item::Enum(item) => Some(&item.attrs), - Item::ExternCrate(item) => Some(&item.attrs), - Item::Fn(item) => Some(&item.attrs), - Item::ForeignMod(item) => Some(&item.attrs), - Item::Impl(item) => Some(&item.attrs), - Item::Macro(item) => Some(&item.attrs), - Item::Mod(item) => Some(&item.attrs), - Item::Static(item) => Some(&item.attrs), - Item::Struct(item) => Some(&item.attrs), - Item::Trait(item) => Some(&item.attrs), - Item::TraitAlias(item) => Some(&item.attrs), - Item::Type(item) => Some(&item.attrs), - Item::Union(item) => Some(&item.attrs), - Item::Use(item) => Some(&item.attrs), + Item::Const(item) => Some(&mut item.attrs), + Item::Enum(item) => Some(&mut item.attrs), + Item::ExternCrate(item) => Some(&mut item.attrs), + Item::Fn(item) => Some(&mut item.attrs), + Item::ForeignMod(item) => Some(&mut item.attrs), + Item::Impl(item) => Some(&mut item.attrs), + Item::Macro(item) => Some(&mut item.attrs), + Item::Mod(item) => Some(&mut item.attrs), + Item::Static(item) => Some(&mut item.attrs), + Item::Struct(item) => Some(&mut item.attrs), + Item::Trait(item) => Some(&mut item.attrs), + Item::TraitAlias(item) => Some(&mut item.attrs), + Item::Type(item) => Some(&mut item.attrs), + Item::Union(item) => Some(&mut item.attrs), + Item::Use(item) => Some(&mut item.attrs), Item::Verbatim(_) => None, _ => None, } } +// recognizes `#[cfg(feature = "impl"]` fn is_cfg_feature_impl(attr: &Attribute) -> bool { if !attr.path().is_ident("cfg") { return false; @@ -530,6 +531,32 @@ fn is_cfg_feature_impl(attr: &Attribute) -> bool { has_feature_impl } +// recognizes `#[cfg(not(feature = "impl"))]` +fn is_cfg_not_feature_impl(attr: &Attribute) -> bool { + if !attr.path().is_ident("cfg") { + return false; + } + + let mut has_not = false; + let mut has_feature_impl = false; + let _ = attr.parse_nested_meta(|meta| { + if meta.path.is_ident("not") { + let _ = meta.parse_nested_meta(|meta| { + if meta.path.is_ident("feature") { + let content = meta.input.to_string(); + if content == "= \"impl\"" { + has_feature_impl = true; + } + } + Ok(()) + }); + has_not = true; + } + Ok(()) + }); + has_not && has_feature_impl +} + fn is_cfg_test(attr: &Attribute) -> bool { if !attr.path().is_ident("cfg") { return false; @@ -545,7 +572,7 @@ fn is_cfg_test(attr: &Attribute) -> bool { has_test } -fn should_remove_item(item: &Item) -> bool { +fn should_remove_item(item: &mut Item) -> bool { if let Some(attrs) = item_attributes(item) { for attr in attrs { if is_cfg_feature_impl(attr) || is_cfg_test(attr) { @@ -580,7 +607,7 @@ impl InterfaceType { } } -fn transform_ast(items: &mut Vec, added_items: &mut Vec) { +pub(crate) fn transform_ast(items: &mut Vec, added_items: &mut Vec) { items.retain_mut(|item| { let mut keep = true; @@ -627,7 +654,13 @@ fn transform_ast(items: &mut Vec, added_items: &mut Vec) { if should_remove_item(item) { keep = false + } else { + // remove any cfg(not(feature = "impl")) attributes + if let Some(attrs) = item_attributes(item) { + attrs.retain(|attr| !is_cfg_not_feature_impl(attr)); + } } + keep }); } @@ -817,3 +850,6 @@ fn main() -> std::io::Result<()> { Ok(()) } + +#[cfg(test)] +mod tests; diff --git a/dylo-cli/src/snapshots/dylo__tests__snapshot_simple_module.snap b/dylo-cli/src/snapshots/dylo__tests__snapshot_simple_module.snap new file mode 100644 index 0000000..f6d49b3 --- /dev/null +++ b/dylo-cli/src/snapshots/dylo__tests__snapshot_simple_module.snap @@ -0,0 +1,18 @@ +--- +source: dylo-cli/src/tests.rs +expression: output +snapshot_kind: text +--- +fn not_impl_only() {} +enum NotImplEnum { + Variant1, + Variant2, +} +impl NotImplEnum { + fn variant1(&self) -> u32 { + 23 + } +} +pub trait Mod: Send + Sync + 'static { + fn foo(&self) -> u32; +} diff --git a/dylo-cli/src/testdata/simple-module.rs b/dylo-cli/src/testdata/simple-module.rs new file mode 100644 index 0000000..1e3a333 --- /dev/null +++ b/dylo-cli/src/testdata/simple-module.rs @@ -0,0 +1,43 @@ +#[cfg(feature = "impl")] +use impl_only; + +#[cfg(feature = "impl")] +fn impl_only() {} + +#[cfg(not(feature = "impl"))] +fn not_impl_only() {} + +#[cfg(feature = "impl")] +#[derive(Default)] +struct ModImpl; + +#[dylo::export] +impl Mod for ModImpl { + fn foo(&self) -> u32 { + 42 + } +} + +#[cfg(feature = "impl")] +enum ImplEnum { + Variant1, + Variant2, +} + +#[cfg(feature = "impl")] +impl ImplEnum { + fn variant1(&self) -> u32 { + 23 + } +} + +enum NotImplEnum { + Variant1, + Variant2, +} + +impl NotImplEnum { + fn variant1(&self) -> u32 { + 23 + } +} diff --git a/dylo-cli/src/tests.rs b/dylo-cli/src/tests.rs new file mode 100644 index 0000000..004cd91 --- /dev/null +++ b/dylo-cli/src/tests.rs @@ -0,0 +1,15 @@ +use super::*; + +#[test] +fn snapshot_simple_module() { + let input_rs = include_str!("testdata/simple-module.rs"); + let mut file = syn::parse_file(input_rs).unwrap(); + + let mut added_items = Vec::new(); + transform_ast(&mut file.items, &mut added_items); + + file.items.extend(added_items); + + let output = prettyplease::unparse(&file); + insta::assert_snapshot!(output); +} diff --git a/dylo-runtime/README.md b/dylo-runtime/README.md index 568933b..4dee127 100644 --- a/dylo-runtime/README.md +++ b/dylo-runtime/README.md @@ -28,7 +28,7 @@ should be pre-built, and put in the right place, next to the executable. That is, if your Cargo workspace looks like this: -``` +```text,ignore workspace/ Cargo.toml mods/ @@ -43,7 +43,7 @@ workspace/ Then `dylo-runtime` expects a file hierarchy like this: -``` +```text,ignore workspace/ target/ debug/ diff --git a/test-workspace/Cargo.toml b/test-workspace/Cargo.toml deleted file mode 100644 index 817396b..0000000 --- a/test-workspace/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[workspace] -members = [ - "app", - "mods/*", -] -exclude = [ - "test-workspace", -] -resolver = "2" - -[profile.dev] -debug = 1 -split-debuginfo = "unpacked" -incremental = true - -[profile.dev.package."*"] -opt-level = 2 - -[profile.release] -debug = 1 -lto = "off" -split-debuginfo = "unpacked" diff --git a/test-workspace/app/Cargo.toml b/test-workspace/app/Cargo.toml deleted file mode 100644 index 211d3b2..0000000 --- a/test-workspace/app/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "app" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/test-workspace/app/src/main.rs b/test-workspace/app/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/test-workspace/app/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/test-workspace/mods/mod-clap/Cargo.toml b/test-workspace/mods/mod-clap/Cargo.toml deleted file mode 100644 index 17bb7bf..0000000 --- a/test-workspace/mods/mod-clap/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "mod-clap" -version = "0.1.0" -edition = "2021" - -[dependencies] diff --git a/test-workspace/mods/mod-clap/src/lib.rs b/test-workspace/mods/mod-clap/src/lib.rs deleted file mode 100644 index b93cf3f..0000000 --- a/test-workspace/mods/mod-clap/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -}