use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ResourceType {
Organization,
User,
Node,
Project,
Instance,
Domain,
Secret,
Environment,
Session,
Vm,
Invite,
}
impl ResourceType {
fn as_str(&self) -> &'static str {
match self {
ResourceType::Organization => "organization",
ResourceType::User => "user",
ResourceType::Node => "node",
ResourceType::Project => "project",
ResourceType::Instance => "instance",
ResourceType::Domain => "domain",
ResourceType::Secret => "secret",
ResourceType::Environment => "environment",
ResourceType::Session => "session",
ResourceType::Vm => "vm",
ResourceType::Invite => "invite",
}
}
fn from_str(s: &str) -> Option<Self> {
Some(match s {
"organization" => ResourceType::Organization,
"user" => ResourceType::User,
"node" => ResourceType::Node,
"project" => ResourceType::Project,
"instance" => ResourceType::Instance,
"domain" => ResourceType::Domain,
"secret" => ResourceType::Secret,
"environment" => ResourceType::Environment,
"session" => ResourceType::Session,
"vm" => ResourceType::Vm,
"invite" => ResourceType::Invite,
_ => return None,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UrnParseError {
Malformed(String),
UnknownResourceType(String),
}
impl fmt::Display for UrnParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UrnParseError::Malformed(s) => write!(f, "malformed URN: {:?}", s),
UrnParseError::UnknownResourceType(s) => {
write!(f, "unknown URN resource type: {:?}", s)
}
}
}
}
impl std::error::Error for UrnParseError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Urn {
resource_type: ResourceType,
id: String,
}
const URN_PREFIX: &str = "urn:artisan:";
impl Urn {
pub fn new(resource_type: ResourceType, id: impl Into<String>) -> Self {
Self {
resource_type,
id: id.into(),
}
}
pub fn resource_type(&self) -> ResourceType {
self.resource_type
}
pub fn id(&self) -> &str {
&self.id
}
pub fn parse(s: &str) -> Result<Self, UrnParseError> {
let rest = s
.strip_prefix(URN_PREFIX)
.ok_or_else(|| UrnParseError::Malformed(s.to_owned()))?;
let (type_segment, id) = rest
.split_once(':')
.ok_or_else(|| UrnParseError::Malformed(s.to_owned()))?;
if id.is_empty() {
return Err(UrnParseError::Malformed(s.to_owned()));
}
let resource_type = ResourceType::from_str(type_segment)
.ok_or_else(|| UrnParseError::UnknownResourceType(type_segment.to_owned()))?;
Ok(Self {
resource_type,
id: id.to_owned(),
})
}
}
impl fmt::Display for Urn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{URN_PREFIX}{}:{}", self.resource_type.as_str(), self.id)
}
}