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