#![cfg_attr(feature = "fail-on-warnings", deny(warnings))]
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
#![allow(clippy::multiple_crate_versions)]
#[cfg(feature = "simulator")]
pub mod simulator;
#[cfg(feature = "std")]
pub mod standard;
#[cfg(feature = "tokio")]
pub mod tokio;
#[cfg(all(feature = "sync", feature = "std"))]
pub trait GenericSyncFile:
Send + Sync + ::std::io::Read + ::std::io::Write + ::std::io::Seek
{
}
#[cfg(all(feature = "async", feature = "tokio"))]
pub trait GenericAsyncFile:
Send
+ Sync
+ switchy_async::io::AsyncRead
+ switchy_async::io::AsyncWrite
+ switchy_async::io::AsyncSeek
{
}
#[allow(unused)]
macro_rules! impl_open_options {
($(,)?) => {
#[derive(Clone)]
pub struct OpenOptions {
pub(crate) create: bool,
pub(crate) append: bool,
pub(crate) read: bool,
pub(crate) write: bool,
pub(crate) truncate: bool,
}
impl Default for OpenOptions {
fn default() -> Self {
Self::new()
}
}
impl OpenOptions {
#[must_use]
pub const fn new() -> Self {
Self {
create: false,
append: false,
read: false,
write: false,
truncate: false,
}
}
#[must_use]
pub const fn create(mut self, create: bool) -> Self {
self.create = create;
self
}
#[must_use]
pub const fn append(mut self, append: bool) -> Self {
self.append = append;
self
}
#[must_use]
pub const fn read(mut self, read: bool) -> Self {
self.read = read;
self
}
#[must_use]
pub const fn write(mut self, write: bool) -> Self {
self.write = write;
self
}
#[must_use]
pub const fn truncate(mut self, truncate: bool) -> Self {
self.truncate = truncate;
self
}
}
};
}
#[allow(unused)]
macro_rules! impl_sync_fs {
($module:ident $(,)?) => {
#[cfg(feature = "sync")]
pub mod sync {
pub use $crate::$module::sync::{
File, canonicalize, create_dir, create_dir_all, read, read_dir_sorted,
read_to_string, remove_dir_all, walk_dir_sorted, write,
};
impl_open_options!();
}
pub use $crate::$module::exists;
};
}
#[allow(unused)]
macro_rules! impl_async_fs {
($module:ident $(,)?) => {
#[cfg(feature = "async")]
pub mod unsync {
pub use $crate::$module::unsync::{
DirEntry, File, Metadata, ReadDir, canonicalize, create_dir, create_dir_all,
exists, is_dir, is_file, read, read_dir, read_dir_sorted, read_to_string,
remove_dir_all, walk_dir_sorted, write,
};
impl_open_options!();
#[cfg(feature = "sync")]
impl OpenOptions {
#[must_use]
pub const fn into_sync(self) -> crate::sync::OpenOptions {
crate::sync::OpenOptions {
create: self.create,
append: self.append,
read: self.read,
write: self.write,
truncate: self.truncate,
}
}
}
#[cfg(feature = "sync")]
impl From<OpenOptions> for crate::sync::OpenOptions {
fn from(value: OpenOptions) -> Self {
value.into_sync()
}
}
}
};
}
#[cfg(feature = "simulator")]
impl_sync_fs!(simulator);
#[cfg(feature = "simulator")]
impl_async_fs!(simulator);
#[cfg(all(not(feature = "simulator"), feature = "std"))]
impl_sync_fs!(standard);
#[cfg(all(not(feature = "simulator"), feature = "tokio"))]
impl_async_fs!(tokio);
#[cfg(feature = "simulator")]
pub use simulator::temp_dir;
#[cfg(all(feature = "std", not(feature = "simulator")))]
pub use standard::temp_dir;
#[cfg(any(feature = "simulator", feature = "std"))]
pub use temp_dir::{TempDir, tempdir, tempdir_in};
#[cfg(all(feature = "std", not(feature = "simulator")))]
pub use temp_dir::Builder;
#[cfg(all(feature = "simulator-real-fs", feature = "simulator"))]
pub use simulator::with_real_fs;
#[cfg(all(feature = "simulator-real-fs", not(feature = "simulator")))]
pub fn with_real_fs<T>(f: impl FnOnce() -> T) -> T {
f()
}
#[must_use]
pub const fn is_simulator_enabled() -> bool {
cfg!(feature = "simulator")
}
#[cfg(all(
feature = "simulator-real-fs",
feature = "simulator",
feature = "sync",
feature = "std"
))]
pub fn seed_from_real_fs<P: AsRef<std::path::Path>, Q: AsRef<std::path::Path>>(
real_path: P,
sim_path: Q,
) -> std::io::Result<()> {
simulator::seed_from_real_fs(real_path, sim_path)
}
#[cfg(not(all(
feature = "simulator-real-fs",
feature = "simulator",
feature = "sync",
feature = "std"
)))]
#[allow(unused_variables)]
pub fn seed_from_real_fs<P: AsRef<std::path::Path>, Q: AsRef<std::path::Path>>(
real_path: P,
sim_path: Q,
) -> std::io::Result<()> {
Ok(())
}
pub fn seed_from_real_fs_same_path<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<()> {
seed_from_real_fs(path.as_ref(), path.as_ref())
}
pub fn seed_relative_to<B, P, I>(base: B, relative_paths: I) -> std::io::Result<()>
where
B: AsRef<std::path::Path>,
P: AsRef<std::path::Path>,
I: IntoIterator<Item = P>,
{
let base = base.as_ref();
for rel in relative_paths {
let full = base.join(rel.as_ref());
seed_from_real_fs(&full, &full)?;
}
Ok(())
}
#[cfg(any(feature = "simulator", feature = "std"))]
#[cfg(test)]
mod temp_dir_tests {
use super::*;
#[test]
fn test_temp_dir_creation() {
let temp_dir = tempdir().expect("Failed to create temp directory");
let path = temp_dir.path();
assert!(!path.to_string_lossy().is_empty());
#[cfg(feature = "simulator")]
assert!(path.starts_with("/tmp"));
#[cfg(all(feature = "std", not(feature = "simulator")))]
{
assert!(path.exists());
assert!(path.is_dir());
}
}
#[test]
fn test_temp_dir_with_prefix() {
let temp_dir =
TempDir::with_prefix("test-prefix-").expect("Failed to create temp directory");
let path = temp_dir.path();
assert!(!path.to_string_lossy().is_empty());
#[cfg(feature = "simulator")]
{
let file_name = path.file_name().unwrap().to_string_lossy();
assert!(file_name.starts_with("test-prefix-"));
}
#[cfg(all(feature = "std", not(feature = "simulator")))]
{
assert!(path.exists());
assert!(path.is_dir());
}
}
#[test]
fn test_temp_dir_with_suffix() {
let temp_dir =
TempDir::with_suffix("-test-suffix").expect("Failed to create temp directory");
let path = temp_dir.path();
assert!(!path.to_string_lossy().is_empty());
#[cfg(feature = "simulator")]
{
let file_name = path.file_name().unwrap().to_string_lossy();
assert!(file_name.ends_with("-test-suffix"));
}
#[cfg(all(feature = "std", not(feature = "simulator")))]
{
assert!(path.exists());
assert!(path.is_dir());
}
}
#[test]
fn test_temp_dir_keep() {
let temp_dir = tempdir().expect("Failed to create temp directory");
let path = temp_dir.path().to_path_buf();
assert!(!path.to_string_lossy().is_empty());
let kept_path = temp_dir.keep();
assert_eq!(path, kept_path);
#[cfg(all(feature = "std", not(feature = "simulator")))]
assert!(kept_path.exists());
}
#[test]
fn test_temp_dir_close() {
let temp_dir = tempdir().expect("Failed to create temp directory");
let path = temp_dir.path().to_path_buf();
assert!(!path.to_string_lossy().is_empty());
temp_dir.close().expect("Failed to close temp directory");
}
#[test]
fn test_temp_dir_in_custom_location() {
let parent_temp = tempdir().expect("Failed to create parent temp directory");
let parent_path = parent_temp.path();
let temp_dir = tempdir_in(parent_path).expect("Failed to create temp directory");
let path = temp_dir.path();
assert!(!path.to_string_lossy().is_empty());
assert!(path.starts_with(parent_path));
#[cfg(all(feature = "std", not(feature = "simulator")))]
{
assert!(path.exists());
assert!(path.is_dir());
}
}
#[cfg(feature = "simulator")]
#[test]
fn test_temp_dir_simulator_reset() {
use crate::simulator::temp_dir::reset_temp_dirs;
reset_temp_dirs();
let temp_dir = tempdir().expect("Failed to create temp directory");
let path = temp_dir.path().to_path_buf();
assert!(!path.to_string_lossy().is_empty());
drop(temp_dir);
}
}