non_empty_str/
boxed.rs

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