• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Context types for polling systems, e.g. kqueue and epoll.
2 
3 #![allow(unsafe_code)]
4 
5 use crate::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
6 
7 use core::fmt;
8 use core::marker::PhantomData;
9 use core::ops::Deref;
10 
11 /// A reference to a `T`.
12 pub struct Ref<'a, T> {
13     t: T,
14     _phantom: PhantomData<&'a T>,
15 }
16 
17 impl<'a, T> Ref<'a, T> {
18     #[inline]
new(t: T) -> Self19     fn new(t: T) -> Self {
20         Self {
21             t,
22             _phantom: PhantomData,
23         }
24     }
25 
26     #[inline]
consume(self) -> T27     fn consume(self) -> T {
28         self.t
29     }
30 }
31 
32 impl<'a, T> Deref for Ref<'a, T> {
33     type Target = T;
34 
35     #[inline]
deref(&self) -> &T36     fn deref(&self) -> &T {
37         &self.t
38     }
39 }
40 
41 impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result42     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
43         self.t.fmt(fmt)
44     }
45 }
46 
47 /// A trait for data stored within an [`Epoll`] instance.
48 ///
49 /// [`Epoll`]: crate::io::epoll::Epoll
50 pub trait Context {
51     /// The type of an element owned by this context.
52     type Data;
53 
54     /// The type of a value used to refer to an element owned by this context.
55     type Target: AsFd;
56 
57     /// Assume ownership of `data`, and returning a `Target`.
acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>58     fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>;
59 
60     /// Encode `target` as a `u64`. The only requirement on this value is that
61     /// it be decodable by `decode`.
encode(&self, target: Ref<'_, Self::Target>) -> u6462     fn encode(&self, target: Ref<'_, Self::Target>) -> u64;
63 
64     /// Decode `raw`, which is a value encoded by `encode`, into a `Target`.
65     ///
66     /// # Safety
67     ///
68     /// `raw` must be a `u64` value returned from `encode`, from the same
69     /// context, and within the context's lifetime.
decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>70     unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>;
71 
72     /// Release ownership of the value referred to by `target` and return it.
release(&self, target: Ref<'_, Self::Target>) -> Self::Data73     fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data;
74 }
75 
76 /// A type implementing [`Context`] where the `Data` type is `BorrowedFd<'a>`.
77 pub struct Borrowing<'a> {
78     _phantom: PhantomData<BorrowedFd<'a>>,
79 }
80 
81 impl<'a> Context for Borrowing<'a> {
82     type Data = BorrowedFd<'a>;
83     type Target = BorrowedFd<'a>;
84 
85     #[inline]
acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>86     fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> {
87         Ref::new(data)
88     }
89 
90     #[inline]
encode(&self, target: Ref<'_, Self::Target>) -> u6491     fn encode(&self, target: Ref<'_, Self::Target>) -> u64 {
92         target.as_raw_fd() as u64
93     }
94 
95     #[inline]
decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>96     unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> {
97         Ref::new(BorrowedFd::<'a>::borrow_raw(raw as RawFd))
98     }
99 
100     #[inline]
release(&self, target: Ref<'_, Self::Target>) -> Self::Data101     fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data {
102         target.consume()
103     }
104 }
105 
106 /// A type implementing [`Context`] where the `Data` type is `T`, a type
107 /// implementing `From<OwnedFd>` and `From<T> for OwnedFd`.
108 ///
109 /// This may be used with [`OwnedFd`], or higher-level types like
110 /// [`std::fs::File`] or [`std::net::TcpStream`].
111 #[cfg(not(feature = "rustc-dep-of-std"))]
112 pub struct Owning<'context, T: Into<OwnedFd> + From<OwnedFd>> {
113     _phantom: PhantomData<&'context T>,
114 }
115 
116 #[cfg(not(feature = "rustc-dep-of-std"))]
117 impl<'context, T: Into<OwnedFd> + From<OwnedFd>> Owning<'context, T> {
118     /// Creates a new empty `Owning`.
119     #[allow(clippy::new_without_default)] // This is a specialized type that doesn't need to be generically constructible.
120     #[inline]
new() -> Self121     pub fn new() -> Self {
122         Self {
123             _phantom: PhantomData,
124         }
125     }
126 }
127 
128 #[cfg(not(feature = "rustc-dep-of-std"))]
129 impl<'context, T: AsFd + Into<OwnedFd> + From<OwnedFd>> Context for Owning<'context, T> {
130     type Data = T;
131     type Target = BorrowedFd<'context>;
132 
133     #[inline]
acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target>134     fn acquire<'call>(&self, data: Self::Data) -> Ref<'call, Self::Target> {
135         let fd: OwnedFd = data.into();
136         let raw_fd = fd.into_raw_fd();
137         // Safety: `epoll` will assign ownership of the file descriptor to the
138         // kernel epoll object. We use `Into<OwnedFd>`+`IntoRawFd` to consume
139         // the `Data` and extract the raw file descriptor and then "borrow" it
140         // with `borrow_raw` knowing that the borrow won't outlive the
141         // kernel epoll object.
142         unsafe { Ref::new(BorrowedFd::<'context>::borrow_raw(raw_fd)) }
143     }
144 
145     #[inline]
encode(&self, target: Ref<'_, Self::Target>) -> u64146     fn encode(&self, target: Ref<'_, Self::Target>) -> u64 {
147         target.as_fd().as_raw_fd() as u64
148     }
149 
150     #[inline]
decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target>151     unsafe fn decode<'call>(&self, raw: u64) -> Ref<'call, Self::Target> {
152         Ref::new(BorrowedFd::<'context>::borrow_raw(raw as RawFd))
153     }
154 
155     #[inline]
release(&self, target: Ref<'_, Self::Target>) -> Self::Data156     fn release(&self, target: Ref<'_, Self::Target>) -> Self::Data {
157         // The file descriptor was held by the kernel epoll object and is now
158         // being released, so we can create a new `OwnedFd` that assumes
159         // ownership.
160         let raw_fd = target.consume().as_raw_fd();
161         unsafe { T::from(OwnedFd::from_raw_fd(raw_fd).into()) }
162     }
163 }
164