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
36 const fn fixed<const CODE: i32>() -> Self {
37 const { assert!(CODE > 0) };
38 Self(
39 num::NonZero::<u32>::MIN
40 .saturating_add(CODE as u32 - 1)
41 .cast_signed(),
42 )
43 }
44
45 pub const fn code(self) -> num::NonZero<i32> {
46 self.0
47 }
48
49 pub const fn is_intr(self) -> bool {
50 self.0.get() == libc::EINTR
51 }
52
53 pub const fn is_canceled(self) -> bool {
54 self.0.get() == libc::ECANCELED
55 }
56
57 pub const fn is_block(self) -> bool {
58 self.0.get() == libc::EAGAIN || self.0.get() == libc::EWOULDBLOCK
59 }
60
61 pub const fn is_refused(self) -> bool {
62 self.0.get() == libc::ECONNREFUSED
63 }
64
65 pub const fn is_pipe(self) -> bool {
66 self.0.get() == libc::EPIPE
67 }
68
69 pub const fn is_reset(self) -> bool {
70 self.0.get() == libc::ECONNRESET
71 }
72
73 pub const fn is_aborted(self) -> bool {
74 self.0.get() == libc::ECONNABORTED
75 }
76
77 pub const fn is_not_connected(self) -> bool {
78 self.0.get() == libc::ENOTCONN
79 }
80
81 pub const fn is_not_found(self) -> bool {
82 self.0.get() == libc::ENOENT || self.0.get() == libc::ENOTDIR
83 }
84}
85
86impl TryFrom<i32> for Errno {
87 type Error = kernel::Invalid;
88
89 fn try_from(raw: i32) -> Result<Self, Self::Error> {
90 match num::NonZero::new(raw) {
91 Some(code) => Self::try_from(code),
92 None => Err(kernel::Invalid {
93 actual: 0,
94 minimum: 1,
95 maximum: i32::MAX as libc::ssize_t,
96 }),
97 }
98 }
99}
100
101impl TryFrom<num::NonZero<i32>> for Errno {
102 type Error = kernel::Invalid;
103
104 fn try_from(code: num::NonZero<i32>) -> Result<Self, Self::Error> {
105 if code.get() > 0 {
106 Ok(Self(code))
107 } else {
108 Err(kernel::Invalid {
109 actual: code.get() as libc::ssize_t,
110 minimum: 1,
111 maximum: i32::MAX as libc::ssize_t,
112 })
113 }
114 }
115}
116
117const _: () = {
118 assert!(mem::size_of::<Errno>() == mem::size_of::<i32>());
119 assert!(mem::size_of::<Option<Errno>>() == mem::size_of::<i32>());
120 assert!(mem::size_of::<Result<(), Errno>>() == mem::size_of::<i32>());
121};
122
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124#[repr(u8)]
125pub enum Cloexec {
126 Get(Errno),
127 Set(Errno),
128}
129
130impl fd::Flags for Cloexec {
131 const READ: libc::c_int = libc::F_GETFD;
132 const WRITE: libc::c_int = libc::F_SETFD;
133 const BIT: libc::c_int = libc::FD_CLOEXEC;
134}
135
136impl From<fd::Failure> for Cloexec {
137 fn from(error: fd::Failure) -> Self {
138 match error {
139 fd::Failure::Get(error) => Self::Get(error),
140 fd::Failure::Set(error) => Self::Set(error),
141 }
142 }
143}
144
145const _: () = {
146 assert!(mem::size_of::<Cloexec>() == 8);
147 assert!(mem::align_of::<Cloexec>() == mem::align_of::<Errno>());
148};
149
150#[derive(Clone, Copy, Debug, PartialEq, Eq)]
151#[repr(u8)]
152pub enum Nonblock {
153 Get(Errno),
154 Set(Errno),
155}
156
157impl fd::Flags for Nonblock {
158 const READ: libc::c_int = libc::F_GETFL;
159 const WRITE: libc::c_int = libc::F_SETFL;
160 const BIT: libc::c_int = libc::O_NONBLOCK;
161}
162
163impl From<fd::Failure> for Nonblock {
164 fn from(error: fd::Failure) -> Self {
165 match error {
166 fd::Failure::Get(error) => Self::Get(error),
167 fd::Failure::Set(error) => Self::Set(error),
168 }
169 }
170}
171
172const _: () = {
173 assert!(mem::size_of::<Nonblock>() == 8);
174 assert!(mem::align_of::<Nonblock>() == mem::align_of::<Errno>());
175};
176
177pub trait Timer: Sized {
179 fn try_new(deadline: Positive) -> Result<Self, timer::Error>;
180 fn try_refresh(&self) -> Result<(), Errno>;
181 fn try_disarm(&self) -> Result<(), Errno>;
182}
183
184impl Timer for convert::Infallible {
185 fn try_new(deadline: Positive) -> Result<Self, timer::Error> {
186 Err(timer::Error::Unsupported { deadline })
187 }
188
189 fn try_refresh(&self) -> Result<(), Errno> {
190 match *self {}
191 }
192
193 fn try_disarm(&self) -> Result<(), Errno> {
194 match *self {}
195 }
196}
197
198pub mod probe;
199
200pub trait Buffer: Sized {
202 fn output(&mut self) -> buffer::raw::Output<'_>;
203 fn len(&self) -> usize;
204 fn is_empty(&self) -> bool {
205 self.len() == 0
206 }
207 fn recycle(self);
208}
209
210pub trait Budget {
212 fn remaining(&self) -> usize;
213 fn admit<T>(&mut self, acquire: impl FnOnce() -> Option<T>) -> quota::Admission<T>;
214}