use crate::trees::null::make_null_group;
use proc_macro2::{Delimiter, Group, Span, TokenStream as TokenStream2, TokenTree as TokenTree2};
use quote::{format_ident, quote};
use std::path::Path;
pub(crate) struct FileDepTracker<'tk> {
prefix_token: &'tk mut TokenTree2,
name_token: &'tk mut TokenTree2,
data_token: &'tk mut TokenTree2,
c_append_files: usize,
a_globalposnum: usize,
}
impl<'tk> FileDepTracker<'tk> {
#[inline]
pub const fn new(
a_globalposnum: usize,
prefix_token: &'tk mut TokenTree2,
name_token: &'tk mut TokenTree2,
data_token: &'tk mut TokenTree2,
) -> Self {
Self {
prefix_token,
name_token,
data_token,
c_append_files: 0,
a_globalposnum,
}
}
#[inline]
pub fn prefix_span(&self) -> Span {
self.prefix_token.span()
}
#[inline]
pub fn name_span(&self) -> Span {
self.name_token.span()
}
#[inline]
pub fn data_span(&self) -> Span {
self.data_token.span()
}
#[inline]
pub const fn is_rewritten(&self) -> bool {
self.c_append_files > 0
}
pub fn into_token_tree2(self) -> Option<(usize, TokenTree2)> {
if self.c_append_files == 0 {
return None;
}
let c_append_files = self.c_append_files;
let data_span = self.data_span();
let data_token = std::mem::replace(self.data_token, make_null_group(data_span));
drop(self);
Some((c_append_files, data_token))
}
pub fn append_track_file(&mut self, path: &Path) {
let name_const = format_ident!(
"__TRACKER_FILE_NUM_{}",
self.a_globalposnum + self.c_append_files
);
let abs_path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());
let path_str = abs_path.to_string_lossy();
let ts2 = TokenStream2::from_iter(quote! {
#[doc(hidden)]
const #name_const: &'static [u8] = include_bytes!(#path_str);
});
self.append_track_files_ts(ts2)
}
pub fn append_track_files_ts(&mut self, ts2: TokenStream2) {
let data_span = self.data_span();
let is_initappendfiles = self.c_append_files == 0;
self.c_append_files += 1;
let mut ngroup = Group::new(Delimiter::None, ts2);
ngroup.set_span(data_span);
if is_initappendfiles {
*self.data_token = ngroup.into();
} else {
match &mut self.data_token {
TokenTree2::Group(group) => {
let mut new_group: Vec<TokenTree2> = group.stream().into_iter().collect();
new_group.push(ngroup.into());
let mut ngroup =
Group::new(Delimiter::None, TokenStream2::from_iter(new_group));
ngroup.set_span(data_span);
*self.data_token = ngroup.into();
}
_ => panic!(
"Undefined behavior reported in `PointTrack`, someone redefined `TokenTree2`, expected `TokenTree2::Group`"
),
}
}
}
}
impl<'tk> Drop for FileDepTracker<'tk> {
fn drop(&mut self) {
if !self.is_rewritten() {
let data_span = self.data_span();
*self.data_token = make_null_group(data_span);
}
*self.prefix_token = make_null_group(self.prefix_token.span());
*self.name_token = make_null_group(self.prefix_token.span());
}
}