heveanly 0.1.0

C is the heavenly option
Documentation
// The code in this file is derived from rust-linux-syscall by John Millikin.
// The original copyright notice has been retained below.

// Copyright (c) 2022 John Millikin <john@john-millikin.com>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
//
// SPDX-License-Identifier: 0BSD

/*
//! This library defines syscall numbers and a [`syscall!`] macro for directly
//! invoking Linux system calls.
//!
//! The [`arch`] modules document available syscall numbers for all supported
//! architectures, and the top-level module re-exports syscall numbers for the
//! current target platform.
//!
//! Syscall results may be inspected with the [`Result*` traits](#traits).
//!
//! # Example
//!
//! ```
//! # #[macro_use] extern crate linux_syscall;
//! # use linux_syscall::*;
//! # fn main() -> core::result::Result<(), linux_errno::Error> {
//! let stdout: i32 = 1;
//! let hello = "Hello, world!\n\0";
//! let rc = unsafe {
//! 	syscall!(SYS_write, stdout, hello.as_ptr(), hello.len())
//! };
//! rc.check()?;
//! # Ok(())
//! # }
//! ```
//!
//! # Safety
//!
//! Very unsafe.
//!
//! Linux syscalls are low-level primitives that operate without any notion
//! of borrow checking or type safety. It is the caller's responsibility to
//! ensure parameters have types, values, and lifetimes appropriate to the
//! syscall being invoked.
//!
//! * The kernel cannot distinguish `*const T` and `*mut T`.
//! * Many syscalls accept complex parameters as pointers to a `struct`. The
//!   caller must ensure such parameters have appropriate layout and alignment.
//! * Syscalls vary between architectures. The same syscall name may have
//!   a completely different signature even on similar targets, for example
//!   `SYS_mmap` on `x86` and `x86_64`.
*/

use super::Errno;

/*
/// An architecture-specific syscall number.
*/
#[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
	}
}

/*
/// Check whether a syscall succeeded or failed.
*/
pub trait Check {
	fn check(&self) -> core::result::Result<(), Errno>;
}

/*
/// Interpret a syscall result as a 32-bit integer.
*/
pub trait Result32: Check {
	fn try_i32(&self) -> core::result::Result<i32, Errno>;

	fn try_u32(&self) -> core::result::Result<u32, Errno>;
}

/*
/// Interpret a syscall result as a 64-bit integer.
*/
pub trait Result64: Check {
	fn try_i64(&self) -> core::result::Result<i64, Errno>;

	fn try_u64(&self) -> core::result::Result<u64, Errno>;
}

/*
/// Interpret a syscall result as a pointer.
*/
pub trait ResultPtr: Check {
	fn try_ptr(&self) -> core::result::Result<*const (), Errno>;

	fn try_ptr_mut(&self) -> core::result::Result<*mut (), Errno>;
}

/*
/// Interpret a syscall result as a pointer-sized integer.
*/
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::*;

/*
/// Invokes a Linux syscall.
///
/// `$syscall` must be a value that implements [`Into<Syscall>`](Syscall).
/// Other arguments must be valid [`asm!`](core::arch::asm!) input operands,
/// such as integers or pointers.
///
/// The returned value is an architecture-specific implementation of [`Result`].
///
/// Additional traits implemented by syscall results vary by architecture.
/// For all architectures currently supported by this library:
///
/// * The [`ResultSize`] and [`ResultPtr`] traits are implemented.
/// * One of the [`Result32`] or [`Result64`] traits is implemented, according
///   to the native word size.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate linux_syscall;
/// # use linux_syscall::*;
/// # fn main() -> core::result::Result<(), linux_errno::Error> {
/// let stdout: i32 = 1;
/// let hello = "Hello, world!\n\0";
/// let rc = unsafe {
/// 	syscall!(SYS_write, stdout, hello.as_ptr(), hello.len())
/// };
/// rc.check()?;
/// # Ok(())
/// # }
/// ```
///
/// # Safety
///
/// Very unsafe. See the [module documentation](self) for details.
#[cfg(doc)]
#[macro_export]
macro_rules! syscall {
	($syscall:expr $(,)?) => {};
	($syscall:expr, $a1:expr $(,)?) => {};
	($syscall:expr, $a1:expr, $a2:expr $(,)?) => {};
	($syscall:expr, $a1:expr, $a2:expr, $a3:expr $(,)?) => {};
	($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr $(,)?) => {};
	($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr $(,)?) => {};
	($syscall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr $(,)?) => {};
}
*/