use alloc::{format, string::String};
use proc_macro2::{Span, TokenStream as TokenStream2};
use std::{borrow::Cow, io::Error as IOError, path::Path};
use syn::Error as SynError;
use crate::points::file_dep_tracker::FileDepTracker;
#[derive(Debug)]
pub enum LoadFileAndAutoMakeTreeErr<'a> {
ReadToString { err: IOError, path: Cow<'a, Path> },
ParseStr(SynError),
}
impl<'a> LoadFileAndAutoMakeTreeErr<'a> {
#[inline]
pub const fn read_to_string(err: IOError, path: Cow<'a, Path>) -> Self {
Self::ReadToString { err, path }
}
pub fn into_tt_err(self, span: Span) -> TokenStream2 {
match self {
Self::ReadToString { err, path } => sq_err! {
[span]: "Error loading file, err: '", #{err:?}, "', path: ", #{path:?}, "."
},
Self::ParseStr(e) => sq_err! {
[span]: "Failed to convert to tree `tt`: '", #{e:?}, "'."
},
}
}
}
#[allow(dead_code)]
pub fn load_file_and_automake_tree<'path>(
path: &'path Path,
tracker: Option<&'_ mut FileDepTracker>,
prepare_file_str: impl FnOnce(&mut String),
) -> Result<Option<TokenStream2>, LoadFileAndAutoMakeTreeErr<'path>> {
load_file_and_automake_tree_with_fns(path, tracker, prepare_file_str, Ok, Err)
}
pub fn load_file_and_automake_tree_with_fns<'path, R>(
path: &'path Path,
tracker: Option<&mut FileDepTracker>,
prepare_file_str: impl FnOnce(&mut String),
next: impl FnOnce(Option<TokenStream2>) -> R,
err: impl FnOnce(LoadFileAndAutoMakeTreeErr<'path>) -> R,
) -> R {
let mut data = match std::fs::read_to_string(path) {
Ok(a) => a,
Err(e) => {
let path = path
.canonicalize()
.map_or_else(|_| Cow::Borrowed(path), Cow::Owned);
return err(LoadFileAndAutoMakeTreeErr::read_to_string(e, path));
}
};
if let Some(tracker) = tracker {
tracker.append_track_file(path);
}
if data.is_empty() {
return next(None);
}
prepare_file_str(&mut data);
match syn::parse_str::<TokenStream2>(&data) {
Ok(a) if !a.is_empty() => next(Some(a)),
Ok(_) => next(None),
Err(e) => err(LoadFileAndAutoMakeTreeErr::ParseStr(e)),
}
}