use bytes::Bytes;
use crate::PathHash;
#[derive(Debug)]
pub(crate) struct PathMap<'a> {
#[cfg(feature = "hash")]
map: ahash::HashMap<&'a str, String>,
#[cfg(not(feature = "hash"))]
map: std::marker::PhantomData<&'a ()>,
}
impl<'a> PathMap<'a> {
pub(crate) fn new() -> Self {
#[cfg(feature = "hash")]
{ Self { map: ahash::HashMap::default() } }
#[cfg(not(feature = "hash"))]
{ Self { map: std::marker::PhantomData } }
}
pub(crate) fn get(&self, path: &str) -> Option<&str> {
#[cfg(feature = "hash")]
{ self.map.get(path).map(|s| &**s) }
#[cfg(not(feature = "hash"))]
{
let _path = path;
None
}
}
}
#[cfg(not(feature = "hash"))]
pub(crate) fn path_of<'a>(
_: PathHash<'_>,
path: &'a str,
_: &Bytes,
_: &mut PathMap<'a>,
) -> String {
path.to_owned()
}
#[cfg(feature = "hash")]
pub(crate) fn path_of<'a>(
hash: PathHash<'_>,
path: &'a str,
content: &Bytes,
map: &mut PathMap<'a>,
) -> String {
use sha2::{Digest, Sha256};
use base64::Engine;
const HASH_BYTES_IN_FILENAME: usize = 9;
let (first_part, hash_prefix, second_part) = match hash {
PathHash::None => return path.to_owned(),
PathHash::Auto => {
let last_seg_start = path.rfind('/').map(|p| p + 1).unwrap_or(0);
let (pos, hash_prefix) = match path[last_seg_start..].find('.') {
Some(pos) => (last_seg_start + pos, '.'),
None => (path.len(), '-'),
};
(&path[..pos], Some(hash_prefix), &path[pos..])
},
PathHash::InBetween { prefix, suffix } => (prefix, None, suffix),
};
let hash = Sha256::digest(&content);
let mut out = first_part.to_owned();
out.extend(hash_prefix);
base64::engine::general_purpose::URL_SAFE_NO_PAD
.encode_string(&hash.as_slice()[..HASH_BYTES_IN_FILENAME], &mut out);
out.push_str(second_part);
map.map.insert(path, out.clone());
out
}