use std::fmt::Write; use quote::ToTokens; macro_rules! syn_path { ($first_segment: ident $(::$segment: ident)*) => { ::syn::Path { leading_colon: None, segments: ::syn::punctuated::Punctuated::from_iter([ syn_path_segment!($first_segment), $(syn_path_segment!($segment),)* ]) } }; } macro_rules! syn_path_segment { ($segment: ident) => { ::syn::PathSegment { ident: ::proc_macro2::Ident::new( stringify!($segment), ::proc_macro2::Span::call_site(), ), arguments: ::syn::PathArguments::None, } }; } pub fn find_engine_crate_path() -> Option { let cargo_crate_name = std::env::var("CARGO_CRATE_NAME").ok()?; let cargo_pkg_name = std::env::var("CARGO_PKG_NAME").ok()?; if cargo_pkg_name == "engine" && cargo_crate_name != "engine" { // Macro is used by a crate example/test/benchmark return Some(syn_path!(engine)); } if cargo_crate_name == "engine" { return Some(syn_path!(crate)); } Some(syn_path!(engine)) } pub fn syn_path_to_string(path: &syn::Path) -> String { let mut output = String::with_capacity(2 + path.segments.len() * 8); if let Some(leading_colon) = path.leading_colon { write!(output, "{}", leading_colon.to_token_stream()).unwrap(); } for (segment, punct) in path.segments.pairs().map(syn::punctuated::Pair::into_tuple) { let segment_ident = &segment.ident; write!(output, "{segment_ident}",).unwrap(); if let Some(punct) = punct { write!(output, "{}", punct.to_token_stream()).unwrap(); } } output }