1 | use std::{ |
2 | ops::Deref, |
3 | os::unix::io::{ |
4 | AsRawFd, |
5 | FromRawFd, |
6 | IntoRawFd, |
7 | RawFd, |
8 | }, |
9 | sync::atomic::{ |
10 | AtomicBool, |
11 | Ordering, |
12 | }, |
13 | }; |
14 | |
15 | use inotify_sys as ffi; |
16 | |
17 | |
18 | /// A RAII guard around a `RawFd` that closes it automatically on drop. |
19 | #[derive (Debug)] |
20 | pub struct FdGuard { |
21 | pub(crate) fd : RawFd, |
22 | pub(crate) close_on_drop: AtomicBool, |
23 | } |
24 | |
25 | impl FdGuard { |
26 | |
27 | /// Indicate that the wrapped file descriptor should _not_ be closed |
28 | /// when the guard is dropped. |
29 | /// |
30 | /// This should be called in cases where ownership of the wrapped file |
31 | /// descriptor has been "moved" out of the guard. |
32 | /// |
33 | /// This is factored out into a separate function to ensure that it's |
34 | /// always used consistently. |
35 | #[inline ] |
36 | pub fn should_not_close(&self) { |
37 | self.close_on_drop.store(val:false, order:Ordering::Release); |
38 | } |
39 | } |
40 | |
41 | impl Deref for FdGuard { |
42 | type Target = RawFd; |
43 | |
44 | #[inline ] |
45 | fn deref(&self) -> &Self::Target { |
46 | &self.fd |
47 | } |
48 | } |
49 | |
50 | impl Drop for FdGuard { |
51 | fn drop(&mut self) { |
52 | if self.close_on_drop.load(order:Ordering::Acquire) { |
53 | unsafe { ffi::close(self.fd); } |
54 | } |
55 | } |
56 | } |
57 | |
58 | impl FromRawFd for FdGuard { |
59 | unsafe fn from_raw_fd(fd: RawFd) -> Self { |
60 | FdGuard { |
61 | fd, |
62 | close_on_drop: AtomicBool::new(true), |
63 | } |
64 | } |
65 | } |
66 | |
67 | impl IntoRawFd for FdGuard { |
68 | fn into_raw_fd(self) -> RawFd { |
69 | self.should_not_close(); |
70 | self.fd |
71 | } |
72 | } |
73 | |
74 | impl AsRawFd for FdGuard { |
75 | fn as_raw_fd(&self) -> RawFd { |
76 | self.fd |
77 | } |
78 | } |
79 | |
80 | impl PartialEq for FdGuard { |
81 | fn eq(&self, other: &FdGuard) -> bool { |
82 | self.fd == other.fd |
83 | } |
84 | } |
85 | |