use std::path::PathBuf;
use proc_macro2::TokenStream;
use syn::{spanned::Spanned, ExprPath, Ident, Item, ItemStruct, Token};
pub fn get_struct_from_path(
mut file_path: PathBuf,
path: ExprPath,
) -> Result<ItemStruct, TokenStream> {
let path_span = path.span();
let mut segments = path.path.segments.into_iter().peekable();
let first = segments.next().unwrap();
let crate_token = Token);
let crate_ident = Ident::from(crate_token);
if first.ident != crate_ident {
err!(
first,
"struct_merge only supports paths in the current 'crate::' space for now."
);
}
let target_struct_name = loop {
let segment = segments.next().unwrap();
if segments.peek().is_none() {
break segment.ident;
}
file_path.push(segment.ident.to_string());
if !file_path.exists() {
file_path.set_extension("rs");
if !file_path.exists() {
return Err(err!(segment, "Cannot find file for path: {:?}", file_path));
}
}
};
let file_content = ok_or_err_return!(
std::fs::read_to_string(&file_path),
path_span,
"Failed to open file: {:?}"
);
let file_ast = ok_or_err_return!(
syn::parse_file(&file_content),
path_span,
"Failed to parse file: {:?}"
);
for item in file_ast.items.into_iter() {
if let Item::Struct(item_struct) = item {
if item_struct.ident == target_struct_name {
return Ok(item_struct);
}
}
}
Err(err!(
path_span,
"Didn't find struct {} in file {:?}",
target_struct_name,
&file_path
))
}