Skip to content

Commit 2322b82

Browse files
bushrat011899ameknite
authored andcommitted
Moved fq_std from bevy_reflect_derive to bevy_macro_utils (bevyengine#9956)
# Objective - Fixes bevyengine#9363 ## Solution Moved `fq_std` from `bevy_reflect_derive` to `bevy_macro_utils`. This does make the `FQ*` types public where they were previously private, which is a change to the public-facing API, but I don't believe a breaking one. Additionally, I've done a basic QA pass over the `bevy_macro_utils` crate, adding `deny(unsafe)`, `warn(missing_docs)`, and documentation where required.
1 parent aaacbd2 commit 2322b82

File tree

18 files changed

+384
-337
lines changed

18 files changed

+384
-337
lines changed

crates/bevy_macro_utils/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ toml_edit = "0.19"
1313
syn = "2.0"
1414
quote = "1.0"
1515
rustc-hash = "1.0"
16+
proc-macro2 = "1.0"

crates/bevy_macro_utils/src/attrs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use syn::{Expr, ExprLit, Lit};
22

33
use crate::symbol::Symbol;
44

5+
/// Get a [literal string](struct@syn::LitStr) from the provided [expression](Expr).
56
pub fn get_lit_str(attr_name: Symbol, value: &Expr) -> syn::Result<&syn::LitStr> {
67
if let Expr::Lit(ExprLit {
78
lit: Lit::Str(lit), ..
@@ -16,6 +17,7 @@ pub fn get_lit_str(attr_name: Symbol, value: &Expr) -> syn::Result<&syn::LitStr>
1617
}
1718
}
1819

20+
/// Get a [literal boolean](struct@syn::LitBool) from the provided [expression](Expr) as a [`bool`].
1921
pub fn get_lit_bool(attr_name: Symbol, value: &Expr) -> syn::Result<bool> {
2022
if let Expr::Lit(ExprLit {
2123
lit: Lit::Bool(lit),
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
extern crate proc_macro;
2+
3+
use proc_macro::TokenStream;
4+
use std::{env, path::PathBuf};
5+
use toml_edit::{Document, Item};
6+
7+
/// The path to the `Cargo.toml` file for the Bevy project.
8+
pub struct BevyManifest {
9+
manifest: Document,
10+
}
11+
12+
impl 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::<Document>().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+
}
36+
const BEVY: &str = "bevy";
37+
const BEVY_INTERNAL: &str = "bevy_internal";
38+
39+
impl BevyManifest {
40+
/// Attempt to retrieve the [path](syn::Path) of a particular package in
41+
/// the [manifest](BevyManifest) by [name](str).
42+
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+
/// Returns the path for the crate with the given name.
77+
///
78+
/// This is a convenience method for constructing a [manifest] and
79+
/// calling the [`get_path`] method.
80+
///
81+
/// This method should only be used where you just need the path and can't
82+
/// cache the [manifest]. If caching is possible, it's recommended to create
83+
/// the [manifest] yourself and use the [`get_path`] method.
84+
///
85+
/// [`get_path`]: Self::get_path
86+
/// [manifest]: Self
87+
pub fn get_path_direct(name: &str) -> syn::Path {
88+
Self::default().get_path(name)
89+
}
90+
91+
/// Returns the path for the crate with the given name.
92+
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+
/// Attempt to parse the provided [path](str) as a [syntax tree node](syn::parse::Parse)
98+
pub fn try_parse_str<T: syn::parse::Parse>(path: &str) -> Option<T> {
99+
syn::parse(path.parse::<TokenStream>().ok()?).ok()
100+
}
101+
102+
/// Attempt to parse provided [path](str) as a [syntax tree node](syn::parse::Parse).
103+
///
104+
/// # Panics
105+
///
106+
/// Will panic if the path is not able to be parsed. For a non-panicing option, see [`try_parse_str`]
107+
///
108+
/// [`try_parse_str`]: Self::try_parse_str
109+
pub fn parse_str<T: syn::parse::Parse>(path: &str) -> T {
110+
Self::try_parse_str(path).unwrap()
111+
}
112+
113+
/// Attempt to get a subcrate [path](syn::Path) under Bevy by [name](str)
114+
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+
}

crates/bevy_reflect/bevy_reflect_derive/src/fq_std.rs renamed to crates/bevy_macro_utils/src/fq_std.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
//! This module contains unit structs that should be used inside `quote!` and `spanned_quote!` using the variable interpolation syntax in place of their equivalent structs and traits present in `std`.
2-
//
3-
//! To create hygienic proc macros, all the names must be its fully qualified form. These unit structs help us to not specify the fully qualified name every single time.
1+
//! This module contains unit structs that should be used inside `quote!` and `spanned_quote!`
2+
//! using the variable interpolation syntax in place of their equivalent structs and traits
3+
//! present in `std`.
4+
//!
5+
//! To create hygienic proc macros, all the names must be its fully qualified form. These
6+
//! unit structs help us to not specify the fully qualified name every single time.
47
//!
58
//! # Example
69
//! Instead of writing this:
@@ -33,14 +36,22 @@
3336
use proc_macro2::TokenStream;
3437
use quote::{quote, ToTokens};
3538

36-
pub(crate) struct FQAny;
37-
pub(crate) struct FQBox;
38-
pub(crate) struct FQClone;
39-
pub(crate) struct FQDefault;
40-
pub(crate) struct FQOption;
41-
pub(crate) struct FQResult;
42-
pub(crate) struct FQSend;
43-
pub(crate) struct FQSync;
39+
/// Fully Qualified (FQ) short name for [`::core::any::Any`]
40+
pub struct FQAny;
41+
/// Fully Qualified (FQ) short name for [`::std::boxed::Box`]
42+
pub struct FQBox;
43+
/// Fully Qualified (FQ) short name for [`::core::clone::Clone`]
44+
pub struct FQClone;
45+
/// Fully Qualified (FQ) short name for [`::core::default::Default`]
46+
pub struct FQDefault;
47+
/// Fully Qualified (FQ) short name for [`::core::option::Option`]
48+
pub struct FQOption;
49+
/// Fully Qualified (FQ) short name for [`::core::result::Result`]
50+
pub struct FQResult;
51+
/// Fully Qualified (FQ) short name for [`::core::marker::Send`]
52+
pub struct FQSend;
53+
/// Fully Qualified (FQ) short name for [`::core::marker::Sync`]
54+
pub struct FQSync;
4455

4556
impl ToTokens for FQAny {
4657
fn to_tokens(&self, tokens: &mut TokenStream) {

0 commit comments

Comments
 (0)