Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit820cc81

Browse files
committed
Add FileExt traits
Addresses issue#576 to add pwrite/pread support to async_std forparity with std & tokio.
1 parent5ee022b commit820cc81

File tree

4 files changed

+301
-2
lines changed

4 files changed

+301
-2
lines changed

‎Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ std = [
5353
"futures-channel",
5454
"async-channel",
5555
"async-lock",
56+
"async-trait",
5657
]
5758
alloc = [
5859
"futures-core/alloc",
@@ -77,6 +78,7 @@ pin-project-lite = { version = "0.2.0", optional = true }
7778
pin-utils = {version ="0.1.0-alpha.4",optional =true }
7879
slab = {version ="0.4.2",optional =true }
7980
async-channel = {version ="1.5.1",optional =true }
81+
async-trait = {version ="0.1.42",optional =true }
8082

8183
# Devdepencency, but they are not allowed to be optional :/
8284
surf = {version ="2.0.0",optional =true }

‎src/fs/file.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,4 +938,35 @@ mod tests {
938938
.unwrap();
939939
});
940940
}
941+
942+
#[cfg(target_os ="windows")]
943+
#[test]
944+
fnasync_file_win_positional_io(){
945+
usesuper::os::windows::fs::FileExt;
946+
947+
crate::task::block_on(asyncmove{
948+
let file =File::open(file!()).await.unwrap();
949+
assert_eq!(10u64, file.seek_write(&[5u8;10],10u64).await.unwrap());
950+
951+
letmut buf:[u8;20];
952+
assert_eq!(20u64, file.seek_read(&buf,0)).await.unwrap();
953+
assert_eq!(buf.iter(),[0u8;10].iter().chain([5u8;10].iter()));
954+
});
955+
}
956+
957+
#[cfg(target_os ="unix")]
958+
#[test]
959+
fnasync_file_unix_positional_io(){
960+
usesuper::os::unix::fs::FileExt;
961+
962+
crate::task::block_on(asyncmove{
963+
let file =File::open(file!()).await.unwrap();
964+
assert_eq!(10u64, file.write_all_at(&[5u8;10],10u64).await.unwrap());
965+
966+
letmut buf:[u8;20];
967+
assert_eq!(20u64, file.read_exact_at(&buf,0)).await.unwrap();
968+
assert_eq!(buf.iter(),[0u8;10].iter().chain([5u8;10].iter()));
969+
});
970+
971+
}
941972
}

‎src/os/unix/fs.rs

Lines changed: 195 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Resu
3030
}
3131

3232
cfg_not_docs!{
33-
pubuse std::os::unix::fs::{DirBuilderExt,DirEntryExt,OpenOptionsExt};
33+
pubuse std::os::unix::fs::{DirBuilderExt,DirEntryExt,OpenOptionsExt,FileExt};
3434
}
3535

