Skip to main content

non_empty_str/
boxed.rs

1//! Non-empty [`Box<str>`].
2
3cfg_select! {
4    feature = "std" => {}
5    feature = "alloc" => {
6        use alloc::{boxed::Box, string::String};
7    }
8    _ => {
9        compile_error!("expected either `std` or `alloc` to be enabled");
10    }
11}
12
13use non_empty_iter::{FromNonEmptyIterator, IntoNonEmptyIterator};
14use non_empty_slice::{NonEmptyBoxedBytes, NonEmptyBytes};
15use thiserror::Error;
16
17use crate::{
18    cow::NonEmptyCowStr,
19    internals::Bytes,
20    str::NonEmptyStr,
21    string::{EmptyString, NonEmptyString},
22};
23
24/// The error message used when the boxed string is empty.
25pub const EMPTY_BOXED_STR: &str = "the boxed string is empty";
26
27/// Similar to [`EmptyString`], but contains the empty boxed string provided.
28#[derive(Debug, Error)]
29#[error("{EMPTY_BOXED_STR}")]
30pub struct EmptyBoxedStr {
31    boxed: Box<str>,
32}
33
34impl EmptyBoxedStr {
35    // NOTE: this is private to prevent creating this error with non-empty boxed strings
36    pub(crate) const fn new(boxed: Box<str>) -> Self {
37        Self { boxed }
38    }
39
40    /// Returns the contained empty boxed string.
41    #[must_use]
42    pub fn get(self) -> Box<str> {
43        self.boxed
44    }
45
46    /// Constructs [`Self`] from [`EmptyString`].
47    #[must_use]
48    pub fn from_empty_string(empty: EmptyString) -> Self {
49        Self::new(empty.get().into_boxed_str())
50    }
51
52    /// Converts [`Self`] into [`EmptyString`].
53    #[must_use]
54    pub fn into_empty_string(self) -> EmptyString {
55        EmptyString::from_empty_boxed_str(self)
56    }
57}
58
59/// Represents non-empty boxed strings, [`Box<NonEmptyStr>`].
60pub type NonEmptyBoxedStr = Box<NonEmptyStr>;
61
62impl Clone for NonEmptyBoxedStr {
63    fn clone(&self) -> Self {
64        self.to_non_empty_string().into_non_empty_boxed_str()
65    }
66}
67
68impl From<NonEmptyBoxedStr> for Box<str> {
69    fn from(boxed: NonEmptyBoxedStr) -> Self {
70        boxed.into_boxed_str()
71    }
72}
73
74impl From<NonEmptyBoxedStr> for Box<Bytes> {
75    fn from(boxed: NonEmptyBoxedStr) -> Self {
76        boxed.into_boxed_bytes()
77    }
78}
79
80impl TryFrom<Box<str>> for NonEmptyBoxedStr {
81    type Error = EmptyBoxedStr;
82
83    fn try_from(boxed: Box<str>) -> Result<Self, Self::Error> {
84        NonEmptyStr::from_boxed_str(boxed)
85    }
86}
87
88impl TryFrom<String> for NonEmptyBoxedStr {
89    type Error = EmptyString;
90
91    fn try_from(string: String) -> Result<Self, Self::Error> {
92        let non_empty_string = NonEmptyString::new(string)?;
93
94        Ok(non_empty_string.into())
95    }
96}
97
98impl From<NonEmptyBoxedStr> for NonEmptyString {
99    fn from(non_empty: NonEmptyBoxedStr) -> Self {
100        non_empty.into_non_empty_string()
101    }
102}
103
104impl From<NonEmptyString> for NonEmptyBoxedStr {
105    fn from(non_empty: NonEmptyString) -> Self {
106        non_empty.into_non_empty_boxed_str()
107    }
108}
109
110impl From<NonEmptyBoxedStr> for String {
111    fn from(non_empty: NonEmptyBoxedStr) -> Self {
112        non_empty.into_boxed_str().into_string()
113    }
114}
115
116impl From<NonEmptyBoxedStr> for NonEmptyBoxedBytes {
117    fn from(non_empty: NonEmptyBoxedStr) -> Self {
118        non_empty.into_non_empty_boxed_bytes()
119    }
120}
121
122impl NonEmptyStr {
123    /// Constructs [`Self`] from [`Box<str>`], provided the boxed string is non-empty.
124    ///
125    /// # Errors
126    ///
127    /// Returns [`EmptyBoxedStr`] if the boxed string is empty.
128    pub fn from_boxed_str(boxed: Box<str>) -> Result<Box<Self>, EmptyBoxedStr> {
129        if boxed.is_empty() {
130            return Err(EmptyBoxedStr::new(boxed));
131        }
132
133        // SAFETY: the boxed string is non-empty at this point
134        Ok(unsafe { Self::from_boxed_str_unchecked(boxed) })
135    }
136
137    /// Constructs [`Self`] from [`Box<str>`] without checking if the boxed string is non-empty.
138    ///
139    /// # Safety
140    ///
141    /// The caller must ensure that the boxed string is non-empty.
142    #[must_use]
143    pub unsafe fn from_boxed_str_unchecked(boxed: Box<str>) -> Box<Self> {
144        // SAFETY: the caller must ensure that the boxed string is non-empty
145        // moreover, `Self` is `repr(transparent)`, so it is safe to transmute
146        // finally, `Box` is created from the raw pointer existing within this function only
147        unsafe { Box::from_raw(Box::into_raw(boxed) as *mut Self) }
148    }
149
150    /// Converts [`Self`] into [`Box<str>`].
151    #[must_use]
152    pub fn into_boxed_str(self: Box<Self>) -> Box<str> {
153        // SAFETY: `Self` is `repr(transparent)`, so it is safe to transmute
154        // moreover, `Box` is created from the raw pointer existing within this function only
155        unsafe { Box::from_raw(Box::into_raw(self) as *mut str) }
156    }
157
158    /// Constructs [`Self`] from [`NonEmptyString`].
159    #[must_use]
160    pub fn from_non_empty_string(non_empty: NonEmptyString) -> Box<Self> {
161        // SAFETY: the string is non-empty by construction, so is the underlying boxed string
162        unsafe { Self::from_boxed_str_unchecked(non_empty.into_string().into_boxed_str()) }
163    }
164
165    /// Converts [`Self`] into [`NonEmptyString`].
166    #[must_use]
167    pub fn into_non_empty_string(self: Box<Self>) -> NonEmptyString {
168        NonEmptyString::from_non_empty_boxed_str(self)
169    }
170
171    /// Converts [`Self`] into [`Box<[u8]>`](Box).
172    #[must_use]
173    pub fn into_boxed_bytes(self: Box<Self>) -> Box<Bytes> {
174        self.into_boxed_str().into_boxed_bytes()
175    }
176
177    /// Converts [`Self`] into [`NonEmptyBoxedBytes`].
178    #[must_use]
179    pub fn into_non_empty_boxed_bytes(self: Box<Self>) -> NonEmptyBoxedBytes {
180        // SAFETY: the string is non-empty by construction, so are its bytes
181        unsafe { NonEmptyBytes::from_boxed_slice_unchecked(self.into_boxed_bytes()) }
182    }
183}
184
185impl NonEmptyString {
186    /// Constructs [`Self`] from [`NonEmptyBoxedStr`].
187    #[must_use]
188    pub fn from_non_empty_boxed_str(non_empty: NonEmptyBoxedStr) -> Self {
189        // SAFETY: the boxed string is non-empty by construction, so is the resulting string
190        unsafe { Self::new_unchecked(non_empty.into_boxed_str().into_string()) }
191    }
192
193    /// Converts [`Self`] into [`NonEmptyBoxedStr`].
194    #[must_use]
195    pub fn into_non_empty_boxed_str(self) -> NonEmptyBoxedStr {
196        NonEmptyStr::from_non_empty_string(self)
197    }
198
199    /// Converts [`Self`] into [`Box<str>`].
200    #[must_use]
201    pub fn into_boxed_str(self) -> Box<str> {
202        self.into_string().into_boxed_str()
203    }
204
205    /// Converts [`Self`] into [`Box<[u8]>`](Box).
206    #[must_use]
207    pub fn into_boxed_bytes(self) -> Box<Bytes> {
208        self.into_non_empty_boxed_str().into_boxed_bytes()
209    }
210
211    /// Converts [`Self`] into [`NonEmptyBoxedBytes`].
212    #[must_use]
213    pub fn into_non_empty_boxed_bytes(self) -> NonEmptyBoxedBytes {
214        self.into_non_empty_boxed_str().into_non_empty_boxed_bytes()
215    }
216}
217
218impl FromNonEmptyIterator<char> for NonEmptyBoxedStr {
219    fn from_non_empty_iter<I: IntoNonEmptyIterator<Item = char>>(iterable: I) -> Self {
220        NonEmptyString::from_non_empty_iter(iterable).into_non_empty_boxed_str()
221    }
222}
223
224impl<'c> FromNonEmptyIterator<&'c char> for NonEmptyBoxedStr {
225    fn from_non_empty_iter<I: IntoNonEmptyIterator<Item = &'c char>>(iterable: I) -> Self {
226        NonEmptyString::from_non_empty_iter(iterable).into_non_empty_boxed_str()
227    }
228}
229
230impl<'s> FromNonEmptyIterator<&'s NonEmptyStr> for NonEmptyBoxedStr {
231    fn from_non_empty_iter<I: IntoNonEmptyIterator<Item = &'s NonEmptyStr>>(iterable: I) -> Self {
232        NonEmptyString::from_non_empty_iter(iterable).into_non_empty_boxed_str()
233    }
234}
235
236impl FromNonEmptyIterator<NonEmptyString> for NonEmptyBoxedStr {
237    fn from_non_empty_iter<I: IntoNonEmptyIterator<Item = NonEmptyString>>(iterable: I) -> Self {
238        NonEmptyString::from_non_empty_iter(iterable).into_non_empty_boxed_str()
239    }
240}
241
242impl FromNonEmptyIterator<Self> for NonEmptyBoxedStr {
243    fn from_non_empty_iter<I: IntoNonEmptyIterator<Item = Self>>(iterable: I) -> Self {
244        NonEmptyString::from_non_empty_iter(iterable).into_non_empty_boxed_str()
245    }
246}
247
248impl<'s> FromNonEmptyIterator<NonEmptyCowStr<'s>> for NonEmptyBoxedStr {
249    fn from_non_empty_iter<I: IntoNonEmptyIterator<Item = NonEmptyCowStr<'s>>>(
250        iterable: I,
251    ) -> Self {
252        NonEmptyString::from_non_empty_iter(iterable).into_non_empty_boxed_str()
253    }
254}