use core::cmp::Ordering;
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, thiserror::Error)]
#[error("invalid aux var type: {0}")]
pub struct ParseAuxVarTypeError(usize);
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(usize)]
pub enum AuxVarType {
Null = 0,
Ignore = 1,
ExecFd = 2,
Phdr = 3,
Phent = 4,
Phnum = 5,
Pagesz = 6,
Base = 7,
Flags = 8,
Entry = 9,
NotElf = 10,
Uid = 11,
EUid = 12,
Gid = 13,
EGid = 14,
Platform = 15,
HwCap = 16,
Clktck = 17,
Secure = 23,
BasePlatform = 24,
Random = 25,
HwCap2 = 26,
ExecFn = 31,
Sysinfo = 32,
SysinfoEhdr = 33,
L1iCacheSize = 40,
L1iCacheGeometry = 41,
L1dCacheSize = 42,
L1dCacheGeometry = 43,
L2CacheSize = 44,
L2CacheGeometry = 45,
L3CacheSize = 46,
L3CacheGeometry = 47,
MinSigStkSz = 51,
}
impl AuxVarType {
#[must_use]
pub const fn variants() -> &'static [Self] {
&[
Self::Null,
Self::Ignore,
Self::ExecFd,
Self::Phdr,
Self::Phent,
Self::Phnum,
Self::Pagesz,
Self::Base,
Self::Flags,
Self::Entry,
Self::NotElf,
Self::Uid,
Self::EUid,
Self::Gid,
Self::EGid,
Self::Platform,
Self::HwCap,
Self::Clktck,
Self::Secure,
Self::BasePlatform,
Self::Random,
Self::HwCap2,
Self::ExecFn,
Self::Sysinfo,
Self::SysinfoEhdr,
Self::L1iCacheSize,
Self::L1iCacheGeometry,
Self::L1dCacheSize,
Self::L1dCacheGeometry,
Self::L2CacheSize,
Self::L2CacheGeometry,
Self::L3CacheSize,
Self::L3CacheGeometry,
Self::MinSigStkSz,
]
}
#[must_use]
pub const fn val(self) -> usize {
self as _
}
#[must_use]
pub const fn value_in_data_area(self) -> bool {
match self {
Self::Null => false,
Self::Ignore => false,
Self::ExecFd => false,
Self::Phdr => false,
Self::Phent => false,
Self::Phnum => false,
Self::Pagesz => false,
Self::Base => false,
Self::Flags => false,
Self::Entry => false,
Self::NotElf => false,
Self::Uid => false,
Self::EUid => false,
Self::Gid => false,
Self::EGid => false,
Self::Platform => true,
Self::HwCap => false,
Self::Clktck => false,
Self::Secure => false,
Self::BasePlatform => true,
Self::Random => true,
Self::HwCap2 => false,
Self::ExecFn => true,
Self::SysinfoEhdr => false,
Self::Sysinfo => false,
Self::L1iCacheSize => false,
Self::L1iCacheGeometry => false,
Self::L1dCacheSize => false,
Self::L1dCacheGeometry => false,
Self::L2CacheSize => false,
Self::L2CacheGeometry => false,
Self::L3CacheSize => false,
Self::L3CacheGeometry => false,
Self::MinSigStkSz => false,
}
}
#[must_use]
pub fn value_is_cstr(self) -> bool {
self.value_in_data_area()
&& [Self::Platform, Self::BasePlatform, Self::ExecFn].contains(&self)
}
#[must_use]
pub const fn data_area_val_size_hint(self) -> Option<usize> {
match self {
Self::Random => Some(16),
_ => None,
}
}
}
impl From<AuxVarType> for usize {
fn from(value: AuxVarType) -> Self {
value.val()
}
}
impl TryFrom<usize> for AuxVarType {
type Error = ParseAuxVarTypeError;
fn try_from(value: usize) -> Result<Self, Self::Error> {
for variant in Self::variants() {
if variant.val() == value {
return Ok(*variant);
}
}
Err(ParseAuxVarTypeError(value))
}
}
impl PartialOrd for AuxVarType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AuxVarType {
fn cmp(&self, other: &Self) -> Ordering {
if matches!(self, Self::Null) && !matches!(other, Self::Null) {
Ordering::Greater
} else {
self.val().cmp(&other.val())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn test_variants_are_sorted() {
let mut variants = AuxVarType::variants().to_vec();
variants.sort();
assert_eq!(AuxVarType::variants(), variants.as_slice());
}
#[test]
fn test_aux_var_key_order() {
let mut set = BTreeSet::new();
set.insert(AuxVarType::ExecFn);
set.insert(AuxVarType::Platform);
set.insert(AuxVarType::Null);
set.insert(AuxVarType::Clktck);
set.insert(AuxVarType::ExecFn);
assert_eq!(set.last(), Some(&AuxVarType::Null));
}
}