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

Commitd182d1b

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

File tree

4 files changed

+298
-2
lines changed

4 files changed

+298
-2
lines changed

‎Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ unstable = [
3838
"std",
3939
"async-io",
4040
"async-process",
41+
"file-ext",
4142
]
4243
attributes = ["async-attributes"]
4344
std = [
@@ -61,6 +62,7 @@ alloc = [
6162
tokio1 = ["async-global-executor/tokio"]
6263
tokio02 = ["async-global-executor/tokio02"]
6364
tokio03 = ["async-global-executor/tokio03"]
65+
file-ext = ["async-trait"]
6466

6567
[dependencies]
6668
async-attributes = {version ="1.1.1",optional =true }
@@ -77,6 +79,7 @@ pin-project-lite = { version = "0.2.0", optional = true }
7779
pin-utils = {version ="0.1.0-alpha.4",optional =true }
7880
slab = {version ="0.4.2",optional =true }
7981
async-channel = {version ="1.5.1",optional =true }
82+
async-trait = {version ="0.1.42",optional =true }
8083

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

‎src/os/windows/fs.rs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ 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!{
@@ -227,4 +227,74 @@ cfg_docs! {
227227
#[stable(feature ="open_options_ext", since ="1.10.0")]
228228
fn security_qos_flags(&mutself, flags:u32) ->&mutSelf;
229229
}
230+
231+
/// Windows-specific extensions to [`fs::File`].
232+
#[async_trait]
233+
pubtraitFileExt{
234+
/// Seeks to a given position and reads a number of bytes.
235+
///
236+
/// Returns the number of bytes read.
237+
///
238+
/// The offset is relative to the start of the file and thus independent
239+
/// from the current cursor. The current cursor **is** affected by this
240+
/// function, it is set to the end of the read.
241+
///
242+
/// Reading beyond the end of the file will always return with a length of
243+
/// 0\.
244+
///
245+
/// Note that similar to `File::read`, it is not an error to return with a
246+
/// short read. When returning from such a short read, the file pointer is
247+
/// still updated.
248+
///
249+
/// # Examples
250+
///
251+
/// ```no_run
252+
/// use async_std::io;
253+
/// use async_std::fs::File;
254+
/// use async_std::os::windows::prelude::*;
255+
///
256+
/// fn main() -> io::Result<()> {
257+
/// let mut file = File::open("foo.txt").await?;
258+
/// let mut buffer = [0; 10];
259+
///
260+
/// // Read 10 bytes, starting 72 bytes from the
261+
/// // start of the file.
262+
/// file.seek_read(&mut buffer[..], 72).await?;
263+
/// Ok(())
264+
/// }
265+
/// ```
266+
asyncfn seek_read(&self, buf:&mut[u8], offset:u64) -> io::Result<usize>;
267+
268+
/// Seeks to a given position and writes a number of bytes.
269+
///
270+
/// Returns the number of bytes written.
271+
///
272+
/// The offset is relative to the start of the file and thus independent
273+
/// from the current cursor. The current cursor **is** affected by this
274+
/// function, it is set to the end of the write.
275+
///
276+
/// When writing beyond the end of the file, the file is appropriately
277+
/// extended and the intermediate bytes are left uninitialized.
278+
///
279+
/// Note that similar to `File::write`, it is not an error to return a
280+
/// short write. When returning from such a short write, the file pointer
281+
/// is still updated.
282+
///
283+
/// # Examples
284+
///
285+
/// ```no_run
286+
/// use async_std::fs::File;
287+
/// use async_std::os::windows::prelude::*;
288+
///
289+
/// fn main() -> std::io::Result<()> {
290+
/// let mut buffer = File::create("foo.txt").await?;
291+
///
292+
/// // Write a byte string starting 72 bytes from
293+
/// // the start of the file.
294+
/// buffer.seek_write(b"some bytes", 72).await?;
295+
/// Ok(())
296+
/// }
297+
/// ```
298+
asyncfn seek_write(&self, buf:&[u8], offset:u64) -> io::Result<usize>;
299+
}
230300
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp