use std::convert::TryFrom;
use std::fmt;
use std::ops::Deref;
use regex::Regex;
use sea_orm::Value;
use thiserror::Error;
use utoipa::ToSchema;
use crate::normalized_name::NormalizedName;
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Hash, ToSchema)]
#[schema(value_type = String)]
pub struct OriginalName(String);
#[derive(Debug, PartialEq, Eq, Error)]
pub enum NameError {
#[error("Invalid character in name")]
InvalidCharacter,
#[error("Invalid length for name")]
InvalidLength,
}
impl OriginalName {
pub fn to_normalized(&self) -> NormalizedName {
NormalizedName::from(self)
}
pub fn from_unchecked(name: String) -> Self {
Self(name)
}
pub fn into_inner(self) -> String {
self.0
}
}
impl TryFrom<String> for OriginalName {
type Error = NameError;
fn try_from(package_name: String) -> Result<Self, Self::Error> {
let re = Regex::new(r"^[a-zA-Z][a-zA-Z0-9-_]*$").unwrap();
if !re.is_match(&package_name) {
Err(NameError::InvalidCharacter)
} else if package_name.len() > 64 {
Err(NameError::InvalidLength)
} else {
Ok(OriginalName(package_name))
}
}
}
impl From<&OriginalName> for String {
fn from(name: &OriginalName) -> Self {
name.to_string()
}
}
impl From<OriginalName> for String {
fn from(name: OriginalName) -> Self {
name.to_string()
}
}
impl From<OriginalName> for Value {
fn from(value: OriginalName) -> Self {
Value::String(Some(value.0))
}
}
impl From<&OriginalName> for Value {
fn from(value: &OriginalName) -> Self {
Value::String(Some(value.0.clone()))
}
}
impl TryFrom<&String> for OriginalName {
type Error = NameError;
fn try_from(package_name: &String) -> Result<Self, Self::Error> {
OriginalName::try_from(package_name.clone())
}
}
impl TryFrom<&str> for OriginalName {
type Error = NameError;
fn try_from(package_name: &str) -> Result<Self, Self::Error> {
OriginalName::try_from(package_name.to_string())
}
}
impl Deref for OriginalName {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for OriginalName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_package_names() {
assert_eq!(
OriginalName::try_from("test-lib").unwrap(),
OriginalName("test-lib".to_string())
);
assert_eq!(
OriginalName::try_from("Test_lib").unwrap(),
OriginalName("Test_lib".to_string())
);
assert_eq!(
OriginalName::try_from("test_lib_foo").unwrap(),
OriginalName("test_lib_foo".to_string())
);
assert_eq!(
OriginalName::try_from("test-lIB-foo").unwrap(),
OriginalName("test-lIB-foo".to_string())
);
assert_eq!(
OriginalName::try_from("test12_14f").unwrap(),
OriginalName("test12_14f".to_string())
);
assert_eq!(
OriginalName::try_from("tEs2-23_1f").unwrap(),
OriginalName("tEs2-23_1f".to_string())
);
assert_eq!(
OriginalName::try_from("testlib").unwrap(),
OriginalName("testlib".to_string())
);
assert_eq!(
OriginalName::try_from("Testlib23").unwrap(),
OriginalName("Testlib23".to_string())
);
}
#[test]
fn invalid_characters_in_package_name() {
assert_eq!(
OriginalName::try_from("_test").unwrap_err(),
NameError::InvalidCharacter
);
assert_eq!(
OriginalName::try_from("44Test").unwrap_err(),
NameError::InvalidCharacter
);
assert_eq!(
OriginalName::try_from("-Av").unwrap_err(),
NameError::InvalidCharacter
);
assert_eq!(
OriginalName::try_from("testÄ").unwrap_err(),
NameError::InvalidCharacter
);
assert_eq!(
OriginalName::try_from("test?").unwrap_err(),
NameError::InvalidCharacter
);
assert_eq!(
OriginalName::try_from(".45A").unwrap_err(),
NameError::InvalidCharacter
);
assert_eq!(
OriginalName::try_from("").unwrap_err(),
NameError::InvalidCharacter
);
}
#[test]
fn too_long_package_name() {
assert_eq!(
OriginalName::try_from(
"zbsfrofdgxekytxrporaocoieaviehlvjrroockxufdkzgtxudkmdkentyyhkmtpx"
)
.unwrap_err(),
NameError::InvalidLength
);
}
}