1#[cfg(not(any(feature = "std", feature = "alloc")))]
4compile_error!("expected either `std` or `alloc` to be enabled");
5
6#[cfg(all(not(feature = "std"), feature = "alloc"))]
7use alloc::{borrow::ToOwned, string::String};
8
9use core::{borrow::Borrow, fmt, ops::Deref, str::FromStr};
10
11use thiserror::Error;
12
13use crate::str::{Empty, Str};
14
15pub const EMPTY_OWNED: &str = "the owned string is empty";
17
18#[derive(Debug, Error)]
22#[error("{EMPTY_OWNED}")]
23#[cfg_attr(
24 feature = "diagnostics",
25 derive(miette::Diagnostic),
26 diagnostic(
27 code(non_empty_str::owned),
28 help("make sure the owned string is non-empty")
29 )
30)]
31pub struct EmptyOwned {
32 string: String,
33}
34
35impl EmptyOwned {
36 const fn new(string: String) -> Self {
38 Self { string }
39 }
40
41 #[must_use]
43 pub fn get(self) -> String {
44 self.string
45 }
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
50#[repr(transparent)]
51pub struct OwnedStr {
52 inner: String,
53}
54
55impl Borrow<Str> for OwnedStr {
56 fn borrow(&self) -> &Str {
57 self.as_str()
58 }
59}
60
61impl fmt::Display for OwnedStr {
62 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
63 self.as_str().fmt(formatter)
64 }
65}
66
67impl TryFrom<String> for OwnedStr {
68 type Error = EmptyOwned;
69
70 fn try_from(value: String) -> Result<Self, Self::Error> {
71 Self::new(value)
72 }
73}
74
75impl From<OwnedStr> for String {
76 fn from(string: OwnedStr) -> Self {
77 string.get()
78 }
79}
80
81impl From<&Str> for OwnedStr {
82 fn from(string: &Str) -> Self {
83 Self::from_str(string)
84 }
85}
86
87impl AsRef<Self> for OwnedStr {
88 fn as_ref(&self) -> &Self {
89 self
90 }
91}
92
93impl AsRef<String> for OwnedStr {
94 fn as_ref(&self) -> &String {
95 self.as_string()
96 }
97}
98
99impl AsRef<Str> for OwnedStr {
100 fn as_ref(&self) -> &Str {
101 self.as_str()
102 }
103}
104
105impl AsRef<str> for OwnedStr {
106 fn as_ref(&self) -> &str {
107 self.as_str().get()
108 }
109}
110
111impl FromStr for OwnedStr {
112 type Err = Empty;
113
114 fn from_str(string: &str) -> Result<Self, Self::Err> {
115 let non_empty = Str::try_from_str(string)?;
116
117 let owned = Self::from_str(non_empty);
118
119 Ok(owned)
120 }
121}
122
123impl Deref for OwnedStr {
124 type Target = String;
125
126 fn deref(&self) -> &Self::Target {
127 self.as_string()
128 }
129}
130
131impl OwnedStr {
132 pub const fn new(string: String) -> Result<Self, EmptyOwned> {
158 if string.is_empty() {
159 return Err(EmptyOwned::new(string));
160 }
161
162 Ok(unsafe { Self::new_unchecked(string) })
164 }
165
166 #[must_use]
172 pub const unsafe fn new_unchecked(inner: String) -> Self {
173 debug_assert!(!inner.is_empty());
174
175 Self { inner }
176 }
177
178 #[cfg(feature = "unsafe-assert")]
179 const fn assert_non_empty(&self) {
180 use core::hint::assert_unchecked;
181
182 unsafe {
184 assert_unchecked(!self.inner.is_empty());
185 }
186 }
187
188 #[allow(clippy::should_implement_trait)]
202 #[must_use]
203 pub fn from_str(string: &Str) -> Self {
204 unsafe { Self::new_unchecked(string.get().to_owned()) }
206 }
207
208 #[must_use]
210 pub const fn as_str(&self) -> &Str {
211 unsafe { Str::from_str_unchecked(self.inner.as_str()) }
213 }
214
215 #[must_use]
217 pub const fn as_string(&self) -> &String {
218 #[cfg(feature = "unsafe-assert")]
219 self.assert_non_empty();
220
221 &self.inner
222 }
223
224 #[must_use]
226 pub fn get(self) -> String {
227 #[cfg(feature = "unsafe-assert")]
228 self.assert_non_empty();
229
230 self.inner
231 }
232}
233
234#[cfg(feature = "serde")]
235mod serde {
236 #[cfg(all(not(feature = "std"), feature = "alloc"))]
237 use alloc::string::String;
238
239 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
240
241 use super::OwnedStr;
242
243 impl Serialize for OwnedStr {
244 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
245 self.as_str().serialize(serializer)
246 }
247 }
248
249 impl<'de> Deserialize<'de> for OwnedStr {
250 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
251 let string = String::deserialize(deserializer)?;
252
253 let non_empty = string.try_into().map_err(D::Error::custom)?;
254
255 Ok(non_empty)
256 }
257 }
258}