Skip to main content

dope_sys/
lib.rs

1use std::{convert, io::Error, 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
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_not_found(self) -> bool {
70        self.0.get() == libc::ENOENT || self.0.get() == libc::ENOTDIR
71    }
72}
73
74impl TryFrom<i32> for Errno {
75    type Error = kernel::Invalid;
76
77    fn try_from(raw: i32) -> Result<Self, Self::Error> {
78        match num::NonZero::new(raw) {
79            Some(code) => Self::try_from(code),
80            None => Err(kernel::Invalid {
81                actual: 0,
82                minimum: 1,
83                maximum: i32::MAX as libc::ssize_t,
84            }),
85        }
86    }
87}
88
89impl TryFrom<num::NonZero<i32>> for Errno {
90    type Error = kernel::Invalid;
91
92    fn try_from(code: num::NonZero<i32>) -> Result<Self, Self::Error> {
93        if code.get() > 0 {
94            Ok(Self(code))
95        } else {
96            Err(kernel::Invalid {
97                actual: code.get() as libc::ssize_t,
98                minimum: 1,
99                maximum: i32::MAX as libc::ssize_t,
100            })
101        }
102    }
103}
104
105impl TryFrom<Error> for Errno {
106    type Error = Error;
107
108    fn try_from(error: Self::Error) -> Result<Self, Self::Error> {
109        match error.raw_os_error() {
110            Some(raw) => Self::try_from(raw).map_err(|_| error),
111            None => Err(error),
112        }
113    }
114}
115
116impl From<Errno> for Error {
117    fn from(error: Errno) -> Self {
118        Self::from_raw_os_error(error.code().get())
119    }
120}
121
122const _: () = {
123    assert!(mem::size_of::<Errno>() == mem::size_of::<i32>());
124    assert!(mem::size_of::<Option<Errno>>() == mem::size_of::<i32>());
125    assert!(mem::size_of::<Result<(), Errno>>() == mem::size_of::<i32>());
126};
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129#[repr(u8)]
130pub enum Cloexec {
131    Get(Errno),
132    Set(Errno),
133}
134
135impl fd::Flags for Cloexec {
136    const READ: libc::c_int = libc::F_GETFD;
137    const WRITE: libc::c_int = libc::F_SETFD;
138    const BIT: libc::c_int = libc::FD_CLOEXEC;
139}
140
141impl From<fd::Failure> for Cloexec {
142    fn from(error: fd::Failure) -> Self {
143        match error {
144            fd::Failure::Get(error) => Self::Get(error),
145            fd::Failure::Set(error) => Self::Set(error),
146        }
147    }
148}
149
150const _: () = {
151    assert!(mem::size_of::<Cloexec>() == 8);
152    assert!(mem::align_of::<Cloexec>() == mem::align_of::<Errno>());
153};
154
155#[derive(Clone, Copy, Debug, PartialEq, Eq)]
156#[repr(u8)]
157pub enum Nonblock {
158    Get(Errno),
159    Set(Errno),
160}
161
162impl fd::Flags for Nonblock {
163    const READ: libc::c_int = libc::F_GETFL;
164    const WRITE: libc::c_int = libc::F_SETFL;
165    const BIT: libc::c_int = libc::O_NONBLOCK;
166}
167
168impl From<fd::Failure> for Nonblock {
169    fn from(error: fd::Failure) -> Self {
170        match error {
171            fd::Failure::Get(error) => Self::Get(error),
172            fd::Failure::Set(error) => Self::Set(error),
173        }
174    }
175}
176
177const _: () = {
178    assert!(mem::size_of::<Nonblock>() == 8);
179    assert!(mem::align_of::<Nonblock>() == mem::align_of::<Errno>());
180};
181
182/// Creation and operations on a live kernel deadline.
183pub trait Timer: Sized {
184    fn try_new(deadline: Positive) -> Result<Self, timer::Error>;
185    fn try_refresh(&self) -> Result<(), Errno>;
186    fn try_disarm(&self) -> Result<(), Errno>;
187}
188
189impl Timer for convert::Infallible {
190    fn try_new(deadline: Positive) -> Result<Self, timer::Error> {
191        Err(timer::Error::Unsupported { deadline })
192    }
193
194    fn try_refresh(&self) -> Result<(), Errno> {
195        match *self {}
196    }
197
198    fn try_disarm(&self) -> Result<(), Errno> {
199        match *self {}
200    }
201}
202
203pub mod probe;
204
205/// A native receive lease retained until its exact completed prefix is released.
206pub trait Buffer: Sized {
207    fn output(&mut self) -> buffer::raw::Output<'_>;
208    fn len(&self) -> usize;
209    fn is_empty(&self) -> bool {
210        self.len() == 0
211    }
212    fn recycle(self);
213}
214
215/// A borrowed scheduler budget; unsuccessful acquisition spends no quota.
216pub trait Budget {
217    fn remaining(&self) -> usize;
218    fn admit<T>(&mut self, acquire: impl FnOnce() -> Option<T>) -> quota::Admission<T>;
219}