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