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<Str> for OwnedStr {
88 fn as_ref(&self) -> &Str {
89 self.as_str()
90 }
91}
92
93impl AsRef<str> for OwnedStr {
94 fn as_ref(&self) -> &str {
95 self.as_str().get()
96 }
97}
98
99impl FromStr for OwnedStr {
100 type Err = Empty;
101
102 fn from_str(string: &str) -> Result<Self, Self::Err> {
103 let non_empty = Str::try_from_str(string)?;
104
105 let owned = Self::from_str(non_empty);
106
107 Ok(owned)
108 }
109}
110
111impl Deref for OwnedStr {
112 type Target = Str;
113
114 fn deref(&self) -> &Self::Target {
115 self.as_str()
116 }
117}
118
119impl OwnedStr {
120 pub const fn new(string: String) -> Result<Self, EmptyOwned> {
146 if string.is_empty() {
147 return Err(EmptyOwned::new(string));
148 }
149
150 Ok(unsafe { Self::new_unchecked(string) })
152 }
153
154 #[must_use]
160 pub const unsafe fn new_unchecked(inner: String) -> Self {
161 debug_assert!(!inner.is_empty());
162
163 Self { inner }
164 }
165
166 #[cfg(feature = "unsafe-assert")]
167 const fn assert_non_empty(&self) {
168 use core::hint::assert_unchecked;
169
170 unsafe {
172 assert_unchecked(!self.inner.is_empty());
173 }
174 }
175
176 #[allow(clippy::should_implement_trait)]
190 #[must_use]
191 pub fn from_str(string: &Str) -> Self {
192 unsafe { Self::new_unchecked(string.get().to_owned()) }
194 }
195
196 #[must_use]
198 pub const fn as_str(&self) -> &Str {
199 unsafe { Str::from_str_unchecked(self.inner.as_str()) }
201 }
202
203 #[must_use]
205 pub fn get(self) -> String {
206 #[cfg(feature = "unsafe-assert")]
207 self.assert_non_empty();
208
209 self.inner
210 }
211}
212
213#[cfg(feature = "serde")]
214mod serde {
215 #[cfg(all(not(feature = "std"), feature = "alloc"))]
216 use alloc::string::String;
217
218 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
219
220 use super::OwnedStr;
221
222 impl Serialize for OwnedStr {
223 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
224 self.as_str().serialize(serializer)
225 }
226 }
227
228 impl<'de> Deserialize<'de> for OwnedStr {
229 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
230 let string = String::deserialize(deserializer)?;
231
232 let non_empty = string.try_into().map_err(D::Error::custom)?;
233
234 Ok(non_empty)
235 }
236 }
237}