use std::path::PathBuf;
use proc_macro2::TokenStream;
use syn::{spanned::Spanned, Ident, Item, ItemStruct, Path, Token};
use crate::error::*;
pub fn get_struct_from_path(root_path: PathBuf, path: Path) -> Result<ItemStruct, TokenStream> {
let path_span = path.span();
let mut segments = 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 {
return Err(err!(
first,
"inter_struct only supports paths in the current 'crate::' space for now."
));
}
let mut file_path = root_path;
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() {
continue;
}
file_path.set_extension("rs");
if file_path.exists() {
continue;
}
};
if file_path.is_dir() && file_path.join("mod.rs").exists() {
file_path.push("mod.rs");
} else if file_path.is_dir() && file_path.join("lib.rs").exists() {
file_path.push("lib.rs");
} else if file_path.is_dir() && file_path.join("main.rs").exists() {
file_path.push("main.rs");
} else if file_path.is_dir() {
return Err(err!(
path_span,
"Couldn't find suitable module in directory {:?}",
file_path
));
}
let file_content = ok_or_err_return!(
std::fs::read_to_string(&file_path),
path_span,
"Failed to open file {:?}: {:?}",
file_path
);
let file_ast = ok_or_err_return!(
syn::parse_file(&file_content),
path_span,
"Failed to parse file {:?}: {:?}",
file_path
);
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
))
}