1use crate::{fs::asyncify, util::as_ref::OwnedBuf};
2
3use std::{io, path::Path};
4
5pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
27 let path = path.as_ref();
28 let contents = crate::util::as_ref::upgrade(contents);
29
30 #[cfg(all(
31 tokio_unstable,
32 feature = "io-uring",
33 feature = "rt",
34 feature = "fs",
35 target_os = "linux"
36 ))]
37 {
38 let handle = crate::runtime::Handle::current();
39 let driver_handle = handle.inner.driver().io();
40 if driver_handle.check_and_init()? {
41 return write_uring(path, contents).await;
42 }
43 }
44
45 write_spawn_blocking(path, contents).await
46}
47
48#[cfg(all(
49 tokio_unstable,
50 feature = "io-uring",
51 feature = "rt",
52 feature = "fs",
53 target_os = "linux"
54))]
55async fn write_uring(path: &Path, mut buf: OwnedBuf) -> io::Result<()> {
56 use crate::{fs::OpenOptions, runtime::driver::op::Op};
57 use std::os::fd::OwnedFd;
58
59 let file = OpenOptions::new()
60 .write(true)
61 .create(true)
62 .truncate(true)
63 .open(path)
64 .await?;
65
66 let mut fd: OwnedFd = file
67 .try_into_std()
68 .expect("unexpected in-flight operation detected")
69 .into();
70
71 let total: usize = buf.as_ref().len();
72 let mut buf_offset: usize = 0;
73 let mut file_offset: u64 = 0;
74 while buf_offset < total {
75 let (n, _buf, _fd) = Op::write_at(fd, buf, buf_offset, file_offset)?.await?;
76 if n == 0 {
77 return Err(io::ErrorKind::WriteZero.into());
78 }
79
80 buf = _buf;
81 fd = _fd;
82 buf_offset += n as usize;
83 file_offset += n as u64;
84 }
85
86 Ok(())
87}
88
89async fn write_spawn_blocking(path: &Path, contents: OwnedBuf) -> io::Result<()> {
90 let path = path.to_owned();
91 asyncify(move || std::fs::write(path, contents)).await
92}