use std::cmp::Ordering;
use anyhow::anyhow;
use irc_proto::{ChannelMode, Mode};
#[derive(Copy, Clone, Debug, Eq, PartialEq, sqlx::Type)]
#[repr(i16)]
pub enum Permission {
Ban = -1,
Normal = 0,
Voice = 1,
HalfOperator = i16::MAX - 2,
Operator = i16::MAX - 1,
Founder = i16::MAX,
}
impl PartialOrd for Permission {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Permission {
fn cmp(&self, other: &Self) -> Ordering {
match (*self as i16, *other as i16) {
(-1, 0) => Ordering::Less,
(0, -1) => Ordering::Greater,
_ => (*self as i16).cmp(&(*other as i16)),
}
}
}
impl TryFrom<ChannelMode> for Permission {
type Error = anyhow::Error;
fn try_from(value: ChannelMode) -> Result<Self, Self::Error> {
match value {
ChannelMode::Ban => Ok(Self::Ban),
ChannelMode::Voice => Ok(Self::Voice),
ChannelMode::Halfop => Ok(Self::HalfOperator),
ChannelMode::Oper => Ok(Self::Operator),
ChannelMode::Founder => Ok(Self::Founder),
_ => Err(anyhow!("unknown user access level: {value:?}")),
}
}
}
impl Permission {
pub const SUPPORTED_PREFIXES: &'static str = "(qohv)~@%+";
#[must_use]
pub fn into_mode(self, add: bool, mask: String) -> Option<Mode<ChannelMode>> {
<Option<ChannelMode>>::from(self).map(|v| {
if add {
Mode::Plus(v, Some(mask))
} else {
Mode::Minus(v, Some(mask))
}
})
}
#[must_use]
pub const fn into_prefix(self) -> &'static str {
match self {
Self::Ban | Self::Normal => "",
Self::Voice => "+",
Self::HalfOperator => "%",
Self::Operator => "@",
Self::Founder => "~",
}
}
}
impl From<Permission> for Option<ChannelMode> {
fn from(value: Permission) -> Self {
match value {
Permission::Ban => Some(ChannelMode::Ban),
Permission::Normal => None,
Permission::Voice => Some(ChannelMode::Voice),
Permission::HalfOperator => Some(ChannelMode::Halfop),
Permission::Operator => Some(ChannelMode::Oper),
Permission::Founder => Some(ChannelMode::Founder),
}
}
}
impl Permission {
#[must_use]
pub fn can_chatter(self) -> bool {
self != Self::Ban
}
#[must_use]
pub fn can_join(self) -> bool {
self != Self::Ban
}
#[must_use]
pub const fn can_set_topic(self) -> bool {
(self as i16) >= (Self::HalfOperator as i16)
}
#[must_use]
pub const fn can_kick(self) -> bool {
(self as i16) >= (Self::HalfOperator as i16)
}
#[must_use]
pub const fn can_set_permission(self, new: Self, old: Self) -> bool {
(self as i16) >= (Self::HalfOperator as i16)
&& (self as i16) > (new as i16)
&& (self as i16) > (old as i16)
}
}