use scursor::{ReadCursor, WriteCursor};
use std::fmt::Write;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct PermissionSet {
pub execute: bool,
pub write: bool,
pub read: bool,
}
impl std::fmt::Display for PermissionSet {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_char(if self.read { 'r' } else { '-' })?;
f.write_char(if self.write { 'w' } else { '-' })?;
f.write_char(if self.execute { 'x' } else { '-' })?;
Ok(())
}
}
impl PermissionSet {
pub const fn all() -> Self {
Self {
execute: true,
write: true,
read: true,
}
}
pub const fn read_only() -> Self {
Self {
execute: false,
write: false,
read: true,
}
}
fn value(self) -> u16 {
let mut x = 0;
if self.execute {
x |= 0b001;
}
if self.write {
x |= 0b010;
}
if self.read {
x |= 0b100;
}
x
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Permissions {
pub world: PermissionSet,
pub group: PermissionSet,
pub owner: PermissionSet,
}
impl Permissions {
pub const fn same(set: PermissionSet) -> Permissions {
Permissions {
world: set,
group: set,
owner: set,
}
}
}
impl std::fmt::Display for Permissions {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"world: {} group: {} owner: {}",
self.world, self.group, self.owner
)
}
}
#[derive(Copy, Clone)]
struct Mask(u16);
impl Mask {
const fn bit(bit: u8) -> Self {
Self(1 << bit)
}
fn is_set(self, value: u16) -> bool {
self.0 & value != 0
}
}
impl Permissions {
const WE: Mask = Mask::bit(0);
const WW: Mask = Mask::bit(1);
const WR: Mask = Mask::bit(2);
const GE: Mask = Mask::bit(3);
const GW: Mask = Mask::bit(4);
const GR: Mask = Mask::bit(5);
const OE: Mask = Mask::bit(6);
const OW: Mask = Mask::bit(7);
const OR: Mask = Mask::bit(8);
fn value(self) -> u16 {
self.world.value() | self.group.value() << 3 | self.owner.value() << 6
}
pub(crate) fn write(&self, cursor: &mut WriteCursor) -> Result<(), scursor::WriteError> {
cursor.write_u16_le(self.value())
}
pub(crate) fn read(cursor: &mut ReadCursor) -> Result<Self, scursor::ReadError> {
let bits = cursor.read_u16_le()?;
Ok(Self {
world: PermissionSet {
execute: Self::WE.is_set(bits),
write: Self::WW.is_set(bits),
read: Self::WR.is_set(bits),
},
group: PermissionSet {
execute: Self::GE.is_set(bits),
write: Self::GW.is_set(bits),
read: Self::GR.is_set(bits),
},
owner: PermissionSet {
execute: Self::OE.is_set(bits),
write: Self::OW.is_set(bits),
read: Self::OR.is_set(bits),
},
})
}
}
#[cfg(test)]
mod test {
use super::*;
fn test_permission_parsing(bytes: &[u8], expected: Permissions) {
let mut cursor = ReadCursor::new(bytes);
let parsed = Permissions::read(&mut cursor).unwrap();
assert!(cursor.is_empty());
assert_eq!(expected, parsed);
}
fn test_permission_writing(value: Permissions, expected: &[u8]) {
let mut buffer: [u8; 2] = [0; 2];
let mut cursor = WriteCursor::new(&mut buffer);
value.write(&mut cursor).unwrap();
assert_eq!(cursor.remaining(), 0);
assert_eq!(cursor.written(), expected);
}
#[test]
fn writes_permission_bytes() {
test_permission_writing(Permissions::same(PermissionSet::all()), &[0xFF, 0x01]);
test_permission_writing(
Permissions::same(PermissionSet::read_only()),
&[0b00100100, 1],
);
}
#[test]
fn parses_permission_bytes() {
test_permission_parsing(&[0xFF, 0x01], Permissions::same(PermissionSet::all()));
test_permission_parsing(
&[0b00100100, 1],
Permissions::same(PermissionSet::read_only()),
);
}
}