1use std::{convert, mem, num};
2
3use o3::{base::time::Positive, buffer, mem::quota};
4
5use crate::{io::fd, thread::timer};
6
7pub mod engine;
8pub mod io;
9pub mod kernel;
10pub mod memory;
11pub mod ring;
12pub mod table;
13
14pub mod thread;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
18#[repr(transparent)]
19pub struct Errno(num::NonZero<i32>);
20
21impl Errno {
22 pub const BAD_DESCRIPTOR: Self = Self::fixed::<{ libc::EBADF }>();
23 pub const CANCELED: Self = Self::fixed::<{ libc::ECANCELED }>();
24 pub const IN_PROGRESS: Self = Self::fixed::<{ libc::EINPROGRESS }>();
25 pub const NO_BUFFER_SPACE: Self = Self::fixed::<{ libc::ENOBUFS }>();
26 pub const ALREADY_EXISTS: Self = Self::fixed::<{ libc::EEXIST }>();
27 pub const PROTOCOL: Self = Self::fixed::<{ libc::EPROTO }>();
28 pub const TOO_MANY_FILES: Self = Self::fixed::<{ libc::EMFILE }>();
29 pub const INTERRUPTED: Self = Self::fixed::<{ libc::EINTR }>();
30 pub const NOT_FOUND: Self = Self::fixed::<{ libc::ENOENT }>();
31 pub const NOT_DIRECTORY: Self = Self::fixed::<{ libc::ENOTDIR }>();
32 pub const SYMLINK_LOOP: Self = Self::fixed::<{ libc::ELOOP }>();
33 pub const NAME_TOO_LONG: Self = Self::fixed::<{ libc::ENAMETOOLONG }>();
34 pub const INVALID_ARGUMENT: Self = Self::fixed::<{ libc::EINVAL }>();
35 pub const IO: Self = Self::fixed::<{ libc::EIO }>();
36 pub const MESSAGE_TOO_LONG: Self = Self::fixed::<{ libc::EMSGSIZE }>();
37
38 const fn fixed<const CODE: i32>() -> Self {
39 const { assert!(CODE > 0) };
40 Self(
41 num::NonZero::<u32>::MIN
42 .saturating_add(CODE as u32 - 1)
43 .cast_signed(),
44 )
45 }
46
47 pub const fn code(self) -> num::NonZero<i32> {
48 self.0
49 }
50
51 pub const fn is_intr(self) -> bool {
52 self.0.get() == libc::EINTR
53 }
54
55 pub const fn is_canceled(self) -> bool {
56 self.0.get() == libc::ECANCELED
57 }
58
59 pub const fn is_block(self) -> bool {
60 self.0.get() == libc::EAGAIN || self.0.get() == libc::EWOULDBLOCK
61 }
62
63 pub const fn is_refused(self) -> bool {
64 self.0.get() == libc::ECONNREFUSED
65 }
66
67 pub const fn is_pipe(self) -> bool {
68 self.0.get() == libc::EPIPE
69 }
70
71 pub const fn is_reset(self) -> bool {
72 self.0.get() == libc::ECONNRESET
73 }
74
75 pub const fn is_aborted(self) -> bool {
76 self.0.get() == libc::ECONNABORTED
77 }
78
79 pub const fn is_not_connected(self) -> bool {
80 self.0.get() == libc::ENOTCONN
81 }
82
83 pub const fn is_not_found(self) -> bool {
84 self.0.get() == libc::ENOENT || self.0.get() == libc::ENOTDIR
85 }
86}
87
88impl TryFrom<i32> for Errno {
89 type Error = kernel::Invalid;
90
91 fn try_from(raw: i32) -> Result<Self, Self::Error> {
92 match num::NonZero::new(raw) {
93 Some(code) => Self::try_from(code),
94 None => Err(kernel::Invalid {
95 actual: 0,
96 minimum: 1,
97 maximum: i32::MAX as libc::ssize_t,
98 }),
99 }
100 }
101}
102
103impl TryFrom<num::NonZero<i32>> for Errno {
104 type Error = kernel::Invalid;
105
106 fn try_from(code: num::NonZero<i32>) -> Result<Self, Self::Error> {
107 if code.get() > 0 {
108 Ok(Self(code))
109 } else {
110 Err(kernel::Invalid {
111 actual: code.get() as libc::ssize_t,
112 minimum: 1,
113 maximum: i32::MAX as libc::ssize_t,
114 })
115 }
116 }
117}
118
119const _: () = {
120 assert!(mem::size_of::<Errno>() == mem::size_of::<i32>());
121 assert!(mem::size_of::<Option<Errno>>() == mem::size_of::<i32>());
122 assert!(mem::size_of::<Result<(), Errno>>() == mem::size_of::<i32>());
123};
124
125#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126#[repr(u8)]
127pub enum Cloexec {
128 Get(Errno),
129 Set(Errno),
130}
131
132impl fd::Flags for Cloexec {
133 const READ: libc::c_int = libc::F_GETFD;
134 const WRITE: libc::c_int = libc::F_SETFD;
135 const BIT: libc::c_int = libc::FD_CLOEXEC;
136}
137
138impl From<fd::Failure> for Cloexec {
139 fn from(error: fd::Failure) -> Self {
140 match error {
141 fd::Failure::Get(error) => Self::Get(error),
142 fd::Failure::Set(error) => Self::Set(error),
143 }
144 }
145}
146
147const _: () = {
148 assert!(mem::size_of::<Cloexec>() == 8);
149 assert!(mem::align_of::<Cloexec>() == mem::align_of::<Errno>());
150};
151
152#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153#[repr(u8)]
154pub enum Nonblock {
155 Get(Errno),
156 Set(Errno),
157}
158
159impl fd::Flags for Nonblock {
160 const READ: libc::c_int = libc::F_GETFL;
161 const WRITE: libc::c_int = libc::F_SETFL;
162 const BIT: libc::c_int = libc::O_NONBLOCK;
163}
164
165impl From<fd::Failure> for Nonblock {
166 fn from(error: fd::Failure) -> Self {
167 match error {
168 fd::Failure::Get(error) => Self::Get(error),
169 fd::Failure::Set(error) => Self::Set(error),
170 }
171 }
172}
173
174const _: () = {
175 assert!(mem::size_of::<Nonblock>() == 8);
176 assert!(mem::align_of::<Nonblock>() == mem::align_of::<Errno>());
177};
178
179pub trait Timer: Sized {
181 fn try_new(deadline: Positive) -> Result<Self, timer::Error>;
182 fn try_refresh(&self) -> Result<(), Errno>;
183 fn try_disarm(&self) -> Result<(), Errno>;
184}
185
186impl Timer for convert::Infallible {
187 fn try_new(deadline: Positive) -> Result<Self, timer::Error> {
188 Err(timer::Error::Unsupported { deadline })
189 }
190
191 fn try_refresh(&self) -> Result<(), Errno> {
192 match *self {}
193 }
194
195 fn try_disarm(&self) -> Result<(), Errno> {
196 match *self {}
197 }
198}
199
200pub mod probe;
201
202pub trait Buffer: Sized {
204 fn output(&mut self) -> buffer::raw::Output<'_>;
205 fn len(&self) -> usize;
206 fn is_empty(&self) -> bool {
207 self.len() == 0
208 }
209 fn recycle(self);
210}
211
212pub trait Budget {
214 fn remaining(&self) -> usize;
215 fn admit<T>(&mut self, acquire: impl FnOnce() -> Option<T>) -> quota::Admission<T>;
216}