bevy_macro_utils/
bevy_manifest.rs1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use std::{env, path::PathBuf};
5use toml_edit::{DocumentMut, Item};
6
7pub struct BevyManifest {
9 manifest: DocumentMut,
10}
11
12impl Default for BevyManifest {
13 fn default() -> Self {
14 Self {
15 manifest: 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!(
21 "No Cargo manifest found for crate. Expected: {}",
22 path.display()
23 );
24 }
25 let manifest = std::fs::read_to_string(path.clone()).unwrap_or_else(|_| {
26 panic!("Unable to read cargo manifest: {}", path.display())
27 });
28 manifest.parse::<DocumentMut>().unwrap_or_else(|_| {
29 panic!("Failed to parse cargo manifest: {}", path.display())
30 })
31 })
32 .expect("CARGO_MANIFEST_DIR is not defined."),
33 }
34 }
35}
36const BEVY: &str = "bevy";
37const BEVY_INTERNAL: &str = "bevy_internal";
38
39impl BevyManifest {
40 pub fn maybe_get_path(&self, name: &str) -> Option<syn::Path> {
43 fn dep_package(dep: &Item) -> Option<&str> {
44 if dep.as_str().is_some() {
45 None
46 } else {
47 dep.get("package").map(|name| name.as_str().unwrap())
48 }
49 }
50
51 let find_in_deps = |deps: &Item| -> Option<syn::Path> {
52 let package = if let Some(dep) = deps.get(name) {
53 return Some(Self::parse_str(dep_package(dep).unwrap_or(name)));
54 } else if let Some(dep) = deps.get(BEVY) {
55 dep_package(dep).unwrap_or(BEVY)
56 } else if let Some(dep) = deps.get(BEVY_INTERNAL) {
57 dep_package(dep).unwrap_or(BEVY_INTERNAL)
58 } else {
59 return None;
60 };
61
62 let mut path = Self::parse_str::<syn::Path>(package);
63 if let Some(module) = name.strip_prefix("bevy_") {
64 path.segments.push(Self::parse_str(module));
65 }
66 Some(path)
67 };
68
69 let deps = self.manifest.get("dependencies");
70 let deps_dev = self.manifest.get("dev-dependencies");
71
72 deps.and_then(find_in_deps)
73 .or_else(|| deps_dev.and_then(find_in_deps))
74 }
75
76 pub fn get_path_direct(name: &str) -> syn::Path {
88 Self::default().get_path(name)
89 }
90
91 pub fn get_path(&self, name: &str) -> syn::Path {
93 self.maybe_get_path(name)
94 .unwrap_or_else(|| Self::parse_str(name))
95 }
96
97 pub fn try_parse_str<T: syn::parse::Parse>(path: &str) -> Option<T> {
99 syn::parse(path.parse::<TokenStream>().ok()?).ok()
100 }
101
102 pub fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
110 Self::try_parse_str(path).unwrap()
111 }
112
113 pub fn get_subcrate(&self, subcrate: &str) -> Option<syn::Path> {
115 self.maybe_get_path(BEVY)
116 .map(|bevy_path| {
117 let mut segments = bevy_path.segments;
118 segments.push(BevyManifest::parse_str(subcrate));
119 syn::Path {
120 leading_colon: None,
121 segments,
122 }
123 })
124 .or_else(|| self.maybe_get_path(&format!("bevy_{subcrate}")))
125 }
126}