use std::borrow::Cow;
use std::fmt;
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use crate::api::ParamValue;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum AccessLevel {
Anonymous,
Guest,
Reporter,
Developer,
Maintainer,
Owner,
Admin,
}
impl AccessLevel {
pub fn as_str(self) -> &'static str {
match self {
AccessLevel::Admin => "admin",
AccessLevel::Owner => "owner",
AccessLevel::Maintainer => "maintainer",
AccessLevel::Developer => "developer",
AccessLevel::Reporter => "reporter",
AccessLevel::Guest => "guest",
AccessLevel::Anonymous => "anonymous",
}
}
pub fn as_u64(self) -> u64 {
match self {
AccessLevel::Admin => 60,
AccessLevel::Owner => 50,
AccessLevel::Maintainer => 40,
AccessLevel::Developer => 30,
AccessLevel::Reporter => 20,
AccessLevel::Guest => 10,
AccessLevel::Anonymous => 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SortOrder {
Ascending,
Descending,
}
impl Default for SortOrder {
fn default() -> Self {
SortOrder::Descending
}
}
impl SortOrder {
pub fn as_str(self) -> &'static str {
match self {
SortOrder::Ascending => "asc",
SortOrder::Descending => "desc",
}
}
}
impl ParamValue<'static> for SortOrder {
fn as_value(self) -> Cow<'static, str> {
self.as_str().into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EnableState {
Enabled,
Disabled,
}
impl EnableState {
pub fn as_str(self) -> &'static str {
match self {
EnableState::Enabled => "enabled",
EnableState::Disabled => "disabled",
}
}
}
impl From<bool> for EnableState {
fn from(b: bool) -> Self {
if b {
EnableState::Enabled
} else {
EnableState::Disabled
}
}
}
impl ParamValue<'static> for EnableState {
fn as_value(self) -> Cow<'static, str> {
self.as_str().into()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NameOrId<'a> {
Name(Cow<'a, str>),
Id(u64),
}
const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &CONTROLS
.add(b' ')
.add(b'"')
.add(b'#')
.add(b'<')
.add(b'>')
.add(b'`')
.add(b'?')
.add(b'{')
.add(b'}')
.add(b'%')
.add(b'/');
pub fn path_escaped<'a>(input: &'a str) -> impl fmt::Display + 'a {
utf8_percent_encode(input, PATH_SEGMENT_ENCODE_SET)
}
impl<'a> fmt::Display for NameOrId<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
NameOrId::Name(name) => write!(f, "{}", path_escaped(name)),
NameOrId::Id(id) => write!(f, "{}", id),
}
}
}
impl<'a> From<u64> for NameOrId<'a> {
fn from(id: u64) -> Self {
NameOrId::Id(id)
}
}
impl<'a> From<&'a str> for NameOrId<'a> {
fn from(name: &'a str) -> Self {
NameOrId::Name(name.into())
}
}
impl<'a> From<String> for NameOrId<'a> {
fn from(name: String) -> Self {
NameOrId::Name(name.into())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisibilityLevel {
Public,
Internal,
Private,
}
impl VisibilityLevel {
pub fn as_str(self) -> &'static str {
match self {
VisibilityLevel::Public => "public",
VisibilityLevel::Internal => "internal",
VisibilityLevel::Private => "private",
}
}
}
impl ParamValue<'static> for VisibilityLevel {
fn as_value(self) -> Cow<'static, str> {
self.as_str().into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum YesNo {
Yes,
No,
}
impl YesNo {
pub fn as_str(self) -> &'static str {
match self {
YesNo::Yes => "yes",
YesNo::No => "no",
}
}
}
impl From<bool> for YesNo {
fn from(b: bool) -> Self {
if b {
YesNo::Yes
} else {
YesNo::No
}
}
}
impl ParamValue<'static> for YesNo {
fn as_value(self) -> Cow<'static, str> {
self.as_str().into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ProtectedAccessLevel {
Developer,
Maintainer,
Admin,
NoAccess,
}
impl Default for ProtectedAccessLevel {
fn default() -> Self {
ProtectedAccessLevel::Maintainer
}
}
impl ProtectedAccessLevel {
fn as_str(self) -> &'static str {
match self {
ProtectedAccessLevel::Developer => "30",
ProtectedAccessLevel::Maintainer => "40",
ProtectedAccessLevel::Admin => "60",
ProtectedAccessLevel::NoAccess => "0",
}
}
}
impl ParamValue<'static> for ProtectedAccessLevel {
fn as_value(self) -> Cow<'static, str> {
self.as_str().into()
}
}
#[cfg(test)]
mod tests {
use std::cmp;
use crate::api::common::{
AccessLevel, EnableState, NameOrId, ProtectedAccessLevel, SortOrder, VisibilityLevel, YesNo,
};
#[test]
fn access_level_as_str() {
let items = &[
(AccessLevel::Anonymous, "anonymous", 0),
(AccessLevel::Guest, "guest", 10),
(AccessLevel::Reporter, "reporter", 20),
(AccessLevel::Developer, "developer", 30),
(AccessLevel::Maintainer, "maintainer", 40),
(AccessLevel::Owner, "owner", 50),
(AccessLevel::Admin, "admin", 60),
];
for (i, s, u) in items {
assert_eq!(i.as_str(), *s);
assert_eq!(i.as_u64(), *u);
}
}
#[test]
fn access_level_ordering() {
let items = &[
AccessLevel::Anonymous,
AccessLevel::Guest,
AccessLevel::Reporter,
AccessLevel::Developer,
AccessLevel::Maintainer,
AccessLevel::Owner,
AccessLevel::Admin,
];
let mut last = None;
for item in items {
if let Some(prev) = last {
assert!(prev < item);
}
last = Some(item);
}
}
#[test]
fn sort_order_default() {
assert_eq!(SortOrder::default(), SortOrder::Descending);
}
#[test]
fn sort_order_as_str() {
let items = &[
(SortOrder::Ascending, "asc"),
(SortOrder::Descending, "desc"),
];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
#[test]
fn enable_state_as_str() {
let items = &[
(EnableState::Enabled, "enabled"),
(EnableState::Disabled, "disabled"),
];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
#[test]
fn enable_state_from_bool() {
let items = &[(EnableState::Enabled, true), (EnableState::Disabled, false)];
for (i, s) in items {
assert_eq!(*i, (*s).into());
}
}
#[test]
fn name_or_id_as_str() {
let items: &[(NameOrId, _)] = &[
("user".into(), "user"),
("special/name".into(), "special%2Fname"),
(
"special/name?string".to_string().into(),
"special%2Fname%3Fstring",
),
(1.into(), "1"),
];
for (i, s) in items {
assert_eq!(i.to_string(), *s);
}
}
#[test]
fn visibility_level_as_str() {
let items = &[
(VisibilityLevel::Public, "public"),
(VisibilityLevel::Internal, "internal"),
(VisibilityLevel::Private, "private"),
];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
#[test]
fn yes_no_as_str() {
let items = &[(YesNo::Yes, "yes"), (YesNo::No, "no")];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
#[test]
fn yes_no_from_bool() {
let items = &[(YesNo::Yes, true), (YesNo::No, false)];
for (i, s) in items {
assert_eq!(*i, (*s).into());
}
}
#[test]
fn protected_access_level_default() {
assert_eq!(
ProtectedAccessLevel::default(),
ProtectedAccessLevel::Maintainer,
);
}
#[test]
fn protected_access_level_ord() {
let items = &[
ProtectedAccessLevel::Developer,
ProtectedAccessLevel::Maintainer,
ProtectedAccessLevel::Admin,
ProtectedAccessLevel::NoAccess,
];
for i in items {
assert_eq!(*i, *i);
assert_eq!(i.cmp(i), cmp::Ordering::Equal);
let mut expect = cmp::Ordering::Greater;
for j in items {
let is_same = i == j;
if is_same {
expect = cmp::Ordering::Equal;
}
assert_eq!(i.cmp(j), expect);
if is_same {
expect = cmp::Ordering::Less;
}
}
let mut expect = cmp::Ordering::Less;
for j in items.iter().rev() {
let is_same = i == j;
if is_same {
expect = cmp::Ordering::Equal;
}
assert_eq!(i.cmp(j), expect);
if is_same {
expect = cmp::Ordering::Greater;
}
}
}
}
#[test]
fn protected_access_level_as_str() {
let items = &[
(ProtectedAccessLevel::Developer, "30"),
(ProtectedAccessLevel::Maintainer, "40"),
(ProtectedAccessLevel::Admin, "60"),
(ProtectedAccessLevel::NoAccess, "0"),
];
for (i, s) in items {
assert_eq!(i.as_str(), *s);
}
}
}