1#[cfg(feature = "unsafe-assert")]
4use core::hint::assert_unchecked;
5
6use core::{fmt, ops::Deref};
7
8use const_macros::{const_ok, const_try};
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
12
13use crate::empty::{Empty, check_str};
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> Deserialize<'de> for Str<'de> {
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<'t> TryFrom<&'t str> for Str<'t> {
47 type Error = Empty;
48
49 fn try_from(value: &'t 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_try!(check_str(value));
82
83 Ok(unsafe { Self::new_unchecked(value) })
84 }
85
86 pub const fn new_ok(value: &'s str) -> Option<Self> {
90 const_ok!(Self::new(value))
91 }
92
93 pub const unsafe fn new_unchecked(value: &'s str) -> Self {
99 Self { value }
100 }
101
102 #[cfg(feature = "unsafe-assert")]
103 const fn assert_non_empty(&self) {
104 unsafe { assert_unchecked(!self.value.is_empty()) }
105 }
106
107 pub const fn take(self) -> &'s str {
109 #[cfg(feature = "unsafe-assert")]
110 self.assert_non_empty();
111
112 self.value
113 }
114}
115
116impl Str<'_> {
117 pub const fn get(&self) -> &str {
119 #[cfg(feature = "unsafe-assert")]
120 self.assert_non_empty();
121
122 self.value
123 }
124}