use core::{fmt, str::FromStr};
use compact_str::CompactString;
use thiserror::Error;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "CompactString"))]
#[repr(transparent)]
pub struct License(CompactString);
#[derive(Debug, Error, Eq, PartialEq)]
pub enum LicenseError {
#[error(
"License must have at least {} characters but has {_0}",
License::MIN_CHAR_LENGTH
)]
TooShort(usize),
#[error(
"License must not have more than {} characters but has {_0}",
License::MAX_CHAR_LENGTH
)]
TooLong(usize),
}
impl License {
pub const MIN_CHAR_LENGTH: usize = 3;
pub const MAX_CHAR_LENGTH: usize = 512;
pub const PROPRIETARY: Self = Self(CompactString::const_new("Proprietary"));
pub const APACHE_V1: Self = Self(CompactString::const_new("Apache-1.0"));
pub const APACHE_V1_1: Self = Self(CompactString::const_new("Apache-1.1"));
pub const APACHE_V2: Self = Self(CompactString::const_new("Apache-2.0"));
pub const BSD_V3_CLAUSE_NEW_OR_REVISED: Self = Self(CompactString::const_new("BSD-3-Clause"));
pub const AGPL_V1_ONLY: Self = Self(CompactString::const_new("AGPL-1.0-only"));
pub const AGPL_V1_OR_LATER: Self = Self(CompactString::const_new("AGPL-1.0-or-later"));
pub const AGPL_V3_ONLY: Self = Self(CompactString::const_new("AGPL-3.0-only"));
pub const AGPL_V3_OR_LATER: Self = Self(CompactString::const_new("AGPL-3.0-or-later"));
pub const GPL_V1_ONLY: Self = Self(CompactString::const_new("GPL-1.0-only"));
pub const GPL_V1_OR_LATER: Self = Self(CompactString::const_new("GPL-1.0-or-later"));
pub const GPL_V2_ONLY: Self = Self(CompactString::const_new("GPL-2.0-only"));
pub const GPL_V2_OR_LATER: Self = Self(CompactString::const_new("GPL-2.0-or-later"));
pub const GPL_V3_ONLY: Self = Self(CompactString::const_new("GPL-3.0-only"));
pub const GPL_V3_OR_LATER: Self = Self(CompactString::const_new("GPL-3.0-or-later"));
pub const MIT: Self = Self(CompactString::const_new("MIT"));
pub fn new<T: AsRef<str> + Into<CompactString>>(license: T) -> Result<Self, LicenseError> {
match license.as_ref().chars().count() {
count if count < Self::MIN_CHAR_LENGTH => Err(LicenseError::TooShort(count)),
count if count > Self::MAX_CHAR_LENGTH => Err(LicenseError::TooLong(count)),
_ => Ok(Self(license.into())),
}
}
#[must_use]
#[inline]
pub unsafe fn new_unchecked<T: Into<CompactString>>(license: T) -> Self {
Self(license.into())
}
#[must_use]
#[inline]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl AsRef<str> for License {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Default for License {
fn default() -> Self {
Self::PROPRIETARY
}
}
impl fmt::Display for License {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl FromStr for License {
type Err = LicenseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
impl TryFrom<CompactString> for License {
type Error = LicenseError;
#[inline]
fn try_from(value: CompactString) -> Result<Self, Self::Error> {
Self::new(value)
}
}