Skip to main content

dope_sys/
lib.rs

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/// A positive operating-system error number.
17#[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
179/// Creation and operations on a live kernel deadline.
180pub 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
202/// A native receive lease retained until its exact completed prefix is released.
203pub 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
212/// A borrowed scheduler budget; unsuccessful acquisition spends no quota.
213pub trait Budget {
214    fn remaining(&self) -> usize;
215    fn admit<T>(&mut self, acquire: impl FnOnce() -> Option<T>) -> quota::Admission<T>;
216}