use std::ffi::OsString;
use std::io;
use std::path::{Component, Path, PathBuf};
use crate::index::normalize_path;
use crate::prelude::*;
use crate::store::Entries;
#[derive(Clone, Debug)]
pub struct CaselessFs<S> {
inner: S,
}
impl<S: Store> CaselessFs<S> {
pub fn new(inner: S) -> Self {
Self { inner }
}
pub fn into_inner(self) -> S {
self.inner
}
pub fn get_ref(&self) -> &S {
&self.inner
}
pub fn get_mut(&mut self) -> &mut S {
&mut self.inner
}
pub fn find<P: AsRef<Path>>(&self, path: P) -> Vec<PathBuf> {
let path = normalize_path(path.as_ref());
let mut paths = vec![PathBuf::new()];
for component in path.components() {
paths = find_next_ascii_lowercase(&self.inner, &component, paths);
if paths.len() == 0 {
return paths;
}
}
paths
}
}
impl<S: Store> Store for CaselessFs<S> {
type File = S::File;
fn open_path(&self, path: &Path) -> io::Result<Self::File> {
if let Ok(file) = self.inner.open_path(path) {
return Ok(file);
}
for path in self.find(path) {
return self.inner.open_path(&path);
}
Err(io::ErrorKind::NotFound.into())
}
fn entries_path(&self, path: &Path) -> io::Result<Entries> {
self.inner.entries_path(path)
}
}
fn find_next_ascii_lowercase<S: Store>(
fs: &S,
component: &Component,
paths: Vec<PathBuf>,
) -> Vec<PathBuf> {
let mut next = Vec::new();
let target: OsString = match component {
Component::Normal(os_s) => (*os_s).to_owned(),
Component::RootDir => {
next.push(Path::new("/").to_owned());
return next;
}
_ => {
panic!(format!("unexpected path component {:?}", component));
}
};
if let Some(t_s) = target.to_str() {
for path in paths {
if let Ok(entries) = fs.entries(&path) {
for e in entries {
if let Ok(entry) = e {
if let Some(e_s) = entry.name.to_str() {
if t_s.to_ascii_lowercase() == e_s.to_ascii_lowercase() {
let mut path = path.to_owned();
path.push(&entry.name);
next.push(path);
}
}
}
}
}
}
} else {
for path in paths {
if let Ok(entries) = fs.entries(&path) {
for e in entries {
if let Ok(entry) = e {
if &entry.name == &target {
let mut path = path.to_owned();
path.push(&entry.name);
next.push(path);
}
}
}
}
}
}
next
}