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