async_fd_lock/
read_guard.rs

1use std::{
2    io::{self, BufRead, Read, Seek},
3    pin::Pin,
4};
5
6use cfg_if::cfg_if;
7use pin_project::{pin_project, pinned_drop};
8
9use crate::sys::{AsOpenFile, AsOpenFileExt, RwLockGuard};
10
11/// A shared lock on a file.
12///
13/// # Panics
14///
15/// Dropping this type may panic if the lock fails to unlock.
16#[must_use = "if unused the RwLock will immediately unlock"]
17#[derive(Debug)]
18#[pin_project(PinnedDrop)]
19pub struct RwLockReadGuard<T: AsOpenFile> {
20    #[pin]
21    file: Option<T>,
22}
23
24impl<T: AsOpenFile> RwLockReadGuard<T> {
25    pub(crate) fn new<F: AsOpenFile>(file: T, guard: RwLockGuard<F>) -> Self {
26        guard.defuse();
27        Self { file: Some(file) }
28    }
29
30    pub fn inner(&self) -> &T {
31        self.file
32            .as_ref()
33            .expect("file only removed during release")
34    }
35
36    pub fn inner_mut(&mut self) -> &mut T {
37        self.file
38            .as_mut()
39            .expect("file only removed during release")
40    }
41
42    pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
43        self.project()
44            .file
45            .as_pin_mut()
46            .expect("file only removed during release")
47    }
48
49    /// Releases the lock, returning the inner file.
50    pub fn release(mut self) -> io::Result<T> {
51        let file = self.file.take().expect("file only removed during release");
52        file.release_lock_blocking()?;
53        Ok(file)
54    }
55}
56
57/// Delegate [`Read`] to the inner file.
58impl<T: AsOpenFile + Read> Read for RwLockReadGuard<T> {
59    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
60        self.inner_mut().read(buf)
61    }
62
63    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
64        self.inner_mut().read_vectored(bufs)
65    }
66
67    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
68        self.inner_mut().read_to_end(buf)
69    }
70
71    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
72        self.inner_mut().read_to_string(buf)
73    }
74
75    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
76        self.inner_mut().read_exact(buf)
77    }
78
79    fn by_ref(&mut self) -> &mut Self
80    where
81        Self: Sized,
82    {
83        self
84    }
85}
86
87impl<T: AsOpenFile + BufRead> BufRead for RwLockReadGuard<T> {
88    fn fill_buf(&mut self) -> io::Result<&[u8]> {
89        self.inner_mut().fill_buf()
90    }
91
92    fn consume(&mut self, amt: usize) {
93        self.inner_mut().consume(amt)
94    }
95
96    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
97        self.inner_mut().read_until(byte, buf)
98    }
99
100    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
101        self.inner_mut().read_line(buf)
102    }
103}
104
105impl<T: AsOpenFile + Seek> Seek for RwLockReadGuard<T> {
106    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
107        self.inner_mut().seek(pos)
108    }
109
110    fn rewind(&mut self) -> io::Result<()> {
111        self.inner_mut().rewind()
112    }
113
114    fn stream_position(&mut self) -> io::Result<u64> {
115        self.inner_mut().stream_position()
116    }
117
118    fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
119        self.inner_mut().seek_relative(offset)
120    }
121}
122
123cfg_if! {
124    if #[cfg(feature = "async")] {
125        use std::task::{Context, Poll};
126        use tokio::io::{AsyncRead, AsyncBufRead, AsyncSeek, ReadBuf};
127
128        /// Delegate [`AsyncRead`] to the inner file.
129        impl<T: AsOpenFile + AsyncRead> AsyncRead for RwLockReadGuard<T> {
130            fn poll_read(
131                self: Pin<&mut Self>,
132                cx: &mut Context<'_>,
133                buf: &mut ReadBuf<'_>,
134            ) -> Poll<io::Result<()>> {
135                self.inner_pin_mut().poll_read(cx, buf)
136            }
137        }
138
139        impl<T: AsOpenFile + AsyncBufRead> AsyncBufRead for RwLockReadGuard<T> {
140            fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
141                self.inner_pin_mut().poll_fill_buf(cx)
142            }
143
144            fn consume(self: Pin<&mut Self>, amt: usize) {
145                self.inner_pin_mut().consume(amt)
146            }
147        }
148
149        impl<T: AsOpenFile + AsyncSeek> AsyncSeek for RwLockReadGuard<T> {
150            fn start_seek(self: Pin<&mut Self>, position: io::SeekFrom) -> io::Result<()> {
151                self.inner_pin_mut().start_seek(position)
152            }
153
154            fn poll_complete(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
155                self.inner_pin_mut().poll_complete(cx)
156            }
157        }
158    }
159}
160
161/// Release the lock if it was not already released, as indicated by a `None`.
162#[pinned_drop]
163impl<T: AsOpenFile> PinnedDrop for RwLockReadGuard<T> {
164    #[inline]
165    fn drop(self: Pin<&mut Self>) {
166        if let Some(file) = self.project().file.as_pin_mut() {
167            let _ = file.release_lock_blocking();
168        }
169    }
170}