3636
cfg_docs!{
37+
use async_trait::async_trait;
38+
3739
/// Unix-specific extensions to `DirBuilder`.
3840
pubtraitDirBuilderExt{
3941
/// Sets the mode to create new directories with. This option defaults to
@@ -68,4 +70,196 @@ cfg_docs! {
6870
/// This options overwrites any previously set custom flags.
6971
fn custom_flags(&mutself, flags:i32) ->&mutSelf;
7072
}
73+
74+
/// Unix-specific extensions to [`fs::File`].
75+
#[async_trait]
76+
pubtraitFileExt{
77+
/// Reads a number of bytes starting from a given offset.
78+
///
79+
/// Returns the number of bytes read.
80+
///
81+
/// The offset is relative to the start of the file and thus independent
82+
/// from the current cursor.
83+
///
84+
/// The current file cursor is not affected by this function.
85+
///
86+
/// Note that similar to [`File::read`], it is not an error to return with a
87+
/// short read.
88+
///
89+
/// [`File::read`]: fs::File::read
90+
///
91+
/// # Examples
92+
///
93+
/// ```no_run
94+
/// use async_std::io;
95+
/// use async_std::fs::File;
96+
/// use async_std::os::unix::prelude::FileExt;
97+
///
98+
/// async fn main() -> io::Result<()> {
99+
/// let mut buf = [0u8; 8];
100+
/// let file = File::open("foo.txt").await?;
101+
///
102+
/// // We now read 8 bytes from the offset 10.
103+
/// let num_bytes_read = file.read_at(&mut buf, 10).await?;
104+
/// println!("read {} bytes: {:?}", num_bytes_read, buf);
105+
/// Ok(())
106+
/// }
107+
/// ```
108+
asyncfn read_at(&self, buf:&mut[u8], offset:u64) -> io::Result<usize>;
109+
110+
/// Reads the exact number of byte required to fill `buf` from the given offset.
111+
///
112+
/// The offset is relative to the start of the file and thus independent
113+
/// from the current cursor.
114+
///
115+
/// The current file cursor is not affected by this function.
116+
///
117+
/// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
118+
///
119+
/// [`read_at`]: FileExt::read_at
120+
///
121+
/// # Errors
122+
///
123+
/// If this function encounters an error of the kind
124+
/// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
125+
/// will continue.
126+
///
127+
/// If this function encounters an "end of file" before completely filling
128+
/// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
129+
/// The contents of `buf` are unspecified in this case.
130+
///
131+
/// If any other read error is encountered then this function immediately
132+
/// returns. The contents of `buf` are unspecified in this case.
133+
///
134+
/// If this function returns an error, it is unspecified how many bytes it
135+
/// has read, but it will never read more than would be necessary to
136+
/// completely fill the buffer.
137+
///
138+
/// # Examples
139+
///
140+
/// ```no_run
141+
/// use async_std::io;
142+
/// use async_std::fs::File;
143+
/// use async_std::os::unix::prelude::FileExt;
144+
///
145+
/// async fn main() -> io::Result<()> {
146+
/// let mut buf = [0u8; 8];
147+
/// let file = File::open("foo.txt").await?;
148+
///
149+
/// // We now read exactly 8 bytes from the offset 10.
150+
/// file.read_exact_at(&mut buf, 10).await?;
151+
/// println!("read {} bytes: {:?}", buf.len(), buf);
152+
/// Ok(())
153+
/// }
154+
/// ```
155+
asyncfn read_exact_at(&self,mut buf:&mut[u8],mut offset:u64) -> io::Result<()>{
156+
while !buf.is_empty(){
157+
matchself.read_at(buf, offset).await{
158+
Ok(0) =>break,
159+
Ok(n) =>{
160+
let tmp = buf;
161+
buf =&mut tmp[n..];
162+
offset += nasu64;
163+
}
164+
Err(ref e)if e.kind() == io::ErrorKind::Interrupted =>{}
165+
Err(e) =>returnErr(e),
166+
}
167+
}
168+
if !buf.is_empty(){
169+
Err(io::Error::new(io::ErrorKind::UnexpectedEof,"failed to fill whole buffer"))
170+
} else{
171+
Ok(())
172+
}
173+
}
174+
175+
/// Writes a number of bytes starting from a given offset.
176+
///
177+
/// Returns the number of bytes written.
178+
///
179+
/// The offset is relative to the start of the file and thus independent
180+
/// from the current cursor.
181+
///
182+
/// The current file cursor is not affected by this function.
183+
///
184+
/// When writing beyond the end of the file, the file is appropriately
185+
/// extended and the intermediate bytes are initialized with the value 0.
186+
///
187+
/// Note that similar to [`File::write`], it is not an error to return a
188+
/// short write.
189+
///
190+
/// [`File::write`]: fs::File::write
191+
///
192+
/// # Examples
193+
///
194+
/// ```no_run
195+
/// use async_std::fs::File;
196+
/// use async_std::io;
197+
/// use async_std::os::unix::prelude::FileExt;
198+
///
199+
/// async fn main() -> io::Result<()> {
200+
/// let file = File::open("foo.txt").await?;
201+
///
202+
/// // We now write at the offset 10.
203+
/// file.write_at(b"sushi", 10).await?;
204+
/// Ok(())
205+
/// }
206+
/// ```
207+
asyncfn write_at(&self, buf:&[u8], offset:u64) -> io::Result<usize>;
208+
209+
/// Attempts to write an entire buffer starting from a given offset.
210+
///
211+
/// The offset is relative to the start of the file and thus independent
212+
/// from the current cursor.
213+
///
214+
/// The current file cursor is not affected by this function.
215+
///
216+
/// This method will continuously call [`write_at`] until there is no more data
217+
/// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
218+
/// returned. This method will not return until the entire buffer has been
219+
/// successfully written or such an error occurs. The first error that is
220+
/// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
221+
/// returned.
222+
///
223+
/// # Errors
224+
///
225+
/// This function will return the first error of
226+
/// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
227+
///
228+
/// [`write_at`]: FileExt::write_at
229+
///
230+
/// # Examples
231+
///
232+
/// ```no_run
233+
/// use async_std::fs::File;
234+
/// use async_std::io;
235+
/// use async_std::os::unix::prelude::FileExt;
236+
///
237+
/// async fn main() -> io::Result<()> {
238+
/// let file = File::open("foo.txt").await?;
239+
///
240+
/// // We now write at the offset 10.
241+
/// file.write_all_at(b"sushi", 10).await?;
242+
/// Ok(())
243+
/// }
244+
/// ```
245+
asyncfn write_all_at(&self,mut buf:&[u8],mut offset:u64) -> io::Result<()>{
246+
while !buf.is_empty(){
247+
matchself.write_at(buf, offset).await{
248+
Ok(0) =>{
249+
returnErr(io::Error::new(
250+
io::ErrorKind::WriteZero,
251+
"failed to write whole buffer",
252+
));
253+
}
254+
Ok(n) =>{
255+
buf =&buf[n..];
256+
offset += nasu64
257+
}
258+
Err(ref e)if e.kind() == io::ErrorKind::Interrupted =>{}
259+
Err(e) =>returnErr(e),
260+
}
261+
}
262+
Ok(())
263+
}
264+
}
71265
}

‎src/os/windows/fs.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ pub async fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io:
5555
}
5656

