use crate::system::Errno;
#[cfg(doc)]
use crate::system::Signals;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::ffi::c_int;
use std::num::NonZero;
use std::str::FromStr;
use strum::{EnumIter, IntoEnumIterator};
use thiserror::Error;
pub type RawNumber = c_int;
#[derive(Clone, Copy, Debug, EnumIter, Eq, Hash, PartialEq)]
#[non_exhaustive]
pub enum Name {
Abrt,
Alrm,
Bus,
Chld,
Cld,
Cont,
Emt,
Fpe,
Hup,
Ill,
Info,
Int,
Io,
Iot,
Kill,
Lost,
Pipe,
Poll,
Prof,
Pwr,
Quit,
Segv,
Stkflt,
Stop,
Sys,
Term,
Thr,
Trap,
Tstp,
Ttin,
Ttou,
Urg,
Usr1,
Usr2,
Vtalrm,
Winch,
Xcpu,
Xfsz,
Rtmin(RawNumber),
Rtmax(RawNumber),
}
impl PartialOrd for Name {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(Self::Rtmin(a), Self::Rtmin(b)) | (Self::Rtmax(a), Self::Rtmax(b)) => a.partial_cmp(b),
_ => None,
}
}
}
impl Name {
#[inline(always)]
pub fn iter() -> NameIter {
<Self as IntoEnumIterator>::iter()
}
#[must_use]
pub fn as_string(&self) -> Cow<'static, str> {
match *self {
Self::Abrt => Cow::Borrowed("ABRT"),
Self::Alrm => Cow::Borrowed("ALRM"),
Self::Bus => Cow::Borrowed("BUS"),
Self::Chld => Cow::Borrowed("CHLD"),
Self::Cld => Cow::Borrowed("CLD"),
Self::Cont => Cow::Borrowed("CONT"),
Self::Emt => Cow::Borrowed("EMT"),
Self::Fpe => Cow::Borrowed("FPE"),
Self::Hup => Cow::Borrowed("HUP"),
Self::Ill => Cow::Borrowed("ILL"),
Self::Info => Cow::Borrowed("INFO"),
Self::Int => Cow::Borrowed("INT"),
Self::Io => Cow::Borrowed("IO"),
Self::Iot => Cow::Borrowed("IOT"),
Self::Kill => Cow::Borrowed("KILL"),
Self::Lost => Cow::Borrowed("LOST"),
Self::Pipe => Cow::Borrowed("PIPE"),
Self::Poll => Cow::Borrowed("POLL"),
Self::Prof => Cow::Borrowed("PROF"),
Self::Pwr => Cow::Borrowed("PWR"),
Self::Quit => Cow::Borrowed("QUIT"),
Self::Segv => Cow::Borrowed("SEGV"),
Self::Stkflt => Cow::Borrowed("STKFLT"),
Self::Stop => Cow::Borrowed("STOP"),
Self::Sys => Cow::Borrowed("SYS"),
Self::Term => Cow::Borrowed("TERM"),
Self::Thr => Cow::Borrowed("THR"),
Self::Trap => Cow::Borrowed("TRAP"),
Self::Tstp => Cow::Borrowed("TSTP"),
Self::Ttin => Cow::Borrowed("TTIN"),
Self::Ttou => Cow::Borrowed("TTOU"),
Self::Urg => Cow::Borrowed("URG"),
Self::Usr1 => Cow::Borrowed("USR1"),
Self::Usr2 => Cow::Borrowed("USR2"),
Self::Vtalrm => Cow::Borrowed("VTALRM"),
Self::Winch => Cow::Borrowed("WINCH"),
Self::Xcpu => Cow::Borrowed("XCPU"),
Self::Xfsz => Cow::Borrowed("XFSZ"),
Self::Rtmin(0) => Cow::Borrowed("RTMIN"),
Self::Rtmax(0) => Cow::Borrowed("RTMAX"),
Self::Rtmin(n) => Cow::Owned(format!("RTMIN{n:+}")),
Self::Rtmax(n) => Cow::Owned(format!("RTMAX{n:+}")),
}
}
}
impl std::fmt::Display for Name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_string().fmt(f)
}
}
#[test]
fn test_name_to_string() {
assert_eq!(Name::Term.to_string(), "TERM");
assert_eq!(Name::Int.to_string(), "INT");
assert_eq!(Name::Rtmin(0).to_string(), "RTMIN");
assert_eq!(Name::Rtmax(0).to_string(), "RTMAX");
assert_eq!(Name::Rtmin(1).to_string(), "RTMIN+1");
assert_eq!(Name::Rtmin(20).to_string(), "RTMIN+20");
assert_eq!(Name::Rtmax(-1).to_string(), "RTMAX-1");
assert_eq!(Name::Rtmax(-20).to_string(), "RTMAX-20");
}
#[derive(Clone, Debug, Eq, Error, Hash, PartialEq)]
pub struct UnknownNameError;
impl std::fmt::Display for UnknownNameError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("unknown signal name")
}
}
impl From<UnknownNameError> for Errno {
#[inline]
fn from(UnknownNameError: UnknownNameError) -> Self {
Errno::EINVAL
}
}
impl FromStr for Name {
type Err = UnknownNameError;
fn from_str(s: &str) -> Result<Self, UnknownNameError> {
match s {
"ABRT" => Ok(Self::Abrt),
"ALRM" => Ok(Self::Alrm),
"BUS" => Ok(Self::Bus),
"CHLD" => Ok(Self::Chld),
"CLD" => Ok(Self::Cld),
"CONT" => Ok(Self::Cont),
"EMT" => Ok(Self::Emt),
"FPE" => Ok(Self::Fpe),
"HUP" => Ok(Self::Hup),
"ILL" => Ok(Self::Ill),
"INFO" => Ok(Self::Info),
"INT" => Ok(Self::Int),
"IO" => Ok(Self::Io),
"IOT" => Ok(Self::Iot),
"KILL" => Ok(Self::Kill),
"LOST" => Ok(Self::Lost),
"PIPE" => Ok(Self::Pipe),
"POLL" => Ok(Self::Poll),
"PROF" => Ok(Self::Prof),
"PWR" => Ok(Self::Pwr),
"QUIT" => Ok(Self::Quit),
"SEGV" => Ok(Self::Segv),
"STKFLT" => Ok(Self::Stkflt),
"STOP" => Ok(Self::Stop),
"SYS" => Ok(Self::Sys),
"TERM" => Ok(Self::Term),
"THR" => Ok(Self::Thr),
"TRAP" => Ok(Self::Trap),
"TSTP" => Ok(Self::Tstp),
"TTIN" => Ok(Self::Ttin),
"TTOU" => Ok(Self::Ttou),
"URG" => Ok(Self::Urg),
"USR1" => Ok(Self::Usr1),
"USR2" => Ok(Self::Usr2),
"VTALRM" => Ok(Self::Vtalrm),
"WINCH" => Ok(Self::Winch),
"XCPU" => Ok(Self::Xcpu),
"XFSZ" => Ok(Self::Xfsz),
"RTMIN" => Ok(Self::Rtmin(0)),
"RTMAX" => Ok(Self::Rtmax(0)),
_ => {
if let Some(tail) = s.strip_prefix("RTMIN") {
if tail.starts_with(['+', '-']) {
if let Ok(n) = tail.parse() {
return Ok(Self::Rtmin(n));
}
}
}
if let Some(tail) = s.strip_prefix("RTMAX") {
if tail.starts_with(['+', '-']) {
if let Ok(n) = tail.parse() {
return Ok(Self::Rtmax(n));
}
}
}
Err(UnknownNameError)
}
}
}
}
#[test]
fn test_name_from_str() {
assert_eq!("ABRT".parse(), Ok(Name::Abrt));
assert_eq!("INT".parse(), Ok(Name::Int));
assert_eq!("QUIT".parse(), Ok(Name::Quit));
assert_eq!("RTMIN".parse(), Ok(Name::Rtmin(0)));
assert_eq!("RTMIN+0".parse(), Ok(Name::Rtmin(0)));
assert_eq!("RTMIN+1".parse(), Ok(Name::Rtmin(1)));
assert_eq!("RTMAX".parse(), Ok(Name::Rtmax(0)));
assert_eq!("RTMAX-0".parse(), Ok(Name::Rtmax(0)));
assert_eq!("RTMAX-1".parse(), Ok(Name::Rtmax(-1)));
assert_eq!("".parse::<Name>(), Err(UnknownNameError));
assert_eq!("FOO".parse::<Name>(), Err(UnknownNameError));
assert_eq!("int".parse::<Name>(), Err(UnknownNameError));
assert_eq!("RTMIN0".parse::<Name>(), Err(UnknownNameError));
assert_eq!("RTMIN+".parse::<Name>(), Err(UnknownNameError));
assert_eq!("RTMAX0".parse::<Name>(), Err(UnknownNameError));
assert_eq!("RTMAX-".parse::<Name>(), Err(UnknownNameError));
assert_eq!("2".parse::<Name>(), Err(UnknownNameError));
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
#[repr(transparent)]
pub struct Number(NonZero<RawNumber>);
impl Number {
#[inline(always)]
#[must_use]
pub const fn as_raw(self) -> RawNumber {
self.0.get()
}
#[inline(always)]
#[must_use]
pub const fn as_raw_non_zero(self) -> NonZero<RawNumber> {
self.0
}
#[inline(always)]
#[must_use]
pub const fn from_raw_unchecked(raw: NonZero<RawNumber>) -> Self {
Self(raw)
}
}
impl From<Number> for NonZero<RawNumber> {
#[inline(always)]
fn from(number: Number) -> Self {
number.0
}
}
impl From<Number> for RawNumber {
#[inline(always)]
fn from(number: Number) -> Self {
number.0.get()
}
}
impl std::fmt::Display for Number {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Binary for Number {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Octal for Number {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::LowerHex for Number {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::UpperHex for Number {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}