use crate::Error;
use crate::extra::iter::ComponentIter;
use crate::extra::{Entry, EntryValue};
use std::cell::OnceCell;
use std::path::Path;
const HASH_FIXED_KEY: usize = 0x6d61706c65;
#[inline(always)]
fn hash_builder() -> ahash::RandomState {
ahash::RandomState::with_seed(HASH_FIXED_KEY)
}
struct SequencedCache {
container: Vec<EntryCache>,
indexes: ahash::HashMap<u64, Vec<usize>>,
}
pub struct EntryCache {
entry: Entry,
cache: OnceCell<SequencedCache>,
}
impl AsRef<Entry> for EntryCache {
fn as_ref(&self) -> &Entry {
&self.entry
}
}
impl TryFrom<Entry> for EntryCache {
type Error = Error;
fn try_from(entry: Entry) -> Result<Self, Self::Error> {
let cache = Self {
entry,
cache: OnceCell::new(),
};
cache.cache_map()?;
Ok(cache)
}
}
impl EntryCache {
#[inline]
fn cache_map(&self) -> Result<&SequencedCache, Error> {
if let Some(cache) = self.cache.get() {
return Ok(cache);
}
let builder = hash_builder();
let mut container = vec![];
let mut indexes: ahash::HashMap<u64, Vec<usize>> = ahash::HashMap::default();
self.entry.try_iter()?.for_each(|e| {
let index = container.len();
let hash = builder.hash_one(e.name().as_bytes());
container.push(EntryCache {
entry: e,
cache: OnceCell::new(),
});
match indexes.entry(hash) {
std::collections::hash_map::Entry::Occupied(mut e) => e.get_mut().push(index),
std::collections::hash_map::Entry::Vacant(e) => {
e.insert(vec![index]);
}
};
});
if self
.cache
.set(SequencedCache { container, indexes })
.is_ok()
{
return Ok(self.cache.get().unwrap());
}
Err(Error::Unexpected(
"init cache failed on `OnceCell::set`".into(),
))
}
#[inline]
pub fn name(&self) -> &str {
self.entry.name()
}
#[inline]
pub fn value(&self) -> &EntryValue {
self.entry.value()
}
#[inline]
pub fn has_children(&self) -> bool {
self.entry.has_children()
}
#[inline]
pub fn try_get(&self, name: &str) -> Result<Option<&EntryCache>, Error> {
let hash = hash_builder().hash_one(name.as_bytes());
let sc = self.cache_map()?;
let Some(indexes) = sc.indexes.get(&hash) else {
return Ok(None);
};
if indexes.len() == 1 {
return Ok(sc.container.get(indexes[0]));
}
for index in indexes.iter().copied() {
let Some(x) = sc.container.get(index) else {
return Ok(None);
};
if x.name().eq(name) {
return Ok(Some(x));
}
}
Ok(None)
}
#[inline]
pub fn get_exact(&self, name: &str) -> &EntryCache {
self.get(name).unwrap_or_else(|| panic!("entry not exists"))
}
#[inline]
pub fn get(&self, name: &str) -> Option<&EntryCache> {
self.try_get(name)
.unwrap_or_else(|e| panic!("get entry failed: {e}"))
}
pub fn try_get_by_path<P: AsRef<Path>>(&self, path: P) -> Result<Option<&EntryCache>, Error> {
let path = path.as_ref();
let mut components = ComponentIter::from(path.components());
let Some(first) = components.next() else {
return Ok(None);
};
let mut cursor = self.try_get(first)?;
for name in components {
if let Some(entry) = cursor {
cursor = entry.try_get(name)?;
} else {
return Ok(None);
}
}
Ok(cursor)
}
#[inline]
pub fn get_by_path<P: AsRef<Path>>(&self, path: P) -> Option<&EntryCache> {
self.try_get_by_path(path)
.unwrap_or_else(|e| panic!("get_by_path: {e}"))
}
#[inline]
pub fn get_by_path_exact<P: AsRef<Path>>(&self, path: P) -> &EntryCache {
self.get_by_path(path)
.unwrap_or_else(|| panic!("path not exists"))
}
#[inline]
pub fn try_to<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>>>(
&'a self,
) -> Result<T, Error> {
T::try_from(self).map_err(|e| e.into())
}
#[inline]
pub fn to<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>>>(&'a self) -> T {
self.try_to().unwrap_or_else(|e| panic!("to: {e}"))
}
#[inline]
pub fn try_get_value<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>>>(
&'a self,
name: &str,
) -> Result<Option<T>, Error> {
if let Some(value) = self.try_get(name)? {
Ok(Some(value.try_to::<T>()?))
} else {
Ok(None)
}
}
#[inline]
pub fn get_value<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>>>(
&'a self,
name: &str,
) -> Option<T> {
self.try_get_value::<T>(name)
.unwrap_or_else(|e| panic!("get_value failed: {e}"))
}
#[inline]
pub fn try_get_default<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>> + Default>(
&'a self,
name: &str,
) -> Result<T, Error> {
Ok(self
.try_get_value::<T>(name)?
.unwrap_or_else(|| T::default()))
}
#[inline]
pub fn get_default<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>> + Default>(
&'a self,
name: &str,
) -> T {
self.try_get_default::<T>(name)
.unwrap_or_else(|e| panic!("get_default: {e}"))
}
#[inline]
pub fn try_get_or_else<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>>>(
&'a self,
name: &str,
f: impl FnOnce() -> Result<T, T::Error>,
) -> Result<T, Error> {
if let Some(value) = self.try_get_value::<T>(name)? {
Ok(value)
} else {
Ok(f().map_err(|e| e.into())?)
}
}
#[inline]
pub fn get_or_else<'a, T: TryFrom<&'a EntryCache, Error = impl Into<Error>>>(
&'a self,
name: &str,
f: impl FnOnce() -> T,
) -> T {
self.try_get_or_else::<T>(name, || Ok(f()))
.unwrap_or_else(|e| panic!("get_or_else: {e}"))
}
#[inline]
pub fn try_iter<'a>(&'a self) -> Result<Box<dyn Iterator<Item = &'a EntryCache> + 'a>, Error> {
let m = self.cache_map()?;
Ok(Box::new(m.container.iter()))
}
#[inline]
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a EntryCache> + 'a> {
self.try_iter().unwrap_or_else(|e| panic!("iter: {e}"))
}
}