1#![cfg_attr(nightly, feature(test))]
5#![allow(non_upper_case_globals)]
6#![allow(dead_code)]
7
8use bitflags::bitflags;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11enum Class
12{
13 Owner(Bit),
14 Group(Bit),
15 Other(Bit),
16}
17
18impl Class
19{
20 #[cfg(nightly)]
22 const fn mode(&self) -> u32
23 {
24 macro_rules! map {
25 ($bit:expr, $bt:path, $constant:ident) => {
26 if $bit.contains($bt) {
27 $constant
28 } else {
29 0
30 }
31 }
32 }
33 match self {
34 Self::Owner(bit) => {
35 0u32 |
36 map!(bit, Bit::Read, MODE_USER_READ) |
37 map!(bit, Bit::Write, MODE_USER_WRITE) |
38 map!(bit, Bit::Execute, MODE_USER_EXECUTE)
39 },
40 Self::Group(bit) => {
41 0u32 |
42 map!(bit, Bit::Read, MODE_GROUP_READ) |
43 map!(bit, Bit::Write, MODE_GROUP_WRITE) |
44 map!(bit, Bit::Execute, MODE_GROUP_EXECUTE)
45 },
46 Self::Other(bit) => {
47 0u32 |
48 map!(bit, Bit::Read, MODE_OTHER_READ) |
49 map!(bit, Bit::Write, MODE_OTHER_WRITE) |
50 map!(bit, Bit::Execute, MODE_OTHER_EXECUTE)
51 },
52 }
53 }
54 #[cfg(not(nightly))]
55 fn mode(&self) -> u32 {
57 macro_rules! map {
58 ($bit:expr, $bt:path, $constant:ident) => {
59 if $bit.contains($bt) {
60 $constant
61 } else {
62 0
63 }
64 }
65 }
66 match self {
67 Self::Owner(bit) => {
68 0u32 |
69 map!(bit, Bit::Read, MODE_USER_READ) |
70 map!(bit, Bit::Write, MODE_USER_WRITE) |
71 map!(bit, Bit::Execute, MODE_USER_EXECUTE)
72 },
73 Self::Group(bit) => {
74 0u32 |
75 map!(bit, Bit::Read, MODE_GROUP_READ) |
76 map!(bit, Bit::Write, MODE_GROUP_WRITE) |
77 map!(bit, Bit::Execute, MODE_GROUP_EXECUTE)
78 },
79 Self::Other(bit) => {
80 0u32 |
81 map!(bit, Bit::Read, MODE_OTHER_READ) |
82 map!(bit, Bit::Write, MODE_OTHER_WRITE) |
83 map!(bit, Bit::Execute, MODE_OTHER_EXECUTE)
84 },
85 }
86 }
87
88 #[cfg(nightly)] const fn mask_mode(&self, bit: u32) -> Bit
89 {
90 macro_rules! map {
91 ($bit:expr, $bt:path, $constant:ident) => {
92 if ($bit & $constant) == $constant {$bt.bits()} else {0u32}
93 }
94 }
95
96 Bit::from_bits_truncate(match self {
97 Self::Owner(_) => {
98 map!(bit, Bit::Read, MODE_USER_READ) |
99 map!(bit, Bit::Write, MODE_USER_WRITE) |
100 map!(bit, Bit::Execute, MODE_USER_EXECUTE)
101 },
102 Self::Group(_) => {
103 map!(bit, Bit::Read, MODE_GROUP_READ) |
104 map!(bit, Bit::Write, MODE_GROUP_WRITE) |
105 map!(bit, Bit::Execute, MODE_GROUP_EXECUTE)
106 },
107 Self::Other(_) => {
108 map!(bit, Bit::Read, MODE_OTHER_READ) |
109 map!(bit, Bit::Write, MODE_OTHER_WRITE) |
110 map!(bit, Bit::Execute, MODE_OTHER_EXECUTE)
111 },
112 })
113 }
114 #[cfg(not(nightly))] fn mask_mode(&self, bit: u32) -> Bit
115 {
116 macro_rules! map {
117 ($bit:expr, $bt:path, $constant:ident) => {
118 if ($bit & $constant) == $constant {$bt.bits()} else {0u32}
119 }
120 }
121
122 Bit::from_bits_truncate(match self {
123 Self::Owner(_) => {
124 map!(bit, Bit::Read, MODE_USER_READ) |
125 map!(bit, Bit::Write, MODE_USER_WRITE) |
126 map!(bit, Bit::Execute, MODE_USER_EXECUTE)
127 },
128 Self::Group(_) => {
129 map!(bit, Bit::Read, MODE_GROUP_READ) |
130 map!(bit, Bit::Write, MODE_GROUP_WRITE) |
131 map!(bit, Bit::Execute, MODE_GROUP_EXECUTE)
132 },
133 Self::Other(_) => {
134 map!(bit, Bit::Read, MODE_OTHER_READ) |
135 map!(bit, Bit::Write, MODE_OTHER_WRITE) |
136 map!(bit, Bit::Execute, MODE_OTHER_EXECUTE)
137 },
138 })
139 }
140}
141
142const MODE_USER: u32 = 0o700;
143const MODE_USER_READ: u32 = 0o400;
144const MODE_USER_WRITE: u32 = 0o200;
145const MODE_USER_EXECUTE: u32 = 0o100;
146
147const MODE_GROUP: u32 = 0o70;
148const MODE_GROUP_READ: u32 = 0o40;
149const MODE_GROUP_WRITE: u32 = 0o20;
150const MODE_GROUP_EXECUTE: u32 = 0o10;
151
152const MODE_OTHER: u32 = 0o7;
153const MODE_OTHER_READ: u32 = 0o4;
154const MODE_OTHER_WRITE: u32 = 0o2;
155const MODE_OTHER_EXECUTE: u32 = 0o1;
156
157const MODE: u32 = 0o777;
158
159bitflags!{
160 pub struct Bit: u32 {
165 const None = 0;
167 const Read = 1;
169 const Write = 2;
171 const Execute = 4;
176
177 const Mask = 7;
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, Ord, PartialOrd)]
194#[repr(C)]
195pub struct Permissions
196{
197 pub owner: Bit,
202
203 pub group: Bit,
208
209 pub other: Bit,
214
215 u_mask: u32,
216}
217
218#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
220pub enum User
221{
222 Owner,
224 Group,
226 Other,
228}
229
230impl User
231{
232 #[cfg(nightly)] pub const fn mode(self, mask: Bit) -> u32
234 {
235 match self {
236 User::Owner => Class::Owner(mask).mode(),
237 User::Group => Class::Group(mask).mode(),
238 User::Other => Class::Other(mask).mode(),
239 }
240 }
241 #[cfg(not(nightly))] pub fn mode(self, mask: Bit) -> u32
243 {
244 match self {
245 User::Owner => Class::Owner(mask).mode(),
246 User::Group => Class::Group(mask).mode(),
247 User::Other => Class::Other(mask).mode(),
248 }
249 }
250
251
252 #[cfg(nightly)] pub const fn from_mode(self, mask: u32) -> Bit
254 {
255 match self {
256 User::Owner => Class::Owner(Bit::Mask).mask_mode(mask),
257 User::Group => Class::Group(Bit::Mask).mask_mode(mask),
258 User::Other => Class::Other(Bit::Mask).mask_mode(mask),
259 }
260 }
261
262 #[cfg(not(nightly))] pub fn from_mode(self, mask: u32) -> Bit
264 {
265 match self {
266 User::Owner => Class::Owner(Bit::Mask).mask_mode(mask),
267 User::Group => Class::Group(Bit::Mask).mask_mode(mask),
268 User::Other => Class::Other(Bit::Mask).mask_mode(mask),
269 }
270 }
271}
272
273impl Default for Permissions
274{
275 #[inline] fn default() -> Self
276 {
277 Self::new()
278 }
279}
280
281impl Permissions
282{
283 pub const fn new() -> Self
285 {
286 Self {
287 owner: Bit::None,
288 group: Bit::None,
289 other: Bit::None,
290
291 u_mask: 0u32,
292 }
293 }
294}
295
296impl Permissions
298{
299 #[inline] const fn c_owner(&self) -> Class
300 {
301 Class::Owner(self.owner)
302 }
303 #[inline] const fn c_group(&self) -> Class
304 {
305 Class::Group(self.group)
306 }
307 #[inline] const fn c_other(&self) -> Class
308 {
309 Class::Other(self.other)
310 }
311
312 #[inline] #[cfg(nightly)] const fn mask_calc(&self) -> u32
314 {
315 self.c_owner().mode() |
316 self.c_group().mode() |
317 self.c_other().mode()
318 }
319
320 #[inline] #[cfg(nightly)] const fn into_calced(mut self) -> Self
321 {
322 self.u_mask = self.mask_calc();
323 self
324 }
325
326 #[inline] pub const fn mask(&self) -> u32
328 {
329 self.u_mask
330 }
331
332 #[inline] #[cfg(not(nightly))] fn mask_calc(&self) -> u32
334 {
335 self.c_owner().mode() |
336 self.c_group().mode() |
337 self.c_other().mode()
338 }
339
340 #[inline] #[cfg(nightly)] const fn from_mask_calc(bit: u32) -> Self
342 {
343 Self{
344 owner: Class::Owner(Bit::Mask).mask_mode(bit),
345 group: Class::Group(Bit::Mask).mask_mode(bit),
346 other: Class::Other(Bit::Mask).mask_mode(bit),
347
348 u_mask: 0,
349 }.into_calced()
350 }
351
352 #[inline] pub const fn from_mask(from: u32) -> Self
354 {
355 MAP[(from & MODE) as usize]
356 }
357
358 #[inline] #[cfg(nightly)] pub const fn add_mask(self, class: User, bit: Bit) -> Self
363 {
364 Self {
365 u_mask: self.u_mask | class.mode(bit),
366 ..match class {
367 User::Owner => {
368 Self {
369 owner: Bit::from_bits_truncate(self.owner.bits() | bit.bits()),
370 ..self
371 }
372 },
373 User::Group => {
374 Self {
375 group: Bit::from_bits_truncate(self.group.bits() | bit.bits()),
376 ..self
377 }
378 },
379 User::Other => {
380 Self {
381 other: Bit::from_bits_truncate(self.other.bits() | bit.bits()),
382 ..self
383 }
384 },
385 }
386 }
387 }
388
389 #[inline] #[cfg(not(nightly))] pub fn add_mask(self, class: User, bit: Bit) -> Self
394 {
395 Self {
396 u_mask: self.u_mask | class.mode(bit),
397 ..match class {
398 User::Owner => {
399 Self {
400 owner: Bit::from_bits_truncate(self.owner.bits() | bit.bits()),
401 ..self
402 }
403 },
404 User::Group => {
405 Self {
406 group: Bit::from_bits_truncate(self.group.bits() | bit.bits()),
407
408 ..self
409 }
410 },
411 User::Other => {
412 Self {
413 other: Bit::from_bits_truncate(self.other.bits() | bit.bits()),
414
415 ..self
416 }
417 },
418 }
419 }
420 }
421
422
423 #[inline] #[cfg(nightly)] pub const fn remove_mask(self, class: User, bit: Bit) -> Self
428 {
429 Self{
430 u_mask: self.u_mask & !class.mode(bit),
431 ..match class {
432 User::Owner => {
433 Self {
434 owner: Bit::from_bits_truncate(self.owner.bits() & !bit.bits()),
435 ..self
436 }
437 },
438 User::Group => {
439 Self {
440 group: Bit::from_bits_truncate(self.group.bits() & !bit.bits()),
441 ..self
442 }
443 },
444 User::Other => {
445 Self {
446 other: Bit::from_bits_truncate(self.other.bits() & !bit.bits()),
447 ..self
448 }
449 },
450 }
451 }
452 }
453
454
455 #[inline] #[cfg(not(nightly))] pub fn remove_mask(self, class: User, bit: Bit) -> Self
460 {
461 Self {
462 u_mask: self.u_mask & !class.mode(bit),
463 ..match class {
464 User::Owner => {
465 Self {
466 owner: Bit::from_bits_truncate(self.owner.bits() & !bit.bits()),
467 ..self
468 }
469 },
470 User::Group => {
471 Self {
472 group: Bit::from_bits_truncate(self.group.bits() & !bit.bits()),
473 ..self
474 }
475 },
476 User::Other => {
477 Self {
478 other: Bit::from_bits_truncate(self.other.bits() & !bit.bits()),
479 ..self
480 }
481 },
482 }
483 }
484 }
485
486 #[inline] #[cfg(nightly)] pub const fn has_mask(&self, class: User, bit: Bit) -> bool
488 {
489 match class {
490 User::Owner => {
491 (self.owner.bits() & bit.bits()) == bit.bits()
492 },
493 User::Group => {
494 (self.group.bits() & bit.bits()) == bit.bits()
495 },
496 User::Other => {
497 (self.other.bits() & bit.bits()) == bit.bits()
498 },
499 }
500 }
501
502 #[inline] #[cfg(not(nightly))] pub fn has_mask(&self, class: User, bit: Bit) -> bool
504 {
505 match class {
506 User::Owner => {
507 (self.owner.bits() & bit.bits()) == bit.bits()
508 },
509 User::Group => {
510 (self.group.bits() & bit.bits()) == bit.bits()
511 },
512 User::Other => {
513 (self.other.bits() & bit.bits()) == bit.bits()
514 },
515 }
516 }
517}
518
519impl From<Permissions> for u32
520{
521 #[inline] fn from(from: Permissions) -> Self
522 {
523 debug_assert_eq!(from.mask_calc(), from.mask());
524 from.mask()
525 }
526}
527
528impl From<u32> for Permissions
529{
530 #[inline] fn from(from: u32) -> Self
531 {
532 Self::from_mask(from)
533 }
534}
535
536mod test;
537#[cfg(nightly)] mod bench;
538
539const fn generate_struct() -> [Permissions; 512]
540{
541 #[cfg(nightly)] return {
542 let mut i: u32 =0;
543 let mut output = [Permissions::new(); 512];
544 loop
545 {
546 output[i as usize] = Permissions::from_mask_calc(i);
547 i+=1;
548 if i == 0o777 { output[0o777] = Permissions::new()
550 .add_mask(User::Owner, Bit::Mask)
551 .add_mask(User::Group, Bit::Mask)
552 .add_mask(User::Other, Bit::Mask);
553 break;
554 }
555 }
556 output
557 };
558
559 #[cfg(not(nightly))] {
560 stable::MAP
561 }
562}
563
564
565#[cfg(feature="speedup_hack_stable")]
566mod output {
567 use super::*;
568 use std::{
569 io::{
570 self,
571 Write,
572 },
573 };
574 pub fn print_map_as_syntax_hack<W: Write+?Sized>(to: &mut W) -> io::Result<()>
575 {
576 fn print_bit<W: Write+?Sized>(to:&mut W, bit: &Bit) -> io::Result<()>
577 {
578 macro_rules! dobit {
579 ($bit:ident, $p:path) => {
580 if $bit.contains($p) {
581 write!(to, "| {}", $p.bits())?;
582
583 }
584 }
585 }
586 write!(to, "Bit::from_bits_truncate(0u32 ")?;
587 dobit!(bit, Bit::Read);
588 dobit!(bit, Bit::Write);
589 dobit!(bit, Bit::Execute);
590 write!(to, "| 0)")?;
591 Ok(())
592 }
593
594 writeln!(to, "[")?;
595 for perm in MAP.iter() {
596 write!(to, "Permissions {{owner: ")?;
597 print_bit(to,&perm.owner)?;
598 write!(to, ", group: ")?;
599 print_bit(to,&perm.group)?;
600 write!(to, ", other: ")?;
601 print_bit(to,&perm.other)?;
602 write!(to, ", u_mask: {}}}, ", perm.mask_calc())?;
603 }
604 writeln!(to, "]")?;
605 Ok(())
606 }
607}
608
609#[cfg(feature="speedup_hack_stable")]
610fn print_map_as_syntax_hack()
611{
612 let stdout = std::io::stdout();
613 let mut stdout = stdout.lock();
614 output::print_map_as_syntax_hack(&mut stdout).unwrap();
615}
616
617#[cfg(feature="speedup_hack_stable")]
619pub fn generate_build_map() {
620 use std::fs::OpenOptions;
621 use std::io::Write;
622
623 let mut file = OpenOptions::new()
624 .create(true)
625 .truncate(true)
626 .write(true)
627 .open("./src/stable/mod.rs").expect("Failed to open file");
628
629 writeln!(&mut file, "//! Hack for fast in stable with no `const fn` stuffs\n").unwrap();
630 writeln!(&mut file, "use super::*;").unwrap();
631
632 writeln!(&mut file, "pub const MAP: [Permissions; 512] = ").unwrap();
633 output::print_map_as_syntax_hack(&mut file).expect("Failed to write");
634 writeln!(&mut file, ";").unwrap();
635}
636
637#[cfg(not(nightly))] mod stable;
638
639const MAP: [Permissions; 512] = generate_struct();
640
641#[cfg(target_family="unix")]
642mod ext;
643#[cfg(target_family="unix")]
644pub use ext::*;
645
646use std::{
648 borrow::Borrow,
649 cmp::{PartialEq,Eq},
650};
651
652impl AsRef<Permissions> for u32
653{
654 fn as_ref(&self) -> &Permissions
655 {
656 &MAP[(*self & 0o777u32) as usize]
657 }
658}
659
660impl AsRef<Permissions> for Permissions
661{
662 fn as_ref(&self) -> &Permissions
663 {
664 &self
665 }
666}
667
668impl Borrow<Permissions> for u32
669{
670 fn borrow(&self) -> &Permissions
671 {
672 self.as_ref()
673 }
674}
675
676impl PartialEq<u32> for Permissions
677{
678 fn eq(&self, other: &u32) -> bool
679 {
680 &Self::from(*other) == self
681 }
682}
683
684impl PartialEq<Permissions> for u32
685{
686 fn eq(&self, other: &Permissions) -> bool
687 {
688 other.eq(self)
689 }
690}
691
692impl std::fmt::Display for Permissions
693{
694 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
695 {
696 write!(f, "0{}", self.mask())
697 }
698}