ploidy_core/codegen/
mod.rs

1use std::path::Path;
2
3use miette::{Context, IntoDiagnostic};
4
5pub mod unique;
6
7pub use unique::{UniqueNames, WordSegments};
8
9pub fn write_to_disk(output: &Path, code: impl IntoCode) -> miette::Result<()> {
10    let code = code.into_code();
11    let path = output.join(code.path());
12    let string = code.into_string()?;
13    if let Some(parent) = path.parent() {
14        std::fs::create_dir_all(parent)
15            .into_diagnostic()
16            .with_context(|| format!("Failed to create directory `{}`", parent.display()))?;
17    }
18    std::fs::write(&path, string)
19        .into_diagnostic()
20        .with_context(|| format!("Failed to write `{}`", path.display()))?;
21    Ok(())
22}
23
24pub trait Code {
25    fn path(&self) -> &str;
26    fn into_string(self) -> miette::Result<String>;
27}
28
29#[cfg(feature = "proc-macro2")]
30impl<T: AsRef<str>> Code for (T, proc_macro2::TokenStream) {
31    fn path(&self) -> &str {
32        self.0.as_ref()
33    }
34
35    fn into_string(self) -> miette::Result<String> {
36        use quote::ToTokens;
37        let file = syn::parse2(self.1.into_token_stream()).into_diagnostic();
38        match file {
39            Ok(file) => Ok(prettyplease::unparse(&file)),
40            Err(err) => Err(err.context(format!("Failed to format `{}`", self.0.as_ref()))),
41        }
42    }
43}
44
45#[cfg(feature = "cargo_toml")]
46impl<T: serde::Serialize> Code for (&'static str, cargo_toml::Manifest<T>) {
47    fn path(&self) -> &str {
48        self.0
49    }
50
51    fn into_string(self) -> miette::Result<String> {
52        toml::to_string_pretty(&self.1)
53            .into_diagnostic()
54            .with_context(|| format!("Failed to serialize `{}`", self.0))
55    }
56}
57
58pub trait IntoCode {
59    type Code: Code;
60
61    fn into_code(self) -> Self::Code;
62}
63
64impl<T: Code> IntoCode for T {
65    type Code = T;
66
67    fn into_code(self) -> Self::Code {
68        self
69    }
70}