use std::str::FromStr;
use serde::{Serialize, Deserialize};
use tracing::{error, instrument};
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub struct ResourceTypeError {
message: String
}
impl fmt::Display for ResourceTypeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for ResourceTypeError {}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize,Default)]
#[serde(rename_all = "camelCase")]
#[serde(into = "i8", from = "i8")]
pub enum ResourceType {
Workspace = 1,
#[default]
Board = 2,
Folder = 3,
}
impl ResourceType {
pub fn as_str(&self) -> &'static str {
match self {
ResourceType::Workspace => "workspace",
ResourceType::Board => "board",
ResourceType::Folder => "folder",
}
}
#[instrument]
pub fn to_i8(&self) -> i8 {
match self {
ResourceType::Workspace => 1,
ResourceType::Board => 2,
ResourceType::Folder => 3,
}
}
#[instrument]
pub fn try_from_i8(value: i8) -> Result<Self, ResourceTypeError> {
match value {
1 => Ok(ResourceType::Workspace),
2 => Ok(ResourceType::Board),
3 => Ok(ResourceType::Folder),
invalid => {
error!(value = invalid, "Invalid ResourceType value");
Err(ResourceTypeError {
message: format!("Invalid ResourceType value: {}", invalid)
})
}
}
}
}
impl From<ResourceType> for i8 {
fn from(resource_type: ResourceType) -> Self {
resource_type.to_i8()
}
}
impl From<ResourceType> for String {
fn from(resource_type: ResourceType) -> Self {
resource_type.as_str().to_string()
}
}
impl From<ResourceType> for i32 {
fn from(resource_type: ResourceType) -> Self {
resource_type.to_i8() as i32
}
}
impl From<i8> for ResourceType {
fn from(value: i8) -> Self {
Self::try_from_i8(value).unwrap_or_else(|e| {
error!(error = %e, "Failed to convert i8 to ResourceType");
panic!("Invalid ResourceType value: {}", value)
})
}
}
impl FromStr for ResourceType {
type Err = ResourceTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"workspace" => Ok(ResourceType::Workspace),
"board" => Ok(ResourceType::Board),
"folder" => Ok(ResourceType::Folder),
invalid => {
error!(value = invalid, "Invalid ResourceType string");
Err(ResourceTypeError {
message: format!("Invalid ResourceType string: {}", invalid)
})
}
}
}
}
impl ToString for ResourceType {
#[instrument]
fn to_string(&self) -> String {
self.as_str().to_string()
}
}
impl TryFrom<i32> for ResourceType {
type Error = ResourceTypeError;
#[instrument]
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value < i8::MIN as i32 || value > i8::MAX as i32 {
error!(value = value, "ResourceType value out of i8 range");
return Err(ResourceTypeError {
message: format!("ResourceType value out of range: {}", value)
});
}
Self::try_from_i8(value as i8)
}
}
impl TryFrom<String> for ResourceType {
type Error = ResourceTypeError;
#[instrument]
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::from_str(&value)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::convert::TryFrom;
#[test]
fn test_from_i8() {
assert_eq!(ResourceType::from(1), ResourceType::Workspace);
assert_eq!(ResourceType::from(2), ResourceType::Board);
assert_eq!(ResourceType::from(3), ResourceType::Folder);
}
#[test]
fn test_to_i8() {
assert_eq!(ResourceType::Workspace.to_i8(), 1);
assert_eq!(ResourceType::Board.to_i8(), 2);
assert_eq!(ResourceType::Folder.to_i8(), 3);
}
#[test]
fn test_from_str() {
assert_eq!("workspace".parse::<ResourceType>().unwrap(), ResourceType::Workspace);
assert_eq!("board".parse::<ResourceType>().unwrap(), ResourceType::Board);
assert_eq!("folder".parse::<ResourceType>().unwrap(), ResourceType::Folder);
}
#[test]
fn test_to_string() {
assert_eq!(ResourceType::Workspace.to_string(), "workspace");
assert_eq!(ResourceType::Board.to_string(), "board");
assert_eq!(ResourceType::Folder.to_string(), "folder");
}
#[test]
fn test_try_from_i32() {
assert_eq!(ResourceType::try_from(1_i32).unwrap(), ResourceType::Workspace);
assert!(ResourceType::try_from(1000_i32).is_err());
}
#[test]
fn test_serde() {
let resource = ResourceType::Board;
let serialized = serde_json::to_string(&resource).unwrap();
let deserialized: ResourceType = serde_json::from_str(&serialized).unwrap();
assert_eq!(resource, deserialized);
}
#[test]
#[should_panic(expected = "Invalid ResourceType value: 4")]
fn test_invalid_from_i8() {
let _ = ResourceType::from(4);
}
}