use color_eyre::eyre::Result;
use crossbeam_channel::unbounded;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use regex::bytes::RegexSet;
use std::num::NonZeroUsize;
use std::path::Component;
use std::path::Path;
use std::path::Prefix;
use std::sync::OnceLock;
use std::thread;
pub(crate) fn strip_path_prefix<'a>(
path: &'a Path,
prefix: &Path,
) -> impl Iterator<Item = Component<'a>> {
let mut components = path.components();
for c in prefix.components() {
let deverbatimize = |c| match c {
Component::Prefix(prefix) => Err(match prefix.kind() {
Prefix::VerbatimUNC(a, b) => Prefix::UNC(a, b),
Prefix::VerbatimDisk(d) => Prefix::Disk(d),
other => other,
}),
c => Ok(c),
};
let c2 = components.next();
if Some(deverbatimize(c)) == c2.map(deverbatimize) {
continue;
}
return c2.into_iter().chain(components);
}
None.into_iter().chain(components)
}
impl CrateType {
pub fn from_file_contents(file_contents: &[u8]) -> CrateType {
static RE: OnceLock<RegexSet> = OnceLock::new();
let re = RE.get_or_init(|| {
RegexSet::new([
r"#\[proc_macro(_derive|_attribute)?[\](]",
r"#\[test\]",
r"fn main()|#\[start\]",
])
.unwrap()
});
match re.matches(file_contents).iter().next() {
Some(0) => CrateType::ProcMacro,
Some(1) => CrateType::Test,
Some(2) => CrateType::Bin,
_ => CrateType::Lib,
}
}
}
pub enum CrateType {
ProcMacro,
Test,
Bin,
Lib,
}
pub fn run_and_collect<const N: usize, SUBMISSION: Send, RESULT: Send>(
num_threads: NonZeroUsize,
submitter: impl FnOnce([Sender<SUBMISSION>; N]) + Send,
runner: impl Sync + Fn(&[Receiver<SUBMISSION>; N], Sender<RESULT>) -> Result<()>,
collector: impl FnOnce(Receiver<RESULT>) + Send,
) -> Result<()> {
let (submit, receive): (Vec<_>, Vec<_>) = std::iter::repeat_with(unbounded).take(N).unzip();
let receive = receive[..].try_into().unwrap();
let mut submit = submit.into_iter();
let submit = std::array::from_fn(|_| submit.next().unwrap());
thread::scope(|s| {
s.spawn(|| submitter(submit));
let (finished_files_sender, finished_files_recv) = unbounded();
s.spawn(|| collector(finished_files_recv));
let mut threads = vec![];
for _ in 0..num_threads.get() {
let finished_files_sender = finished_files_sender.clone();
threads.push(s.spawn(|| runner(receive, finished_files_sender)));
}
for thread in threads {
thread.join().unwrap()?;
}
Ok(())
})
}