5757
cfg_not_docs!{
58-
pubuse std::os::windows::fs::{OpenOptionsExt};
58+
pubuse std::os::windows::fs::{OpenOptionsExt,FileExt};
5959
}
6060

6161
cfg_docs!{
62+
use async_trait::async_trait;
63+
6264
/// Windows-specific extensions to `OpenOptions`.
6365
pubtraitOpenOptionsExt{
6466
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
@@ -223,4 +225,74 @@ cfg_docs! {
223225
/// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
224226
fn security_qos_flags(&mutself, flags:u32) ->&mutSelf;
225227
}
228+
229+
/// Windows-specific extensions to [`fs::File`].
230+
#[async_trait]
231+
pubtraitFileExt{
232+
/// Seeks to a given position and reads a number of bytes.
233+
///
234+
/// Returns the number of bytes read.
235+
///
236+
/// The offset is relative to the start of the file and thus independent
237+
/// from the current cursor. The current cursor **is** affected by this
238+
/// function, it is set to the end of the read.
239+
///
240+
/// Reading beyond the end of the file will always return with a length of
241+
/// 0\.
242+
///
243+
/// Note that similar to `File::read`, it is not an error to return with a
244+
/// short read. When returning from such a short read, the file pointer is
245+
/// still updated.
246+
///
247+
/// # Examples
248+
///
249+
/// ```no_run
250+
/// use async_std::io;
251+
/// use async_std::fs::File;
252+
/// use async_std::os::windows::prelude::*;
253+
///
254+
/// fn main() -> io::Result<()> {
255+
/// let mut file = File::open("foo.txt").await?;
256+
/// let mut buffer = [0; 10];
257+
///
258+
/// // Read 10 bytes, starting 72 bytes from the
259+
/// // start of the file.
260+
/// file.seek_read(&mut buffer[..], 72).await?;
261+
/// Ok(())
262+
/// }
263+
/// ```
264+
asyncfn seek_read(&self, buf:&mut[u8], offset:u64) -> io::Result<usize>;
265+
266+
/// Seeks to a given position and writes a number of bytes.
267+
///
268+
/// Returns the number of bytes written.
269+
///
270+
/// The offset is relative to the start of the file and thus independent
271+
/// from the current cursor. The current cursor **is** affected by this
272+
/// function, it is set to the end of the write.
273+
///
274+
/// When writing beyond the end of the file, the file is appropriately
275+
/// extended and the intermediate bytes are left uninitialized.
276+
///
277+
/// Note that similar to `File::write`, it is not an error to return a
278+
/// short write. When returning from such a short write, the file pointer
279+
/// is still updated.
280+
///
281+
/// # Examples
282+
///
283+
/// ```no_run
284+
/// use async_std::fs::File;
285+
/// use async_std::os::windows::prelude::*;
286+
///
287+
/// fn main() -> std::io::Result<()> {
288+
/// let mut buffer = File::create("foo.txt").await?;
289+
///
290+
/// // Write a byte string starting 72 bytes from
291+
/// // the start of the file.
292+
/// buffer.seek_write(b"some bytes", 72).await?;
293+
/// Ok(())
294+
/// }
295+
/// ```
296+
asyncfn seek_write(&self, buf:&[u8], offset:u64) -> io::Result<usize>;
297+
}
226298
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp