winget_types/locale/
license.rs

1use core::{fmt, str::FromStr};
2
3use compact_str::CompactString;
4use thiserror::Error;
5
6/// A license governing the use and or distribution for a product.
7///
8/// Where available, [`SPDX`] short identifiers are preferred.
9///
10/// [`SPDX`]: https://spdx.org/licenses/
11#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[cfg_attr(feature = "serde", serde(try_from = "CompactString"))]
14#[repr(transparent)]
15pub struct License(CompactString);
16
17#[derive(Debug, Error, Eq, PartialEq)]
18pub enum LicenseError {
19    #[error(
20        "License must have at least {} characters but has {_0}",
21        License::MIN_CHAR_LENGTH
22    )]
23    TooShort(usize),
24    #[error(
25        "License must not have more than {} characters but has {_0}",
26        License::MAX_CHAR_LENGTH
27    )]
28    TooLong(usize),
29}
30
31impl License {
32    pub const MIN_CHAR_LENGTH: usize = 3;
33    pub const MAX_CHAR_LENGTH: usize = 512;
34
35    /// Represents a proprietary license.
36    ///
37    /// Use this when the license information for a package is unknown or not publicly available.
38    /// Proprietary licenses typically restrict usage, modification, and redistribution.
39    pub const PROPRIETARY: Self = Self(CompactString::const_new("Proprietary"));
40
41    /// <https://spdx.org/licenses/Apache-1.0.html>
42    pub const APACHE_V1: Self = Self(CompactString::const_new("Apache-1.0"));
43
44    /// <https://spdx.org/licenses/Apache-1.1.html>
45    pub const APACHE_V1_1: Self = Self(CompactString::const_new("Apache-1.1"));
46
47    /// <https://spdx.org/licenses/Apache-2.0.html>
48    pub const APACHE_V2: Self = Self(CompactString::const_new("Apache-2.0"));
49
50    /// <https://spdx.org/licenses/BSD-3-Clause.html>
51    pub const BSD_V3_CLAUSE_NEW_OR_REVISED: Self = Self(CompactString::const_new("BSD-3-Clause"));
52
53    /// <https://spdx.org/licenses/AGPL-1.0-only.html>
54    pub const AGPL_V1_ONLY: Self = Self(CompactString::const_new("AGPL-1.0-only"));
55
56    /// <https://spdx.org/licenses/AGPL-1.0-or-later.html>
57    pub const AGPL_V1_OR_LATER: Self = Self(CompactString::const_new("AGPL-1.0-or-later"));
58
59    /// <https://spdx.org/licenses/AGPL-3.0-only.html>
60    pub const AGPL_V3_ONLY: Self = Self(CompactString::const_new("AGPL-3.0-only"));
61
62    /// <https://spdx.org/licenses/AGPL-3.0-or-later.html>
63    pub const AGPL_V3_OR_LATER: Self = Self(CompactString::const_new("AGPL-3.0-or-later"));
64
65    /// <https://spdx.org/licenses/GPL-1.0-only.html>
66    pub const GPL_V1_ONLY: Self = Self(CompactString::const_new("GPL-1.0-only"));
67
68    /// <https://spdx.org/licenses/GPL-1.0-or-later.html>
69    pub const GPL_V1_OR_LATER: Self = Self(CompactString::const_new("GPL-1.0-or-later"));
70
71    /// <https://spdx.org/licenses/GPL-2.0-only.html>
72    pub const GPL_V2_ONLY: Self = Self(CompactString::const_new("GPL-2.0-only"));
73
74    /// <https://spdx.org/licenses/GPL-2.0-or-later.html>
75    pub const GPL_V2_OR_LATER: Self = Self(CompactString::const_new("GPL-2.0-or-later"));
76
77    /// <https://spdx.org/licenses/GPL-3.0-only.html>
78    pub const GPL_V3_ONLY: Self = Self(CompactString::const_new("GPL-3.0-only"));
79
80    /// <https://spdx.org/licenses/GPL-3.0-or-later.html>
81    pub const GPL_V3_OR_LATER: Self = Self(CompactString::const_new("GPL-3.0-or-later"));
82
83    /// <https://spdx.org/licenses/MIT.html>
84    pub const MIT: Self = Self(CompactString::const_new("MIT"));
85
86    /// Creates a new `License` from any type that implements `AsRef<str>` and
87    /// `Into<CompactString>`.
88    ///
89    /// # Errors
90    ///
91    /// Returns an `Err` if the license is less than 3 characters long or more than 512 characters
92    /// long.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use winget_types::locale::License;
98    /// # use winget_types::locale::LicenseError;
99    ///
100    /// # fn main() -> Result<(), LicenseError>  {
101    /// let license = License::new("MIT")?;
102    ///
103    /// assert_eq!(license.as_str(), "MIT");
104    /// # Ok(())
105    /// # }
106    /// ```
107    pub fn new<T: AsRef<str> + Into<CompactString>>(license: T) -> Result<Self, LicenseError> {
108        match license.as_ref().chars().count() {
109            count if count < Self::MIN_CHAR_LENGTH => Err(LicenseError::TooShort(count)),
110            count if count > Self::MAX_CHAR_LENGTH => Err(LicenseError::TooLong(count)),
111            _ => Ok(Self(license.into())),
112        }
113    }
114
115    /// Creates a new `License` from any type that implements `Into<CompactString>` without checking
116    /// its validity.
117    ///
118    /// # Safety
119    ///
120    /// The license must not be less than 3 characters long or more than 512 characters long.
121    #[must_use]
122    #[inline]
123    pub unsafe fn new_unchecked<T: Into<CompactString>>(license: T) -> Self {
124        Self(license.into())
125    }
126
127    /// Extracts a string slice containing the entire `License`.
128    #[must_use]
129    #[inline]
130    pub fn as_str(&self) -> &str {
131        self.0.as_str()
132    }
133}
134
135impl AsRef<str> for License {
136    #[inline]
137    fn as_ref(&self) -> &str {
138        self.as_str()
139    }
140}
141
142impl Default for License {
143    fn default() -> Self {
144        Self::PROPRIETARY
145    }
146}
147
148impl fmt::Display for License {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        self.0.fmt(f)
151    }
152}
153
154impl FromStr for License {
155    type Err = LicenseError;
156
157    #[inline]
158    fn from_str(s: &str) -> Result<Self, Self::Err> {
159        Self::new(s)
160    }
161}
162
163impl TryFrom<CompactString> for License {
164    type Error = LicenseError;
165
166    #[inline]
167    fn try_from(value: CompactString) -> Result<Self, Self::Error> {
168        Self::new(value)
169    }
170}