/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! We unfortunately have to mock `Path` because of `exists`, `try_exists`, and `metadata`. pub use std::path::*; use super::mock::MockKey; use std::ffi::OsStr; macro_rules! delegate { ( fn $name:ident (&self $(, $arg:ident : $argty:ty )* ) -> $ret:ty ) => { pub fn $name (&self, $($arg : $ty)*) -> $ret { self.0.$name($($arg),*) } } } #[repr(transparent)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Path(std::path::Path); impl AsRef for Path { fn as_ref(&self) -> &std::path::Path { &self.0 } } impl AsRef for Path { fn as_ref(&self) -> &OsStr { self.0.as_ref() } } impl AsRef for &str { fn as_ref(&self) -> &Path { Path::from_path(self.as_ref()) } } impl AsRef for String { fn as_ref(&self) -> &Path { Path::from_path(self.as_ref()) } } impl AsRef for &OsStr { fn as_ref(&self) -> &Path { Path::from_path(self.as_ref()) } } impl Path { fn from_path(path: &std::path::Path) -> &Self { // # Safety // Transparent wrapper is safe to transmute. unsafe { std::mem::transmute(path) } } pub fn exists(&self) -> bool { super::fs::MockFS .try_get(|files| { files .path(self, false, |item| match &item.content { super::fs::MockFSContent::File(r) => r.is_ok(), _ => true, }) .unwrap_or(false) }) .unwrap_or(false) } pub fn read_dir(&self) -> super::io::Result { super::fs::ReadDir::new(&self.0) } delegate!(fn display(&self) -> Display); delegate!(fn file_stem(&self) -> Option<&OsStr>); delegate!(fn file_name(&self) -> Option<&OsStr>); delegate!(fn extension(&self) -> Option<&OsStr>); pub fn join>(&self, path: P) -> PathBuf { PathBuf(self.0.join(&path.as_ref().0)) } pub fn parent(&self) -> Option<&Path> { self.0.parent().map(Path::from_path) } } #[repr(transparent)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PathBuf(pub(super) std::path::PathBuf); impl PathBuf { pub fn set_extension>(&mut self, extension: S) -> bool { self.0.set_extension(extension) } pub fn push>(&mut self, path: P) { self.0.push(path.as_ref()) } pub fn pop(&mut self) -> bool { self.0.pop() } } impl std::ops::Deref for PathBuf { type Target = Path; fn deref(&self) -> &Self::Target { Path::from_path(self.0.as_ref()) } } impl AsRef for PathBuf { fn as_ref(&self) -> &Path { Path::from_path(self.0.as_ref()) } } impl AsRef for PathBuf { fn as_ref(&self) -> &std::path::Path { self.0.as_ref() } } impl AsRef for PathBuf { fn as_ref(&self) -> &OsStr { self.0.as_ref() } } impl From for PathBuf { fn from(os_str: std::ffi::OsString) -> Self { PathBuf(os_str.into()) } } impl From for PathBuf { fn from(pathbuf: std::path::PathBuf) -> Self { PathBuf(pathbuf) } } impl From for std::ffi::OsString { fn from(pathbuf: PathBuf) -> Self { pathbuf.0.into() } } impl From<&str> for PathBuf { fn from(s: &str) -> Self { PathBuf(s.into()) } }