non_empty_str/
str.rs

1//! Non-empty [`str`].
2
3#[cfg(feature = "unsafe-assert")]
4use core::hint::assert_unchecked;
5
6use core::{fmt, ops::Deref};
7
8use const_macros::{const_early, const_ok};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
12
13use crate::empty::Empty;
14
15/// Represents non-empty [`str`] values.
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct Str<'s> {
18    value: &'s str,
19}
20
21#[cfg(feature = "serde")]
22impl Serialize for Str<'_> {
23    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
24        self.get().serialize(serializer)
25    }
26}
27
28#[cfg(feature = "serde")]
29type Value<'s> = &'s str;
30
31#[cfg(feature = "serde")]
32impl<'de: 's, 's> Deserialize<'de> for Str<'s> {
33    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
34        let value = Value::deserialize(deserializer)?;
35
36        Self::new(value).map_err(Error::custom)
37    }
38}
39
40impl fmt::Display for Str<'_> {
41    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42        self.get().fmt(formatter)
43    }
44}
45
46impl<'s> TryFrom<&'s str> for Str<'s> {
47    type Error = Empty;
48
49    fn try_from(value: &'s str) -> Result<Self, Self::Error> {
50        Self::new(value)
51    }
52}
53
54impl<'s> From<Str<'s>> for &'s str {
55    fn from(value: Str<'s>) -> Self {
56        value.take()
57    }
58}
59
60impl AsRef<str> for Str<'_> {
61    fn as_ref(&self) -> &str {
62        self.get()
63    }
64}
65
66impl Deref for Str<'_> {
67    type Target = str;
68
69    fn deref(&self) -> &Self::Target {
70        self.get()
71    }
72}
73
74impl<'s> Str<'s> {
75    /// Constructs [`Self`], provided the given value is non-empty.
76    ///
77    /// # Errors
78    ///
79    /// Returns [`Empty`] if the given string is empty.
80    pub const fn new(value: &'s str) -> Result<Self, Empty> {
81        const_early!(value.is_empty() => Empty);
82
83        // SAFETY: the value is non-empty at this point
84        Ok(unsafe { Self::new_unchecked(value) })
85    }
86
87    /// Similar to [`new`], but the error is discarded.
88    ///
89    /// [`new`]: Self::new
90    pub const fn new_ok(value: &'s str) -> Option<Self> {
91        const_ok!(Self::new(value))
92    }
93
94    /// Constructs [`Self`] without checking if the given value is non-empty.
95    ///
96    /// # Safety
97    ///
98    /// The caller must ensure that the given value is non-empty.
99    pub const unsafe fn new_unchecked(value: &'s str) -> Self {
100        Self { value }
101    }
102
103    #[cfg(feature = "unsafe-assert")]
104    const fn assert_non_empty(&self) {
105        // SAFETY: the value is non-empty by construction
106        unsafe {
107            assert_unchecked(!self.value.is_empty());
108        }
109    }
110
111    /// Consumes [`Self`], returning the wrapped string.
112    pub const fn take(self) -> &'s str {
113        #[cfg(feature = "unsafe-assert")]
114        self.assert_non_empty();
115
116        self.value
117    }
118}
119
120/// Type alias for [`Str`] with `'static` lifetime.
121pub type StaticStr = Str<'static>;
122
123impl Str<'_> {
124    /// Returns the wrapped string reference.
125    pub const fn get(&self) -> &str {
126        #[cfg(feature = "unsafe-assert")]
127        self.assert_non_empty();
128
129        self.value
130    }
131}