1#[cfg(windows)]
2use std::io::{Seek, SeekFrom};
3#[cfg(unix)]
4use std::os::unix::fs::FileExt;
5#[cfg(windows)]
6use std::os::windows::fs::FileExt;
7use std::{fs::File, io, io::Write, path::Path};
8
9use super::{ReadAt, Size, WriteAt};
10
11#[derive(Debug)]
43pub struct RandomAccessFile {
44 file: File,
45 #[cfg(not(unix))]
46 pos: u64,
47}
48
49impl RandomAccessFile {
50 pub fn open<P: AsRef<Path>>(path: P) -> io::Result<RandomAccessFile> {
53 RandomAccessFile::try_new(File::open(path)?)
54 }
55
56 pub fn try_new(file: File) -> io::Result<RandomAccessFile> {
58 RandomAccessFile::try_new_impl(file)
59 }
60
61 #[cfg(all(unix, target_os = "linux"))]
62 fn try_new_impl(file: File) -> io::Result<RandomAccessFile> {
63 unsafe {
64 use std::os::unix::io::AsRawFd;
65 libc::posix_fadvise(file.as_raw_fd(), 0, 0, libc::POSIX_FADV_RANDOM);
66 }
67
68 Ok(RandomAccessFile { file })
69 }
70
71 #[cfg(all(unix, not(target_os = "linux")))]
72 fn try_new_impl(file: File) -> io::Result<RandomAccessFile> {
73 Ok(RandomAccessFile { file })
74 }
75
76 #[cfg(not(unix))]
77 fn try_new_impl(mut file: File) -> io::Result<RandomAccessFile> {
78 let pos = file.seek(SeekFrom::Current(0))?;
79 Ok(RandomAccessFile { file, pos })
80 }
81
82 pub fn try_into_inner(self) -> Result<File, (RandomAccessFile, io::Error)> {
84 RandomAccessFile::try_into_inner_impl(self)
85 }
86
87 #[cfg(unix)]
88 fn try_into_inner_impl(self) -> Result<File, (RandomAccessFile, io::Error)> {
89 Ok(self.file)
90 }
91
92 #[cfg(not(unix))]
93 fn try_into_inner_impl(mut self) -> Result<File, (RandomAccessFile, io::Error)> {
94 match self.file.seek(SeekFrom::Start(self.pos)) {
95 Ok(_) => Ok(self.file),
96 Err(err) => Err((self, err)),
97 }
98 }
99}
100
101#[cfg(unix)]
102impl ReadAt for RandomAccessFile {
103 #[inline]
104 fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
105 FileExt::read_at(&self.file, buf, pos)
106 }
107}
108
109#[cfg(unix)]
110impl WriteAt for &RandomAccessFile {
111 fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
112 FileExt::write_at(&self.file, buf, pos)
113 }
114
115 fn flush(&mut self) -> io::Result<()> {
116 Write::flush(&mut &self.file)
117 }
118}
119
120#[cfg(windows)]
121impl ReadAt for RandomAccessFile {
122 #[inline]
123 fn read_at(&self, pos: u64, buf: &mut [u8]) -> io::Result<usize> {
124 FileExt::seek_read(&self.file, buf, pos)
125 }
126}
127
128#[cfg(windows)]
129impl WriteAt for &RandomAccessFile {
130 fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
131 FileExt::seek_write(&self.file, buf, pos)
132 }
133
134 fn flush(&mut self) -> io::Result<()> {
135 Write::flush(&mut &self.file)
136 }
137}
138
139impl WriteAt for RandomAccessFile {
140 fn write_at(&mut self, pos: u64, buf: &[u8]) -> io::Result<usize> {
141 WriteAt::write_at(&mut &*self, pos, buf)
142 }
143
144 fn flush(&mut self) -> io::Result<()> {
145 WriteAt::flush(&mut &*self)
146 }
147}
148
149impl Size for RandomAccessFile {
150 fn size(&self) -> io::Result<Option<u64>> {
151 self.file.size()
152 }
153}