1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::num::NonZeroU8;
15 
16 /// The interested events, such as readable, writeable.
17 #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
18 pub struct Interest(NonZeroU8);
19 use std::ops;
20 
21 const READABLE: u8 = 0b0001;
22 const WRITABLE: u8 = 0b0010;
23 
24 /// A wrapper that wraps around fd events
25 impl Interest {
26     /// An interest for readable events
27     pub const READABLE: Interest = Interest(unsafe { NonZeroU8::new_unchecked(READABLE) });
28     /// An interest for writeable events
29     pub const WRITABLE: Interest = Interest(unsafe { NonZeroU8::new_unchecked(WRITABLE) });
30 
31     /// Combines two Interest into one.
add(self, other: Interest) -> Interest32     pub const fn add(self, other: Interest) -> Interest {
33         Interest(unsafe { NonZeroU8::new_unchecked(self.0.get() | other.0.get()) })
34     }
35 
36     /// Checks if the interest is for readable events.
is_readable(self) -> bool37     pub const fn is_readable(self) -> bool {
38         (self.0.get() & READABLE) != 0
39     }
40 
41     /// Checks if the interest is for writeable events.
is_writable(self) -> bool42     pub const fn is_writable(self) -> bool {
43         (self.0.get() & WRITABLE) != 0
44     }
45 
46     /// Convert interest to the event value.
47     #[cfg(target_os = "linux")]
into_io_event(self) -> libc::c_uint48     pub fn into_io_event(self) -> libc::c_uint {
49         let mut io_event = libc::EPOLLET as u32;
50 
51         if self.is_readable() {
52             io_event |= libc::EPOLLIN as u32;
53             io_event |= libc::EPOLLRDHUP as u32;
54         }
55 
56         if self.is_writable() {
57             io_event |= libc::EPOLLOUT as u32;
58         }
59 
60         io_event as libc::c_uint
61     }
62 }
63 
64 impl ops::BitOr for Interest {
65     type Output = Self;
66 
67     #[inline]
bitor(self, other: Self) -> Self68     fn bitor(self, other: Self) -> Self {
69         self.add(other)
70     }
71 }
72 
73 #[cfg(test)]
74 mod test {
75     /// UT cases for `into_io_event`.
76     ///
77     /// # Brief
78     /// 1. Create different kinds of Interest
79     /// 2. Turn the Interest into IO Event
80     #[cfg(target_os = "linux")]
81     #[test]
ut_interest_to_io_event()82     fn ut_interest_to_io_event() {
83         use std::num::NonZeroU8;
84 
85         use libc::c_int;
86 
87         use crate::Interest;
88 
89         #[allow(clippy::init_numbered_fields)]
90         let interest = Interest {
91             0: NonZeroU8::new(4).unwrap(),
92         };
93         let event = interest.into_io_event();
94         assert_eq!(event as c_int, libc::EPOLLET);
95 
96         let interest = Interest::READABLE;
97         let event = interest.into_io_event();
98         assert_eq!(
99             event as c_int,
100             libc::EPOLLET | libc::EPOLLIN | libc::EPOLLRDHUP
101         );
102 
103         let interest = Interest::WRITABLE;
104         let event = interest.into_io_event();
105         assert_eq!(event as c_int, libc::EPOLLET | libc::EPOLLOUT);
106 
107         let interest = Interest::READABLE | Interest::WRITABLE;
108         let event = interest.into_io_event();
109         assert_eq!(
110             event as c_int,
111             libc::EPOLLET | libc::EPOLLIN | libc::EPOLLRDHUP | libc::EPOLLOUT
112         );
113     }
114 }
115