gravitron_macro_utils/
lib.rs1extern crate proc_macro;
2
3use std::{env, path::PathBuf};
4
5use proc_macro::TokenStream;
6use toml_edit::{DocumentMut, Item};
7
8pub struct Manifest {
9 doc: DocumentMut,
10}
11
12impl Default for Manifest {
13 fn default() -> Self {
14 Self {
15 doc: env::var_os("CARGO_MANIFEST_DIR")
16 .map(PathBuf::from)
17 .map(|mut path| {
18 path.push("Cargo.toml");
19 if !path.exists() {
20 panic!("No Cargo.toml found. Expected: {}", path.display());
21 }
22 let manifest = std::fs::read_to_string(path.clone())
23 .unwrap_or_else(|_| panic!("Unable to read Cargo.toml: {}", path.display()));
24 manifest
25 .parse::<DocumentMut>()
26 .unwrap_or_else(|_| panic!("Failed to parse Cargo.toml: {}", path.display()))
27 })
28 .expect("CARGO_MANIFEST_DIR not defined."),
29 }
30 }
31}
32
33const GRAVITRON: &str = "gravitron";
34
35impl Manifest {
36 pub fn get_path(&self, name: &str) -> syn::Path {
37 self.try_get_path(name).unwrap_or_else(|| parse_str(name))
38 }
39
40 pub fn try_get_path(&self, name: &str) -> Option<syn::Path> {
41 fn dep_package(dep: &Item) -> Option<&str> {
42 if dep.as_str().is_some() {
43 None
44 } else {
45 dep.get("package").map(|name| name.as_str().unwrap())
46 }
47 }
48
49 let find = |d: &Item| {
50 let dep = if let Some(dep) = d.get(name) {
51 return Some(parse_str(dep_package(dep).unwrap_or(name)));
52 } else if let Some(dep) = d.get(GRAVITRON) {
53 dep_package(dep).unwrap_or(GRAVITRON)
54 } else {
55 return None;
56 };
57
58 let mut path = parse_str::<syn::Path>(dep);
59 if let Some(module) = name.strip_prefix("gravitron_") {
60 path.segments.push(parse_str(module));
61 }
62 Some(path)
63 };
64
65 let dependencies = self.doc.get("dependencies");
66 let dev_dependencies = self.doc.get("dev-dependencies");
67
68 dependencies
69 .and_then(find)
70 .or_else(|| dev_dependencies.and_then(find))
71 }
72}
73
74fn try_parse_str<T: syn::parse::Parse>(path: &str) -> Option<T> {
75 syn::parse(path.parse::<TokenStream>().ok()?).ok()
76}
77
78fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
79 try_parse_str(path).unwrap()
80}