1#[cfg(all(
2 tokio_unstable,
3 feature = "io-uring",
4 feature = "rt",
5 feature = "fs",
6 target_os = "linux"
7))]
8use crate::io::blocking;
9use crate::{fs::asyncify, util::as_ref::OwnedBuf};
10
11use std::{io, path::Path};
12
13pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
35 let path = path.as_ref();
36
37 #[cfg(all(
38 tokio_unstable,
39 feature = "io-uring",
40 feature = "rt",
41 feature = "fs",
42 target_os = "linux"
43 ))]
44 {
45 let handle = crate::runtime::Handle::current();
46 let driver_handle = handle.inner.driver().io();
47 if driver_handle.check_and_init()? {
48 let mut buf = blocking::Buf::with_capacity(contents.as_ref().len());
49 buf.copy_from(contents.as_ref(), contents.as_ref().len());
50 return write_uring(path, buf).await;
51 }
52 }
53
54 let contents = crate::util::as_ref::upgrade(contents);
55 write_spawn_blocking(path, contents).await
56}
57
58#[cfg(all(
59 tokio_unstable,
60 feature = "io-uring",
61 feature = "rt",
62 feature = "fs",
63 target_os = "linux"
64))]
65async fn write_uring(path: &Path, mut buf: blocking::Buf) -> io::Result<()> {
66 use crate::{fs::OpenOptions, io::uring::utils::ArcFd, runtime::driver::op::Op};
67 use std::sync::Arc;
68
69 let file = OpenOptions::new()
70 .write(true)
71 .create(true)
72 .truncate(true)
73 .open(path)
74 .await?;
75
76 let mut fd: ArcFd = Arc::new(
77 file.try_into_std()
78 .expect("unexpected in-flight operation detected"),
79 );
80
81 let mut file_offset: u64 = 0;
82 while !buf.is_empty() {
83 let (n, _buf, _fd) = Op::write_at(fd, buf, file_offset).await;
84 let n = n?;
86 if n == 0 {
87 return Err(io::ErrorKind::WriteZero.into());
88 }
89
90 buf = _buf;
91 fd = _fd;
92 file_offset += n as u64;
93 }
94
95 Ok(())
96}
97
98async fn write_spawn_blocking(path: &Path, contents: OwnedBuf) -> io::Result<()> {
99 let path = path.to_owned();
100 asyncify(move || std::fs::write(path, contents)).await
101}