1#![deny(unsafe_code)]
2
3use std::error::Error;
4use std::fmt;
5use std::io;
6use std::str::FromStr;
7
8#[cfg(all(target_os = "linux", target_env = "gnu"))]
9use libc::__rlimit_resource_t as resource_t;
10
11#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
12use libc::c_int as resource_t;
13
14#[allow(clippy::module_name_repetitions)]
20pub type RawResource = resource_t;
21
22#[allow(clippy::doc_markdown)]
37#[derive(Clone, Copy, PartialEq, Eq, Hash)]
38pub struct Resource {
39 tag: u16,
40 value: u16,
41}
42
43impl fmt::Debug for Resource {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 let idx = Self::VALUE_TABLE.iter().position(|v| v == self).unwrap();
46 write!(f, "Resource::{}", Self::IDENT_TABLE[idx])
47 }
48}
49
50impl FromStr for Resource {
51 type Err = ParseResourceError;
52
53 fn from_str(s: &str) -> Result<Self, Self::Err> {
54 let pos = Self::NAME_TABLE.iter().position(|&name| s == name);
55 match pos {
56 Some(idx) => Ok(Self::VALUE_TABLE[idx]),
57 None => Err(ParseResourceError { _priv: () }),
58 }
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct ParseResourceError {
65 _priv: (),
67}
68
69impl fmt::Display for ParseResourceError {
70 #[inline]
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 write!(f, "failed to parse Resource")
73 }
74}
75
76impl Error for ParseResourceError {}
77
78macro_rules! declare_resource {
79 {$($(#[$attr:meta])* $id:ident = $tag:expr => $c_enum:ident,)+} => {
80 impl Resource{
81 $(
82 $(#[$attr])*
83 pub const $id: Self = Self{ tag: $tag, value: libc::$c_enum as u16 };
84 )+
85 }
86
87 #[allow(unused_doc_comments)]
88 impl Resource{
89 const NAME_TABLE: &'static [&'static str] = &[
90 $(
91 $(#[$attr])*
92 {
93 stringify!($c_enum)
94 },
95 )+
96 ];
97
98 const VALUE_TABLE: &'static [Self] = &[
99 $(
100 $(#[$attr])*
101 {
102 Self::$id
103 },
104 )+
105 ];
106
107 const IDENT_TABLE: &'static [&'static str] = &[
108 $(
109 $(#[$attr])*
110 {
111 stringify!($id)
112 },
113 )+
114 ];
115 }
116
117 #[cfg(test)]
118 mod tests{
119 use super::*;
120
121 #[allow(unused_comparisons)]
122 #[allow(unused_doc_comments)]
123 #[test]
124 fn name_value(){
125 $(
126 $(#[$attr])*
127 {
128 assert_eq!(Resource::$id.as_name(), stringify!($c_enum));
129 assert_eq!(Resource::from_str(stringify!($c_enum)).unwrap(), Resource::$id);
130 assert!((0..=128).contains(&libc::$c_enum));
131 }
132 )+
133 }
134
135 #[allow(unused_doc_comments)]
136 #[test]
137 fn unique_tag(){
138 use std::collections::HashSet;
139
140 let tags = [
141 $(
142 $(#[$attr])*
143 { $tag },
144 )+
145 ];
146
147 let s: HashSet<u16> = tags.iter().copied().collect();
148 assert_eq!(s.len(), Resource::NAME_TABLE.len());
149 }
150
151 #[allow(unused_doc_comments)]
152 #[test]
153 fn raw_eq(){
154 $(
155 $(#[$attr])*
156 {
157 assert_eq!(Resource::$id.as_raw(), libc::$c_enum);
158 }
159 )+
160 }
161
162 #[allow(unused_doc_comments)]
163 #[test]
164 fn from_str(){
165 $(
166 $(#[$attr])*
167 {
168 assert_eq!(Resource::from_str(stringify!($c_enum)), Ok(Resource::$id));
169 }
170 )+
171
172 assert!(Resource::from_str("asdqwe").is_err());
173 }
174
175 #[test]
176 fn available(){
177 assert_eq!(
178 Resource::available_names().len(),
179 Resource::available_resources().len()
180 );
181 }
182 }
183 };
184}
185
186impl Resource {
187 #[inline]
191 pub fn set(self, soft: u64, hard: u64) -> io::Result<()> {
192 super::setrlimit(self, soft, hard)
193 }
194
195 #[inline]
199 pub fn get(self) -> io::Result<(u64, u64)> {
200 super::getrlimit(self)
201 }
202
203 #[must_use]
211 #[allow(clippy::missing_panics_doc)] pub fn as_name(self) -> &'static str {
213 let idx = Self::VALUE_TABLE.iter().position(|&v| v == self).unwrap();
214 Self::NAME_TABLE[idx]
215 }
216
217 #[must_use]
219 pub const fn available_names() -> &'static [&'static str] {
220 Self::NAME_TABLE
221 }
222
223 #[must_use]
225 pub const fn available_resources() -> &'static [Self] {
226 Self::VALUE_TABLE
227 }
228
229 #[inline]
235 #[must_use]
236 pub const fn as_raw(self) -> RawResource {
237 self.value as _
238 }
239}
240
241declare_resource! {
244
245 #[cfg(any(
248 all(target_os = "linux", target_env = "gnu"),
249 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
250 all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
251 all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
252 any(target_os = "freebsd", target_os = "dragonfly"),
253 any(target_os = "macos", target_os = "ios"),
254 target_os = "android",
255 target_os = "emscripten",
256 target_os = "fuchsia",
257 target_os = "haiku",
258 target_os = "netbsd",
259 target_os = "solarish",
260 ))]
261 AS = 1 => RLIMIT_AS,
262
263
264 #[cfg(any(
267 all(target_os = "linux", target_env = "gnu"),
268 all(target_os = "linux", target_env = "musl"),
269 all(target_os = "linux", target_env = "uclibc"),
270 any(target_os = "freebsd", target_os = "dragonfly"),
271 any(target_os = "macos", target_os = "ios"),
272 any(target_os = "openbsd", target_os = "netbsd"),
273 target_os = "android",
274 target_os = "emscripten",
275 target_os = "fuchsia",
276 target_os = "haiku",
277 target_os = "solarish",
278 ))]
279 CORE = 2 => RLIMIT_CORE,
280
281
282 #[cfg(any(
285 all(target_os = "linux", target_env = "gnu"),
286 all(target_os = "linux", target_env = "musl"),
287 all(target_os = "linux", target_env = "uclibc"),
288 any(target_os = "freebsd", target_os = "dragonfly"),
289 any(target_os = "macos", target_os = "ios"),
290 any(target_os = "openbsd", target_os = "netbsd"),
291 target_os = "android",
292 target_os = "emscripten",
293 target_os = "fuchsia",
294 target_os = "haiku",
295 target_os = "solarish",
296 ))]
297 CPU = 3 => RLIMIT_CPU,
298
299
300 #[cfg(any(
304 all(target_os = "linux", target_env = "gnu"),
305 all(target_os = "linux", target_env = "musl"),
306 all(target_os = "linux", target_env = "uclibc"),
307 any(target_os = "freebsd", target_os = "dragonfly"),
308 any(target_os = "macos", target_os = "ios"),
309 any(target_os = "openbsd", target_os = "netbsd"),
310 target_os = "android",
311 target_os = "emscripten",
312 target_os = "fuchsia",
313 target_os = "haiku",
314 target_os = "solarish",
315 ))]
316 DATA = 4 => RLIMIT_DATA,
317
318
319 #[cfg(any(
322 all(target_os = "linux", target_env = "gnu"),
323 all(target_os = "linux", target_env = "musl"),
324 all(target_os = "linux", target_env = "uclibc"),
325 any(target_os = "freebsd", target_os = "dragonfly"),
326 any(target_os = "macos", target_os = "ios"),
327 any(target_os = "openbsd", target_os = "netbsd"),
328 target_os = "android",
329 target_os = "emscripten",
330 target_os = "fuchsia",
331 target_os = "haiku",
332 target_os = "solarish",
333 ))]
334 FSIZE = 5 => RLIMIT_FSIZE,
335
336
337 #[cfg(any(
339 target_os = "freebsd",
340 ))]
341 KQUEUES = 6 => RLIMIT_KQUEUES,
342
343
344 #[cfg(any(
350 all(target_os = "linux", target_env = "gnu"),
351 all(target_os = "linux", target_env = "musl"),
352 all(target_os = "linux", target_env = "uclibc"),
353 target_os = "android",
354 target_os = "emscripten",
355 target_os = "fuchsia",
356 ))]
357 LOCKS = 7 => RLIMIT_LOCKS,
358
359
360 #[cfg(any(
363 all(target_os = "linux", target_env = "gnu"),
364 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
365 all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
366 all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
367 any(target_os = "freebsd", target_os = "dragonfly"),
368 any(target_os = "macos", target_os = "ios"),
369 any(target_os = "openbsd", target_os = "netbsd"),
370 target_os = "android",
371 target_os = "emscripten",
372 target_os = "fuchsia",
373 ))]
374 MEMLOCK = 8 => RLIMIT_MEMLOCK,
375
376
377 #[cfg(any(
381 all(target_os = "linux", target_env = "gnu"),
382 all(target_os = "linux", target_env = "musl"),
383 all(target_os = "linux", target_env = "uclibc"),
384 target_os = "android",
385 target_os = "emscripten",
386 target_os = "fuchsia",
387 ))]
388 MSGQUEUE = 9 => RLIMIT_MSGQUEUE,
389
390
391 #[cfg(any(
395 all(target_os = "linux", target_env = "gnu"),
396 all(target_os = "linux", target_env = "musl"),
397 all(target_os = "linux", target_env = "uclibc"),
398 target_os = "android",
399 target_os = "emscripten",
400 target_os = "fuchsia",
401 ))]
402 NICE = 10 => RLIMIT_NICE,
403
404
405 #[cfg(any(
409 all(target_os = "linux", target_env = "gnu"),
410 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
411 all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
412 all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
413 any(target_os = "freebsd", target_os = "dragonfly"),
414 any(target_os = "macos", target_os = "ios"),
415 any(target_os = "openbsd", target_os = "netbsd"),
416 target_os = "android",
417 target_os = "emscripten",
418 target_os = "fuchsia",
419 target_os = "haiku",
420 target_os = "solarish",
421 ))]
422 NOFILE = 11 => RLIMIT_NOFILE,
423
424
425 #[cfg(any(
427 target_os = "haiku",
428 ))]
429 NOVMON = 12 => RLIMIT_NOVMON,
430
431
432 #[cfg(any(
435 all(target_os = "linux", target_env = "gnu"),
436 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
437 all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
438 all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
439 any(target_os = "freebsd", target_os = "dragonfly"),
440 any(target_os = "macos", target_os = "ios"),
441 any(target_os = "openbsd", target_os = "netbsd"),
442 target_os = "android",
443 target_os = "emscripten",
444 target_os = "fuchsia",
445 ))]
446 NPROC = 13 => RLIMIT_NPROC,
447
448
449 #[cfg(any(
451 target_os = "freebsd",
452 ))]
453 NPTS = 14 => RLIMIT_NPTS,
454
455
456 #[cfg(any(
461 target_os = "netbsd",
462 ))]
463 NTHR = 15 => RLIMIT_NTHR,
464
465
466 #[cfg(any(
468 target_os = "dragonfly",
469 ))]
470 POSIXLOCKS = 16 => RLIMIT_POSIXLOCKS,
471
472
473 #[cfg(any(
477 all(target_os = "linux", target_env = "gnu"),
478 all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "mips", target_arch = "powerpc", target_arch = "hexagon", target_arch = "arm")),
479 all(target_os = "linux", target_env = "musl", any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "mips64", target_arch = "powerpc64")),
480 all(target_os = "linux", target_env = "uclibc", any(target_arch = "mips", target_arch = "mips64")),
481 any(target_os = "freebsd", target_os = "dragonfly"),
482 any(target_os = "macos", target_os = "ios"),
483 any(target_os = "openbsd", target_os = "netbsd"),
484 target_os = "android",
485 target_os = "emscripten",
486 target_os = "fuchsia",
487 ))]
488 RSS = 17 => RLIMIT_RSS,
489
490
491 #[cfg(any(
495 all(target_os = "linux", target_env = "gnu"),
496 all(target_os = "linux", target_env = "musl"),
497 all(target_os = "linux", target_env = "uclibc"),
498 target_os = "android",
499 target_os = "emscripten",
500 target_os = "fuchsia",
501 ))]
502 RTPRIO = 18 => RLIMIT_RTPRIO,
503
504
505 #[cfg(any(
509 all(target_os = "linux", target_env = "gnu"),
510 all(target_os = "linux", target_env = "musl"),
511 target_os = "fuchsia",
512 ))]
513 RTTIME = 19 => RLIMIT_RTTIME,
514
515
516 #[cfg(any(
521 any(target_os = "freebsd", target_os = "dragonfly"),
522 target_os = "netbsd",
523 ))]
524 SBSIZE = 20 => RLIMIT_SBSIZE,
525
526
527 #[cfg(any(
531 all(target_os = "linux", target_env = "gnu"),
532 all(target_os = "linux", target_env = "musl"),
533 all(target_os = "linux", target_env = "uclibc"),
534 target_os = "android",
535 target_os = "emscripten",
536 target_os = "fuchsia",
537 ))]
538 SIGPENDING = 21 => RLIMIT_SIGPENDING,
539
540
541 #[cfg(any(
544 all(target_os = "linux", target_env = "gnu"),
545 all(target_os = "linux", target_env = "musl"),
546 all(target_os = "linux", target_env = "uclibc"),
547 any(target_os = "freebsd", target_os = "dragonfly"),
548 any(target_os = "macos", target_os = "ios"),
549 any(target_os = "openbsd", target_os = "netbsd"),
550 target_os = "android",
551 target_os = "emscripten",
552 target_os = "fuchsia",
553 target_os = "haiku",
554 target_os = "solarish",
555 ))]
556 STACK = 22 => RLIMIT_STACK,
557
558
559 #[cfg(any(
562 target_os = "freebsd",
563 ))]
564 SWAP = 23 => RLIMIT_SWAP,
565
566
567 #[cfg(any(
569 target_os = "freebsd",
570 ))]
571 UMTXP = 24 => RLIMIT_UMTXP,
572
573
574 #[cfg(any(
576 any(target_os = "freebsd", target_os = "dragonfly"),
577 target_os = "solarish",
578 ))]
579 VMEM = 25 => RLIMIT_VMEM,
580
581}
582