use std::{
borrow::Cow,
fmt::{Display, Formatter},
};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
#[cfg(feature = "bounded-static")]
use bounded_static::ToStatic;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{
command::CommandBody,
core::{impl_try_from, AString, Atom, NonEmptyVec},
extensions::quota::error::{QuotaError, QuotaRootError, SetQuotaError},
mailbox::Mailbox,
response::Data,
};
impl<'a> CommandBody<'a> {
pub fn get_quota<A>(root: A) -> Result<Self, A::Error>
where
A: TryInto<AString<'a>>,
{
Ok(CommandBody::GetQuota {
root: root.try_into()?,
})
}
pub fn get_quota_root<M>(mailbox: M) -> Result<Self, M::Error>
where
M: TryInto<Mailbox<'a>>,
{
Ok(CommandBody::GetQuotaRoot {
mailbox: mailbox.try_into()?,
})
}
pub fn set_quota<R, S>(root: R, quotas: S) -> Result<Self, SetQuotaError<R::Error, S::Error>>
where
R: TryInto<AString<'a>>,
S: TryInto<Vec<QuotaSet<'a>>>,
{
Ok(CommandBody::SetQuota {
root: root.try_into().map_err(SetQuotaError::Root)?,
quotas: quotas.try_into().map_err(SetQuotaError::QuotaSet)?,
})
}
}
impl<'a> Data<'a> {
pub fn quota<R, Q>(root: R, quotas: Q) -> Result<Self, QuotaError<R::Error, Q::Error>>
where
R: TryInto<AString<'a>>,
Q: TryInto<NonEmptyVec<QuotaGet<'a>>>,
{
Ok(Self::Quota {
root: root.try_into().map_err(QuotaError::Root)?,
quotas: quotas.try_into().map_err(QuotaError::Quotas)?,
})
}
pub fn quota_root<M, R>(
mailbox: M,
roots: R,
) -> Result<Self, QuotaRootError<M::Error, R::Error>>
where
M: TryInto<Mailbox<'a>>,
R: TryInto<Vec<AString<'a>>>,
{
Ok(Self::QuotaRoot {
mailbox: mailbox.try_into().map_err(QuotaRootError::Mailbox)?,
roots: roots.try_into().map_err(QuotaRootError::Roots)?,
})
}
}
#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Resource<'a> {
Storage,
Message,
Mailbox,
AnnotationStorage,
Other(ResourceOther<'a>),
}
#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ResourceOther<'a>(Atom<'a>);
impl_try_from!(Atom<'a>, 'a, &'a [u8], Resource<'a>);
impl_try_from!(Atom<'a>, 'a, Vec<u8>, Resource<'a>);
impl_try_from!(Atom<'a>, 'a, &'a str, Resource<'a>);
impl_try_from!(Atom<'a>, 'a, String, Resource<'a>);
impl_try_from!(Atom<'a>, 'a, Cow<'a, str>, Resource<'a>);
impl<'a> From<Atom<'a>> for Resource<'a> {
fn from(atom: Atom<'a>) -> Self {
match atom.inner().to_ascii_uppercase().as_ref() {
"STORAGE" => Resource::Storage,
"MESSAGE" => Resource::Message,
"MAILBOX" => Resource::Mailbox,
"ANNOTATION-STORAGE" => Resource::AnnotationStorage,
_ => Resource::Other(ResourceOther(atom)),
}
}
}
impl<'a> Display for Resource<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Storage => "STORAGE",
Self::Message => "MESSAGE",
Self::Mailbox => "MAILBOX",
Self::AnnotationStorage => "ANNOTATION-STORAGE",
Self::Other(other) => other.0.as_ref(),
})
}
}
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QuotaGet<'a> {
pub resource: Resource<'a>,
pub usage: u64,
pub limit: u64,
}
impl<'a> QuotaGet<'a> {
pub fn new(resource: Resource<'a>, usage: u64, limit: u64) -> Self {
Self {
resource,
usage,
limit,
}
}
}
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QuotaSet<'a> {
pub resource: Resource<'a>,
pub limit: u64,
}
impl<'a> QuotaSet<'a> {
pub fn new(resource: Resource<'a>, limit: u64) -> Self {
Self { resource, limit }
}
}
pub mod error {
use thiserror::Error;
#[derive(Clone, Debug, Eq, Error, Hash, Ord, PartialEq, PartialOrd)]
pub enum QuotaError<R, Q> {
#[error("Invalid root: {0}")]
Root(R),
#[error("Invalid quotas: {0}")]
Quotas(Q),
}
#[derive(Clone, Debug, Eq, Error, Hash, Ord, PartialEq, PartialOrd)]
pub enum QuotaRootError<M, R> {
#[error("Invalid mailbox: {0}")]
Mailbox(M),
#[error("Invalid roots: {0}")]
Roots(R),
}
#[derive(Clone, Debug, Eq, Error, Hash, Ord, PartialEq, PartialOrd)]
pub enum SetQuotaError<R, S> {
#[error("Invalid root: {0}")]
Root(R),
#[error("Invalid quota set: {0}")]
QuotaSet(S),
}
}