1#![doc = include_str!("../README.md")]
2use std::{path::PathBuf, process::Command};
5
6use proc_macro::{TokenStream, TokenTree};
7
8#[proc_macro]
14pub fn export_coda(tokens: TokenStream) -> TokenStream {
15 let coda_path = parse_token_string(tokens);
16
17 let workspace_toml = Command::new(env!("CARGO"))
19 .arg("locate-project")
20 .arg("--workspace")
21 .arg("--message-format=plain")
22 .output()
23 .unwrap()
24 .stdout;
25 let workspace_toml = String::from_utf8_lossy(&workspace_toml);
26 let workspace_root = PathBuf::from(workspace_toml.trim());
27 let workspace_root = workspace_root.parent().unwrap();
28
29 let path = workspace_root.join(coda_path);
31
32 let coda = std::fs::read_to_string(path.clone()).unwrap();
34 let coda = codas::parse::parse(&coda).unwrap();
35
36 let mut codegen = vec![];
38 #[cfg(feature = "serde")]
39 {
40 codas::langs::rust::generate_types(&coda, &mut codegen, true).unwrap();
41 }
42 #[cfg(not(feature = "serde"))]
43 {
44 codas::langs::rust::generate_types(&coda, &mut codegen, false).unwrap();
45 }
46 let codegen = String::from_utf8_lossy(&codegen);
47
48 let mut codegen_prefix = format!(
52 r#"
53 const _: &str = include_str!("{}");
54 "#,
55 path.display()
56 );
57 codegen_prefix += &codegen;
58
59 codegen_prefix.parse().unwrap()
60}
61
62fn parse_token_string(tokens: TokenStream) -> String {
65 let mut coda = match tokens.into_iter().next() {
67 Some(TokenTree::Literal(string)) => string.to_string(),
68 _ => panic!("rly?"),
69 };
70
71 if coda.starts_with("r#") {
73 coda.remove(0); coda.remove(0); coda.remove(coda.len() - 1); }
77
78 coda.remove(0);
80 coda.remove(coda.len() - 1);
81
82 coda
83}