async_fd_lock/
read_guard.rs1use 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#[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 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
57impl<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 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#[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}