1#[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#[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 pub const fn new(value: &'s str) -> Result<Self, Empty> {
81 const_early!(value.is_empty() => Empty);
82
83 Ok(unsafe { Self::new_unchecked(value) })
85 }
86
87 pub const fn new_ok(value: &'s str) -> Option<Self> {
91 const_ok!(Self::new(value))
92 }
93
94 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 unsafe {
107 assert_unchecked(!self.value.is_empty());
108 }
109 }
110
111 pub const fn take(self) -> &'s str {
113 #[cfg(feature = "unsafe-assert")]
114 self.assert_non_empty();
115
116 self.value
117 }
118}
119
120pub type StaticStr = Str<'static>;
122
123impl Str<'_> {
124 pub const fn get(&self) -> &str {
126 #[cfg(feature = "unsafe-assert")]
127 self.assert_non_empty();
128
129 self.value
130 }
131}