#[allow(unused_imports)]
use crate::{SharedString, source::DirEntry};
use std::{
fmt,
ops::{Deref, DerefMut},
path::{Path, PathBuf},
};
pub fn is_invalid_id(id: &str) -> bool {
id.starts_with('.')
|| id.ends_with('.')
|| id.contains("..")
|| id.contains('/')
|| id.contains('\\')
}
pub fn path_of_entry(root: &Path, entry: DirEntry) -> PathBuf {
let (id, ext) = match entry {
DirEntry::File(id, ext) => (id, Some(ext)),
DirEntry::Directory(id) => (id, None),
};
let capacity = root.as_os_str().len() + id.len() + ext.map_or(0, |ext| ext.len()) + 2;
let mut path = PathBuf::with_capacity(capacity);
path.push(root);
path.extend(id.split('.'));
if let Some(ext) = ext {
path.set_extension(ext);
}
path
}
pub(crate) fn split_file_name(path: &Path) -> Option<(&str, &str)> {
let name = path.file_name()?.to_str()?;
match name.split_once('.') {
Some(("", _)) => None,
Some(res) => Some(res),
None => Some((name, "")),
}
}
#[cfg(any(feature = "tar", feature = "zip", feature = "hot-reloading"))]
#[derive(Default)]
pub struct IdBuilder {
buf: String,
}
#[cfg(any(feature = "tar", feature = "zip", feature = "hot-reloading"))]
impl IdBuilder {
pub fn push(&mut self, s: &str) -> Option<()> {
if s.contains('.') {
return None;
}
if !self.buf.is_empty() {
self.buf.push('.');
}
self.buf.push_str(s);
Some(())
}
pub fn pop(&mut self) -> Option<()> {
if self.buf.is_empty() {
return None;
}
let pos = self.buf.rfind('.').unwrap_or(0);
self.buf.truncate(pos);
Some(())
}
#[inline]
pub fn join(&self) -> SharedString {
self.buf.as_str().into()
}
#[inline]
pub fn reset(&mut self) {
self.buf.clear()
}
}
#[cfg(feature = "parking_lot")]
use parking_lot as sync;
#[cfg(not(feature = "parking_lot"))]
use std::sync;
pub(crate) use sync::{RwLockReadGuard, RwLockWriteGuard};
#[cfg(feature = "parking_lot")]
#[inline]
fn wrap<T>(param: T) -> T {
param
}
#[cfg(not(feature = "parking_lot"))]
#[inline]
fn wrap<T>(param: sync::LockResult<T>) -> T {
param.unwrap_or_else(sync::PoisonError::into_inner)
}
pub(crate) struct RwLock<T: ?Sized>(sync::RwLock<T>);
#[allow(unused)]
impl<T> RwLock<T> {
#[inline]
pub fn new(inner: T) -> Self {
Self(sync::RwLock::new(inner))
}
#[inline]
pub fn into_inner(self) -> T {
wrap(self.0.into_inner())
}
}
impl<T: ?Sized> RwLock<T> {
#[inline]
pub fn read(&self) -> RwLockReadGuard<'_, T> {
wrap(self.0.read())
}
#[inline]
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
wrap(self.0.write())
}
}
#[allow(unused)]
#[derive(Default)]
pub(crate) struct Mutex<T: ?Sized>(sync::Mutex<T>);
#[allow(unused)]
impl<T> Mutex<T> {
#[inline]
pub fn new(inner: T) -> Self {
Self(sync::Mutex::new(inner))
}
}
#[allow(unused)]
impl<T: ?Sized> Mutex<T> {
#[inline]
pub fn lock(&self) -> sync::MutexGuard<'_, T> {
wrap(self.0.lock())
}
}
#[allow(unused)]
#[derive(Default)]
pub(crate) struct Condvar(sync::Condvar);
#[allow(unused)]
impl Condvar {
#[inline]
pub fn new() -> Self {
Self(sync::Condvar::new())
}
#[inline]
pub fn notify_all(&self) {
self.0.notify_all();
}
#[inline]
pub fn wait_while<'a, T, F>(
&self,
mut guard: sync::MutexGuard<'a, T>,
mut condition: F,
) -> sync::MutexGuard<'a, T>
where
F: FnMut(&mut T) -> bool,
{
#[cfg(feature = "parking_lot")]
{
while condition(&mut guard) {
self.0.wait(&mut guard);
}
guard
}
#[cfg(not(feature = "parking_lot"))]
{
while condition(&mut guard) {
guard = wrap(self.0.wait(guard));
}
guard
}
}
}
#[cfg(feature = "faster-hash")]
pub(crate) use foldhash::fast::RandomState;
#[cfg(not(feature = "faster-hash"))]
pub(crate) use std::collections::hash_map::RandomState;
pub(crate) struct HashMap<K, V>(hashbrown::HashMap<K, V, RandomState>);
impl<K, V> HashMap<K, V> {
#[inline]
#[allow(unused)]
pub fn new() -> Self {
Self(hashbrown::HashMap::with_hasher(RandomState::default()))
}
#[cfg(feature = "zip")]
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self(hashbrown::HashMap::with_capacity_and_hasher(
capacity,
RandomState::default(),
))
}
}
impl<K, V> Deref for HashMap<K, V> {
type Target = hashbrown::HashMap<K, V, RandomState>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<K, V> DerefMut for HashMap<K, V> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<K, V> fmt::Debug for HashMap<K, V>
where
hashbrown::HashMap<K, V, RandomState>: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(feature = "hot-reloading")]
pub(crate) struct HashSet<T>(hashbrown::HashSet<T, RandomState>);
#[cfg(feature = "hot-reloading")]
impl<T> HashSet<T> {
#[inline]
pub fn new() -> Self {
Self(hashbrown::HashSet::with_hasher(RandomState::default()))
}
}
#[cfg(feature = "hot-reloading")]
impl<T> Deref for HashSet<T> {
type Target = hashbrown::HashSet<T, RandomState>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "hot-reloading")]
impl<T> DerefMut for HashSet<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(feature = "hot-reloading")]
impl<T> Default for HashSet<T> {
fn default() -> Self {
Self(hashbrown::HashSet::default())
}
}
#[cfg(feature = "hot-reloading")]
impl<T> IntoIterator for HashSet<T> {
type Item = T;
type IntoIter = hashbrown::hash_set::IntoIter<T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[cfg(feature = "hot-reloading")]
impl<T> fmt::Debug for HashSet<T>
where
hashbrown::HashSet<T, RandomState>: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}