winget_types/locale/documentation/
label.rs

1use core::{fmt, str::FromStr};
2
3use compact_str::CompactString;
4use thiserror::Error;
5
6#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "serde", serde(try_from = "&str"))]
9#[repr(transparent)]
10pub struct DocumentLabel(CompactString);
11
12#[derive(Debug, Error, Eq, PartialEq)]
13pub enum DocumentLabelError {
14    #[error("Document label must not be empty")]
15    Empty,
16    #[error(
17        "Document label must not have more than {} characters but has {_0}",
18        DocumentLabel::MAX_CHAR_LENGTH
19    )]
20    TooLong(usize),
21}
22
23impl DocumentLabel {
24    pub const MAX_CHAR_LENGTH: usize = 100;
25
26    /// Creates a new `DocumentLabel` from any type that implements `AsRef<str>` and
27    /// `Into<CompactString>`.
28    ///
29    /// # Errors
30    ///
31    /// Returns an `Err` if the document label is empty or more than 100 characters long.
32    pub fn new<T: AsRef<str> + Into<CompactString>>(
33        document_label: T,
34    ) -> Result<Self, DocumentLabelError> {
35        let channel_str = document_label.as_ref();
36
37        if channel_str.is_empty() {
38            return Err(DocumentLabelError::Empty);
39        }
40
41        let char_count = channel_str.chars().count();
42        if char_count > Self::MAX_CHAR_LENGTH {
43            return Err(DocumentLabelError::TooLong(char_count));
44        }
45
46        Ok(Self(document_label.into()))
47    }
48
49    /// Creates a new `DocumentLabel` from any type that implements `Into<CompactString>` without
50    /// checking its validity.
51    ///
52    /// # Safety
53    ///
54    /// The document label must not be empty or more than 100 characters long.
55    #[must_use]
56    #[inline]
57    pub unsafe fn new_unchecked<T: Into<CompactString>>(document_label: T) -> Self {
58        Self(document_label.into())
59    }
60
61    /// Extracts a string slice containing the entire `DocumentLabel`.
62    #[must_use]
63    #[inline]
64    pub fn as_str(&self) -> &str {
65        self.0.as_str()
66    }
67}
68
69impl AsRef<str> for DocumentLabel {
70    #[inline]
71    fn as_ref(&self) -> &str {
72        self.as_str()
73    }
74}
75
76impl fmt::Display for DocumentLabel {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        self.0.fmt(f)
79    }
80}
81
82impl FromStr for DocumentLabel {
83    type Err = DocumentLabelError;
84
85    #[inline]
86    fn from_str(s: &str) -> Result<Self, Self::Err> {
87        Self::new(s)
88    }
89}
90
91impl TryFrom<&str> for DocumentLabel {
92    type Error = DocumentLabelError;
93
94    #[inline]
95    fn try_from(value: &str) -> Result<Self, Self::Error> {
96        Self::new(value)
97    }
98}