parent
8434cf0425
commit
a68f418ffd
@ -0,0 +1,18 @@
|
|||||||
|
//! Argument stuff
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// Name of executable
|
||||||
|
pub fn program_name() -> &'static str
|
||||||
|
{
|
||||||
|
lazy_static! {
|
||||||
|
static ref NAME: String = std::env::args().next().unwrap();
|
||||||
|
}
|
||||||
|
&NAME[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print usage
|
||||||
|
pub fn usage()
|
||||||
|
{
|
||||||
|
println!(r#"Usage: {} <files...>"#, program_name());
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
use super::*;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
pub trait StringJoinExt: Sized
|
||||||
|
{
|
||||||
|
fn join<P: AsRef<str>>(self, sep: P) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I,T> StringJoinExt for I
|
||||||
|
where I: IntoIterator<Item=T>,
|
||||||
|
T: AsRef<str>
|
||||||
|
{
|
||||||
|
fn join<P: AsRef<str>>(self, sep: P) -> String
|
||||||
|
{
|
||||||
|
let mut string = String::new();
|
||||||
|
for (first, s) in iter::successors(Some(true), |_| Some(false)).zip(self.into_iter())
|
||||||
|
{
|
||||||
|
if !first {
|
||||||
|
string.push_str(sep.as_ref());
|
||||||
|
}
|
||||||
|
string.push_str(s.as_ref());
|
||||||
|
}
|
||||||
|
string
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
//! Map iter
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
iter,
|
||||||
|
collections::HashSet,
|
||||||
|
hash::Hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO: Feature flag for SHA256 hashing
|
||||||
|
type HashOutput = u64;
|
||||||
|
|
||||||
|
fn compute<H: Hash>(what: &H) -> HashOutput
|
||||||
|
{
|
||||||
|
use std::hash::Hasher;
|
||||||
|
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||||
|
what.hash(&mut hasher);
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DedupIter<I: Iterator>(I, HashSet<HashOutput>)
|
||||||
|
where <I as Iterator>::Item: Hash;
|
||||||
|
|
||||||
|
impl<I: Iterator> Iterator for DedupIter<I>
|
||||||
|
where I::Item: Hash
|
||||||
|
{
|
||||||
|
type Item = I::Item;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>
|
||||||
|
{
|
||||||
|
if let Some(next) = self.0.next() {
|
||||||
|
let hash = compute(&next);
|
||||||
|
if self.1.insert(hash) {
|
||||||
|
Some(next)
|
||||||
|
} else {
|
||||||
|
return self.next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>)
|
||||||
|
{
|
||||||
|
let (low, high) = self.0.size_hint();
|
||||||
|
|
||||||
|
(if low < 1 {0} else {1}, high)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DedupIterExt: Iterator + Sized
|
||||||
|
where Self::Item: Hash
|
||||||
|
{
|
||||||
|
fn dedup(self) -> DedupIter<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator> DedupIterExt for I
|
||||||
|
where I::Item: Hash
|
||||||
|
{
|
||||||
|
fn dedup(self) -> DedupIter<Self>
|
||||||
|
{
|
||||||
|
let set = match self.size_hint() {
|
||||||
|
(0, Some(0)) | (0, None) => HashSet::new(),
|
||||||
|
(x, None) | (_, Some(x)) => HashSet::with_capacity(x),
|
||||||
|
};
|
||||||
|
DedupIter(self, set)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
//! Splash screen~
|
||||||
|
use super::*;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
macro_rules! feature {
|
||||||
|
(in $name:tt, $desc:literal) => {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg($name)] {
|
||||||
|
println!(" +{}\t{}", stringify!($name), $desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($name:literal, $desc:literal $($tt:tt)*) => {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature=$name)] {
|
||||||
|
println!(" +{}\t{}", $name, format!($desc $($tt)*));
|
||||||
|
} else {
|
||||||
|
println!(" -{}", $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn splash() -> ! {
|
||||||
|
arg::usage();
|
||||||
|
|
||||||
|
// splash screen
|
||||||
|
println!(r#"
|
||||||
|
> sever ({}) v{}
|
||||||
|
> Coerce hardlinks to new files
|
||||||
|
|
||||||
|
For verbose output, set `RUST_LOG` env var to one of the following:
|
||||||
|
trace - Most verbose
|
||||||
|
debug - Verbose
|
||||||
|
info - Default
|
||||||
|
warn - Only show warnings
|
||||||
|
error - Only show errors
|
||||||
|
|
||||||
|
Made by {} with <3 (Licensed GPL 3.0 or later)"#, arg::program_name(), env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_AUTHORS"));
|
||||||
|
println!("\nEnabled extensions: ");
|
||||||
|
feature!(in nightly, "\tCompiled with Rust nightly extensions");
|
||||||
|
println!();
|
||||||
|
feature!("parallel", "\tWill run up to {} operations in parallel", parallel::MAX_WORKERS.map(|x| Cow::Owned(x.to_string())).unwrap_or(Cow::Borrowed("unlimited")));
|
||||||
|
feature!("limit-concurrency", "Concurrency is capped");
|
||||||
|
feature!("threads", "\tUsing thread-pool");
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
Loading…
Reference in new issue