#![allow(rustdoc::broken_intra_doc_links)]
#![doc = include_str!("../README.md")]
use proc_macro::TokenStream;
mod derive;
mod observe;
#[proc_macro_derive(Observe, attributes(muon))]
pub fn derive_observe(input: TokenStream) -> TokenStream {
let input: syn::DeriveInput = syn::parse_macro_input!(input);
derive::derive_observe(input).into()
}
#[proc_macro]
pub fn observe(input: TokenStream) -> TokenStream {
let input: observe::ObserveInput = syn::parse_macro_input!(input);
observe::observe(input).into()
}
#[cfg(test)]
mod test {
use std::env::var;
use std::fs::{create_dir_all, read_to_string, write};
use std::path::{Path, PathBuf};
use macro_expand::Context;
use pretty_assertions::StrComparison;
use prettyplease::unparse;
use walkdir::WalkDir;
struct TestDiff {
path: PathBuf,
expect: String,
actual: String,
}
#[test]
fn fixtures() {
let input_dir = "fixtures/input";
let output_dir = "fixtures/output";
let mut diffs = vec![];
let will_emit = var("EMIT").is_ok_and(|v| !v.is_empty());
for entry in WalkDir::new(input_dir).into_iter().filter_map(Result::ok) {
let input_path = entry.path();
if !input_path.is_file() || input_path.extension() != Some("rs".as_ref()) {
continue;
}
let path = input_path.strip_prefix(input_dir).unwrap();
let output_path = Path::new(output_dir).join(path);
let input = read_to_string(input_path).unwrap().parse().unwrap();
let mut ctx = Context::new();
ctx.module("muon")
.proc_macro("observe", crate::observe::observe)
.proc_macro_derive("Observe", crate::derive::derive_observe, vec!["muon".into()]);
let actual = unparse(&syn::parse2(ctx.transform(input)).unwrap());
let expect_result = read_to_string(&output_path);
if let Ok(expect) = &expect_result
&& expect == &actual
{
continue;
}
if will_emit {
create_dir_all(output_path.parent().unwrap()).unwrap();
write(output_path, &actual).unwrap();
}
if let Ok(expect) = expect_result {
diffs.push(TestDiff {
path: path.to_path_buf(),
expect,
actual,
});
}
}
let len = diffs.len();
for diff in diffs {
eprintln!("diff {}", diff.path.display());
eprintln!("{}", StrComparison::new(&diff.expect, &diff.actual));
}
if len > 0 && !will_emit {
panic!("Some tests failed");
}
}
}