1use std::convert::Infallible;
2use std::fmt::{self, Debug, Display};
3use std::str::{self, FromStr};
4
5#[cfg(feature = "serde")]
6use serde_with::{DeserializeFromStr, SerializeDisplay};
7
8#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
10#[repr(usize)]
11pub enum Common {
12 Arch,
13 Argc,
14 CapFe,
15 CapFi,
16 CapFp,
17 CapFver,
18 Comm,
19 Cwd,
20 Dev,
21 Exe,
22 Exit,
23 Inode,
24 Item,
25 Items,
26 Key,
27 Mode,
28 Msg,
29 Name,
30 Nametype,
31 Pid,
32 PPid,
33 Ses,
34 Subj,
35 Success,
36 Syscall,
37 Tty,
38}
39
40const COMMON: &[(&str, Common)] = &[
41 ("arch", Common::Arch),
42 ("argc", Common::Argc),
43 ("cap_fe", Common::CapFe),
44 ("cap_fi", Common::CapFi),
45 ("cap_fp", Common::CapFp),
46 ("cap_fver", Common::CapFver),
47 ("comm", Common::Comm),
48 ("cwd", Common::Cwd),
49 ("dev", Common::Dev),
50 ("exe", Common::Exe),
51 ("exit", Common::Exit),
52 ("inode", Common::Inode),
53 ("item", Common::Item),
54 ("items", Common::Items),
55 ("key", Common::Key),
56 ("mode", Common::Mode),
57 ("msg", Common::Msg),
58 ("name", Common::Name),
59 ("nametype", Common::Nametype),
60 ("pid", Common::Pid),
61 ("ppid", Common::PPid),
62 ("ses", Common::Ses),
63 ("subj", Common::Subj),
64 ("success", Common::Success),
65 ("syscall", Common::Syscall),
66 ("tty", Common::Tty),
67];
68
69impl TryFrom<&[u8]> for Common {
70 type Error = &'static str;
71 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
72 let i = COMMON
73 .binary_search_by_key(&value, |(s, _)| s.as_bytes())
74 .map_err(|_| "unknown key")?;
75 Ok(COMMON[i].1)
76 }
77}
78
79impl From<Common> for &'static str {
80 fn from(value: Common) -> Self {
81 COMMON[value as usize].0
82 }
83}
84
85impl Display for Common {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 let c = COMMON[*self as usize].0;
88 write!(f, "{c}")
89 }
90}
91
92pub(crate) type NVec = tinyvec::TinyVec<[u8; 14]>;
93
94#[derive(PartialEq, Eq, Clone)]
98#[cfg_attr(feature = "serde", derive(SerializeDisplay, DeserializeFromStr))]
99pub enum Key {
100 Name(NVec),
102 NameUID(NVec),
104 NameGID(NVec),
106 Common(Common),
108 NameTranslated(NVec),
111 Arg(u32, Option<u16>),
114 ArgLen(u32),
116 Literal(&'static str),
118}
119
120impl Default for Key {
121 fn default() -> Self {
122 Key::Literal("no_key")
123 }
124}
125
126impl Debug for Key {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.write_str(&self.to_string())
129 }
130}
131
132impl Display for Key {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 match self {
135 Key::Arg(x, Some(y)) => write!(f, "a{x}[{y}]"),
136 Key::Arg(x, None) => write!(f, "a{x}"),
137 Key::ArgLen(x) => write!(f, "a{x}_len"),
138 Key::Name(r) | Key::NameUID(r) | Key::NameGID(r) => {
139 let s = unsafe { str::from_utf8_unchecked(r) };
141 f.write_str(s)
142 }
143 Key::Common(c) => write!(f, "{c}"),
144 Key::NameTranslated(r) => {
145 let s = unsafe { str::from_utf8_unchecked(r) };
147 f.write_str(&str::to_ascii_uppercase(s))
148 }
149 Key::Literal(s) => f.write_str(s),
150 }
151 }
152}
153
154fn try_parse_a(s: &str) -> Option<Key> {
155 match s.strip_prefix("a") {
156 Some(s) => {
157 if let Some(s) = s.strip_suffix("]") {
158 let (x, y) = s.split_once("[")?;
159 Some(Key::Arg(
160 u32::from_str(x).ok()?,
161 Some(u16::from_str(y).ok()?),
162 ))
163 } else if let Some(s) = s.strip_suffix("_len") {
164 Some(Key::ArgLen(u32::from_str(s).ok()?))
165 } else {
166 Some(Key::Arg(u32::from_str(s).ok()?, None))
167 }
168 }
169 _ => None,
170 }
171}
172
173impl FromStr for Key {
174 type Err = Infallible;
175
176 fn from_str(s: &str) -> Result<Self, Self::Err> {
177 if let Ok(c) = Common::try_from(s.as_bytes()) {
178 Ok(Key::Common(c))
179 } else if let Some(k) = try_parse_a(s) {
180 Ok(k)
181 } else if s.ends_with("uid") {
182 Ok(Key::NameUID(s.as_bytes().into()))
183 } else if s.ends_with("gid") {
184 Ok(Key::NameGID(s.as_bytes().into()))
185 } else {
186 Ok(Key::from(s.as_bytes()))
187 }
188 }
189}
190
191impl PartialEq<str> for Key {
192 fn eq(&self, other: &str) -> bool {
193 self == other.as_bytes()
194 }
195}
196
197impl PartialEq<[u8]> for Key {
198 fn eq(&self, other: &[u8]) -> bool {
199 match self {
200 Key::Name(r) | Key::NameUID(r) | Key::NameGID(r) => r.as_ref() == other,
201 _ => self.to_string().as_bytes() == other,
202 }
203 }
204}
205
206impl From<&'static str> for Key {
207 fn from(value: &'static str) -> Self {
208 Self::Literal(value)
209 }
210}
211
212impl From<&[u8]> for Key {
213 fn from(value: &[u8]) -> Self {
214 Self::Name(NVec::from(value))
215 }
216}