use super::Errno;
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Syscall {
nr: u32,
}
impl Syscall {
#[inline(always)]
pub const fn from_u32(nr: u32) -> Syscall {
Syscall { nr }
}
}
impl From<u32> for Syscall {
#[inline(always)]
fn from(nr: u32) -> Syscall {
Syscall { nr }
}
}
impl From<Syscall> for u32 {
#[inline(always)]
fn from(syscall: Syscall) -> u32 {
syscall.nr
}
}
pub trait Check {
fn check(&self) -> core::result::Result<(), Errno>;
}
pub trait Result32: Check {
fn try_i32(&self) -> core::result::Result<i32, Errno>;
fn try_u32(&self) -> core::result::Result<u32, Errno>;
}
pub trait Result64: Check {
fn try_i64(&self) -> core::result::Result<i64, Errno>;
fn try_u64(&self) -> core::result::Result<u64, Errno>;
}
pub trait ResultPtr: Check {
fn try_ptr(&self) -> core::result::Result<*const (), Errno>;
fn try_ptr_mut(&self) -> core::result::Result<*mut (), Errno>;
}
pub trait ResultSize: Check {
fn try_isize(&self) -> core::result::Result<isize, Errno>;
fn try_usize(&self) -> core::result::Result<usize, Errno>;
}
macro_rules! single_register_result {
($arch_result:ty) => {
use super::Errno;
impl super::Check for $arch_result {
#[inline]
fn check(&self) -> core::result::Result<(), Errno> {
if self.0 >= self::MAX_ERRNO {
return Err(new_err(self.0 as i32));
}
Ok(())
}
}
#[inline(always)]
#[cold]
const fn new_err(truncated_register: i32) -> Errno {
let (err, _) = truncated_register.overflowing_neg();
unsafe { Errno::new_unchecked(err) }
}
impl super::ResultPtr for $arch_result {
#[inline]
fn try_ptr(&self) -> core::result::Result<*const (), Errno> {
super::Check::check(self)?;
Ok(self.0 as *const ())
}
#[inline]
fn try_ptr_mut(&self) -> core::result::Result<*mut (), Errno> {
super::Check::check(self)?;
Ok(self.0 as *mut ())
}
}
impl<T> core::convert::TryFrom<$arch_result> for *const T {
type Error = Errno;
#[inline]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::ResultPtr::try_ptr(&rc).map(|p| p.cast())
}
}
impl<T> core::convert::TryFrom<$arch_result> for *mut T {
type Error = Errno;
#[inline]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::ResultPtr::try_ptr_mut(&rc).map(|p| p.cast())
}
}
impl super::ResultSize for $arch_result {
#[inline]
fn try_isize(&self) -> core::result::Result<isize, Errno> {
super::Check::check(self)?;
Ok(self.0 as isize)
}
#[inline]
fn try_usize(&self) -> core::result::Result<usize, Errno> {
super::Check::check(self)?;
Ok(self.0 as usize)
}
}
impl core::convert::TryFrom<$arch_result> for isize {
type Error = Errno;
#[inline(always)]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::ResultSize::try_isize(&rc)
}
}
impl core::convert::TryFrom<$arch_result> for usize {
type Error = Errno;
#[inline(always)]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::ResultSize::try_usize(&rc)
}
}
};
}
#[cfg(any(target_pointer_width = "32", doc))]
macro_rules! single_register_result32 {
($arch_result:ty) => {
single_register_result!($arch_result);
const MAX_ERRNO: u32 = (-4095i32) as u32;
impl super::Result32 for $arch_result {
#[inline]
fn try_i32(&self) -> core::result::Result<i32, Errno> {
super::Check::check(self)?;
Ok(self.0 as i32)
}
#[inline]
fn try_u32(&self) -> core::result::Result<u32, Errno> {
super::Check::check(self)?;
Ok(self.0)
}
}
impl core::convert::TryFrom<$arch_result> for i32 {
type Error = Errno;
#[inline(always)]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::Result32::try_i32(&rc)
}
}
impl core::convert::TryFrom<$arch_result> for u32 {
type Error = Errno;
#[inline(always)]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::Result32::try_u32(&rc)
}
}
};
}
#[cfg(any(target_pointer_width = "64", doc))]
macro_rules! single_register_result64 {
($arch_result:ty) => {
single_register_result!($arch_result);
const MAX_ERRNO: u64 = (-4095i64) as u64;
impl super::Result64 for $arch_result {
#[inline]
fn try_i64(&self) -> core::result::Result<i64, Errno> {
super::Check::check(self)?;
Ok(self.0 as i64)
}
#[inline]
fn try_u64(&self) -> core::result::Result<u64, Errno> {
super::Check::check(self)?;
Ok(self.0)
}
}
impl core::convert::TryFrom<$arch_result> for i64 {
type Error = Errno;
#[inline(always)]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::Result64::try_i64(&rc)
}
}
impl core::convert::TryFrom<$arch_result> for u64 {
type Error = Errno;
#[inline(always)]
fn try_from(rc: $arch_result) -> core::result::Result<Self, Errno> {
super::Result64::try_u64(&rc)
}
}
};
}
macro_rules! syscall_constants {
( $( $name:ident = $value:literal , )+ ) => {
use super::Syscall;
$(
pub const $name: Syscall = Syscall::from_u32($value);
)*
};
}
#[cfg(target_arch = "arm")]
#[path = "syscall/arm.rs"]
mod arch;
#[cfg(target_arch = "aarch64")]
#[path = "syscall/aarch64.rs"]
mod arch;
#[cfg(target_arch = "riscv64")]
#[path = "syscall/riscv64.rs"]
mod arch;
#[cfg(target_arch = "x86")]
#[path = "syscall/x86.rs"]
mod arch;
#[cfg(target_arch = "x86_64")]
#[path = "syscall/x86_64.rs"]
mod arch;
pub use arch::*;