Skip to main content

openapi_trait_shared/
debug.rs

1//! Optional, env-var-gated dump of generated code for local inspection.
2//!
3//! Unlike `cargo expand`, this writes only the tokens a backend macro produced
4//! directly — it does not recursively expand the nested derives and macros
5//! inside that output — which keeps the dump focused on the code generation
6//! under inspection.
7
8use std::path::PathBuf;
9
10/// Environment variable that enables and (optionally) locates the dump.
11const ENV_VAR: &str = "OPENAPI_TRAIT_DEBUG";
12
13/// Write a prettyprinted copy of `expanded` to disk when debug output is
14/// enabled.
15///
16/// Whether anything is written is decided at macro-expansion time from the
17/// `OPENAPI_TRAIT_DEBUG` environment variable:
18///
19/// - unset, empty, `0`, or `false` — disabled (no-op).
20/// - `1` or `true` — write to the default directory.
21/// - any other value — used verbatim as the target directory path.
22///
23/// The default directory is `$OUT_DIR/openapi-trait-debug` when `OUT_DIR` is
24/// set (i.e. the consuming crate has a build script), otherwise
25/// `<system temp dir>/openapi-trait-debug`. The file is named after the
26/// generated module (`<mod_ident>.rs`), and the resolved path is printed to
27/// stderr.
28///
29/// Failures are reported to stderr but never abort compilation: debug output
30/// is a convenience and must not turn a buildable crate into a broken one
31/// (e.g. on read-only filesystems).
32pub fn write_debug_output(mod_ident: &syn::Ident, expanded: &proc_macro2::TokenStream) {
33    let Some(dir) = resolve_dir() else {
34        return;
35    };
36
37    let path = dir.join(format!("{mod_ident}.rs"));
38
39    let formatted = syn::parse2::<syn::File>(expanded.clone()).map_or_else(
40        |_| expanded.to_string(),
41        |file| prettyplease::unparse(&file),
42    );
43
44    match std::fs::create_dir_all(&dir).and_then(|()| std::fs::write(&path, formatted)) {
45        Ok(()) => eprintln!("openapi-trait: wrote debug output to {}", path.display()),
46        Err(error) => eprintln!(
47            "openapi-trait: failed to write debug output to {}: {error}",
48            path.display()
49        ),
50    }
51}
52
53/// Resolve the target directory, or `None` when debug output is disabled.
54fn resolve_dir() -> Option<PathBuf> {
55    let value = std::env::var(ENV_VAR).ok()?;
56
57    match value.trim() {
58        "" | "0" | "false" => None,
59        "1" | "true" => Some(default_dir()),
60        path => Some(PathBuf::from(path)),
61    }
62}
63
64/// Default dump directory when the env var is a plain on/off toggle.
65fn default_dir() -> PathBuf {
66    std::env::var_os("OUT_DIR")
67        .map_or_else(std::env::temp_dir, PathBuf::from)
68        .join("openapi-trait-debug")
69}