use crate::account::Account;
use serde::de::{self, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum PermissionLevel {
ReadOnly = 0,
ReadWrite = 1,
Advanced = 2,
All = 255,
}
impl PermissionLevel {
pub fn value(&self) -> u8 {
*self as u8
}
}
impl fmt::Display for PermissionLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value())
}
}
impl From<u8> for PermissionLevel {
fn from(v: u8) -> Self {
match v {
255 => PermissionLevel::All,
1 => PermissionLevel::ReadWrite,
2 => PermissionLevel::Advanced,
_ => PermissionLevel::ReadOnly,
}
}
}
impl Serialize for PermissionLevel {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u8(self.value())
}
}
struct PermissionLevelVisitor;
impl<'de> Visitor<'de> for PermissionLevelVisitor {
type Value = PermissionLevel;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a permission level (0, 1, 2, or 255)")
}
fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(PermissionLevel::from(value))
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
if value <= 255 {
Ok(PermissionLevel::from(value as u8))
} else {
Err(E::custom(format!(
"permission level out of range: {}",
value
)))
}
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
value
.parse::<u8>()
.map(PermissionLevel::from)
.map_err(|_| E::custom(format!("invalid permission level string: {}", value)))
}
}
impl<'de> Deserialize<'de> for PermissionLevel {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(PermissionLevelVisitor)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Permission(pub PermissionLevel);
impl Permission {
pub const ALL: Self = Self(PermissionLevel::All);
pub const READ_ONLY: Self = Self(PermissionLevel::ReadOnly);
pub fn can_execute(&self, required_level: PermissionLevel) -> bool {
self.0 >= required_level
}
pub fn is_read_only(&self) -> bool {
self.0 == PermissionLevel::ReadOnly
}
pub fn parse_for_account(permission_str: &str, account: Account) -> Self {
let key = account.as_ref();
for entry in permission_str.split_whitespace() {
if let Some((user, value)) = entry.split_once('=')
&& user == key
&& let Ok(v) = value.parse::<u8>()
{
return Permission(PermissionLevel::from(v));
}
}
Permission::READ_ONLY
}
}
impl From<PermissionLevel> for Permission {
fn from(level: PermissionLevel) -> Self {
Permission(level)
}
}
impl Default for Permission {
fn default() -> Self {
Permission::READ_ONLY
}
}
#[cfg(test)]
mod tests {
use super::*;
const PERMISSION_STR: &str = "super=255 user1=0 user2=1 user3=2";
#[test]
fn parse_super_gets_all() {
let perm = Permission::parse_for_account(PERMISSION_STR, Account::Super);
assert_eq!(perm, Permission::ALL);
assert!(perm.can_execute(PermissionLevel::All));
assert!(perm.can_execute(PermissionLevel::Advanced));
}
#[test]
fn parse_user1_read_only() {
let perm = Permission::parse_for_account(PERMISSION_STR, Account::User1);
assert_eq!(perm, Permission::READ_ONLY);
assert!(perm.is_read_only());
assert!(!perm.can_execute(PermissionLevel::ReadWrite));
}
#[test]
fn parse_user2_read_write() {
let perm = Permission::parse_for_account(PERMISSION_STR, Account::User2);
assert_eq!(perm.0, PermissionLevel::ReadWrite);
assert!(perm.can_execute(PermissionLevel::ReadWrite));
assert!(!perm.can_execute(PermissionLevel::Advanced));
}
#[test]
fn parse_user3_advanced() {
let perm = Permission::parse_for_account(PERMISSION_STR, Account::User3);
assert_eq!(perm.0, PermissionLevel::Advanced);
assert!(perm.can_execute(PermissionLevel::Advanced));
assert!(!perm.can_execute(PermissionLevel::All));
}
#[test]
fn parse_missing_account_defaults_to_read_only() {
let perm = Permission::parse_for_account("super=255", Account::User1);
assert_eq!(perm, Permission::READ_ONLY);
}
#[test]
fn serialize_permission_level() {
let level = PermissionLevel::Advanced;
let json = serde_json::to_string(&level).unwrap();
assert_eq!(json, "2");
}
#[test]
fn deserialize_permission_level() {
let level: PermissionLevel = serde_json::from_str("2").unwrap();
assert_eq!(level, PermissionLevel::Advanced);
let level: PermissionLevel = serde_json::from_str("\"255\"").unwrap();
assert_eq!(level, PermissionLevel::All);
}
}