use failure::Error;
#[allow(deprecated)]
use std::hash::{Hash, Hasher, SipHasher};
use url::Url;
pub fn to_hex(num: u64) -> String {
const CHARS: &[u8] = b"0123456789abcdef";
let bytes = &[
num as u8,
(num >> 8) as u8,
(num >> 16) as u8,
(num >> 24) as u8,
(num >> 32) as u8,
(num >> 40) as u8,
(num >> 48) as u8,
(num >> 56) as u8,
];
let mut output = vec![0u8; 16];
let mut ind = 0;
for &byte in bytes {
output[ind] = CHARS[(byte >> 4) as usize];
output[ind + 1] = CHARS[(byte & 0xf) as usize];
ind += 2;
}
String::from_utf8(output).expect("valid utf-8 hex string")
}
pub fn hash_u64<H: Hash>(hashable: H) -> u64 {
#[allow(deprecated)]
let mut hasher = SipHasher::new_with_keys(0, 0);
hashable.hash(&mut hasher);
hasher.finish()
}
pub fn short_hash<H: Hash>(hashable: &H) -> String {
to_hex(hash_u64(hashable))
}
pub fn ident(url: &Url) -> String {
let ident = url
.path_segments()
.and_then(|mut s| s.next_back())
.unwrap_or("");
let ident = if ident == "" { "_empty" } else { ident };
format!("{}-{}", ident, short_hash(&url))
}
pub fn canonicalize_url(url: &Url) -> Result<Url, Error> {
let mut url = url.clone();
if url.cannot_be_a_base() {
failure::bail!(
"invalid url `{}`: cannot-be-a-base-URLs are not supported",
url
)
}
if url.path().ends_with('/') {
url.path_segments_mut().unwrap().pop_if_empty();
}
if url.host_str() == Some("github.com") {
url.set_scheme("https").unwrap();
let path = url.path().to_lowercase();
url.set_path(&path);
}
let needs_chopping = url.path().ends_with(".git");
if needs_chopping {
let last = {
let last = url.path_segments().unwrap().next_back().unwrap();
last[..last.len() - 4].to_owned()
};
url.path_segments_mut().unwrap().pop().push(&last);
}
url.set_fragment(None);
url.set_query(None);
Ok(url)
}