1use std::io::{self, Read, Seek, Write};
6use std::path::Path;
7
8use seams_rs_core::{
9 AsyncFileRead, AsyncFileSystem, AsyncFileWrite, BoxFuture, FileRead, FileSystem, FileWrite,
10 Metadata,
11};
12use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
13
14#[derive(Debug, Default, Clone, Copy)]
18pub struct StdFileSystem;
19
20impl StdFileSystem {
21 pub fn new() -> Self {
23 Self
24 }
25}
26
27fn metadata_from_std(m: std::fs::Metadata) -> Metadata {
28 Metadata::new(m.len(), m.is_file(), m.is_dir(), m.modified().ok())
29}
30
31impl FileSystem for StdFileSystem {
32 fn create_dir_all(&self, path: &Path) -> io::Result<()> {
33 std::fs::create_dir_all(path)
34 }
35
36 fn remove_dir_all(&self, path: &Path) -> io::Result<()> {
37 std::fs::remove_dir_all(path)
38 }
39
40 fn try_exists(&self, path: &Path) -> io::Result<bool> {
41 std::fs::exists(path)
42 }
43
44 fn open_read(&self, path: &Path) -> io::Result<Box<dyn FileRead>> {
45 Ok(Box::new(StdFileRead(std::fs::File::open(path)?)))
46 }
47
48 fn open_write(&self, path: &Path) -> io::Result<Box<dyn FileWrite>> {
49 Ok(Box::new(StdFileWrite(std::fs::File::create(path)?)))
50 }
51
52 fn metadata(&self, path: &Path) -> io::Result<Metadata> {
53 Ok(metadata_from_std(std::fs::metadata(path)?))
54 }
55
56 fn rename(&self, from: &Path, to: &Path) -> io::Result<()> {
57 std::fs::rename(from, to)
58 }
59}
60
61struct StdFileRead(std::fs::File);
62
63impl FileRead for StdFileRead {
64 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
65 Read::read_to_end(&mut self.0, buf)
66 }
67 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
68 Read::read_exact(&mut self.0, buf)
69 }
70 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
71 Seek::seek(&mut self.0, pos)
72 }
73}
74
75struct StdFileWrite(std::fs::File);
76
77impl FileWrite for StdFileWrite {
78 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
79 Write::write_all(&mut self.0, buf)
80 }
81 fn flush(&mut self) -> io::Result<()> {
82 Write::flush(&mut self.0)
83 }
84 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
85 Seek::seek(&mut self.0, pos)
86 }
87}
88
89#[derive(Debug, Default, Clone, Copy)]
93pub struct TokioFileSystem;
94
95impl TokioFileSystem {
96 pub fn new() -> Self {
98 Self
99 }
100}
101
102impl AsyncFileSystem for TokioFileSystem {
103 fn create_dir_all<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, io::Result<()>> {
104 Box::pin(tokio::fs::create_dir_all(path))
105 }
106
107 fn remove_dir_all<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, io::Result<()>> {
108 Box::pin(tokio::fs::remove_dir_all(path))
109 }
110
111 fn try_exists<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, io::Result<bool>> {
112 Box::pin(tokio::fs::try_exists(path))
113 }
114
115 fn open_read<'a>(
116 &'a self,
117 path: &'a Path,
118 ) -> BoxFuture<'a, io::Result<Box<dyn AsyncFileRead>>> {
119 Box::pin(async move {
120 let f = tokio::fs::File::open(path).await?;
121 Ok(Box::new(TokioFileRead(f)) as Box<dyn AsyncFileRead>)
122 })
123 }
124
125 fn open_write<'a>(
126 &'a self,
127 path: &'a Path,
128 ) -> BoxFuture<'a, io::Result<Box<dyn AsyncFileWrite>>> {
129 Box::pin(async move {
130 let f = tokio::fs::File::create(path).await?;
131 Ok(Box::new(TokioFileWrite(f)) as Box<dyn AsyncFileWrite>)
132 })
133 }
134
135 fn metadata<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, io::Result<Metadata>> {
136 Box::pin(async move {
137 let m = tokio::fs::metadata(path).await?;
138 Ok(Metadata::new(
139 m.len(),
140 m.is_file(),
141 m.is_dir(),
142 m.modified().ok(),
143 ))
144 })
145 }
146
147 fn rename<'a>(&'a self, from: &'a Path, to: &'a Path) -> BoxFuture<'a, io::Result<()>> {
148 Box::pin(tokio::fs::rename(from, to))
149 }
150}
151
152struct TokioFileRead(tokio::fs::File);
153
154impl AsyncFileRead for TokioFileRead {
155 fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> BoxFuture<'a, io::Result<usize>> {
156 Box::pin(self.0.read_to_end(buf))
157 }
158 fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> BoxFuture<'a, io::Result<()>> {
159 Box::pin(async move {
160 self.0.read_exact(buf).await?;
161 Ok(())
162 })
163 }
164 fn seek(&mut self, pos: io::SeekFrom) -> BoxFuture<'_, io::Result<u64>> {
165 Box::pin(self.0.seek(pos))
166 }
167}
168
169struct TokioFileWrite(tokio::fs::File);
170
171impl AsyncFileWrite for TokioFileWrite {
172 fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> BoxFuture<'a, io::Result<()>> {
173 Box::pin(self.0.write_all(buf))
174 }
175 fn flush(&mut self) -> BoxFuture<'_, io::Result<()>> {
176 Box::pin(self.0.flush())
177 }
178 fn seek(&mut self, pos: io::SeekFrom) -> BoxFuture<'_, io::Result<u64>> {
179 Box::pin(self.0.seek(pos))
180 }
181}