Skip to main content

hipstr/string/
convert.rs

1//! Conversion trait implementations for `HipStr`.
2
3use alloc::borrow::Cow;
4use alloc::boxed::Box;
5use alloc::string::String;
6use alloc::vec::Vec;
7#[cfg(feature = "std")]
8use std::net::ToSocketAddrs;
9
10use super::HipStr;
11use crate::bytes::HipByt;
12use crate::Backend;
13
14impl<B> AsRef<str> for HipStr<'_, B>
15where
16    B: Backend,
17{
18    #[inline]
19    fn as_ref(&self) -> &str {
20        self.as_str()
21    }
22}
23
24impl<B> AsRef<[u8]> for HipStr<'_, B>
25where
26    B: Backend,
27{
28    #[inline]
29    fn as_ref(&self) -> &[u8] {
30        self.as_bytes()
31    }
32}
33
34#[cfg(feature = "std")]
35impl<B> AsRef<std::ffi::OsStr> for HipStr<'_, B>
36where
37    B: Backend,
38{
39    fn as_ref(&self) -> &std::ffi::OsStr {
40        self.as_str().as_ref()
41    }
42}
43
44#[cfg(feature = "std")]
45impl<B> AsRef<std::path::Path> for HipStr<'_, B>
46where
47    B: Backend,
48{
49    fn as_ref(&self) -> &std::path::Path {
50        self.as_str().as_ref()
51    }
52}
53
54// Infallible conversions
55
56impl<B> From<&str> for HipStr<'_, B>
57where
58    B: Backend,
59{
60    #[inline]
61    fn from(value: &str) -> Self {
62        Self(HipByt::from(value.as_bytes()))
63    }
64}
65
66impl<B> From<Box<str>> for HipStr<'_, B>
67where
68    B: Backend,
69{
70    #[inline]
71    fn from(value: Box<str>) -> Self {
72        Self(HipByt::from(value.into_boxed_bytes().into_vec()))
73    }
74}
75
76impl<B> From<String> for HipStr<'_, B>
77where
78    B: Backend,
79{
80    #[inline]
81    fn from(value: String) -> Self {
82        Self(HipByt::from(value.into_bytes()))
83    }
84}
85
86impl<'borrow, B> From<Cow<'borrow, str>> for HipStr<'borrow, B>
87where
88    B: Backend,
89{
90    #[inline]
91    fn from(value: Cow<'borrow, str>) -> Self {
92        match value {
93            Cow::Borrowed(borrow) => Self::borrowed(borrow),
94            Cow::Owned(owned) => Self::from(owned),
95        }
96    }
97}
98
99impl<B> From<HipStr<'_, B>> for String
100where
101    B: Backend,
102{
103    #[inline]
104    fn from(value: HipStr<B>) -> Self {
105        value
106            .into_string()
107            .unwrap_or_else(|value| value.as_str().into())
108    }
109}
110
111#[cfg(feature = "std")]
112impl<B> From<HipStr<'_, B>> for std::ffi::OsString
113where
114    B: Backend,
115{
116    #[inline]
117    fn from(value: HipStr<B>) -> Self {
118        value
119            .into_string()
120            .unwrap_or_else(|value| value.as_str().into())
121            .into()
122    }
123}
124
125impl<'borrow, B> From<HipStr<'borrow, B>> for HipByt<'borrow, B>
126where
127    B: Backend,
128{
129    #[inline]
130    fn from(value: HipStr<'borrow, B>) -> Self {
131        value.0
132    }
133}
134
135impl<B> From<HipStr<'_, B>> for Vec<u8>
136where
137    B: Backend,
138{
139    #[inline]
140    fn from(value: HipStr<B>) -> Self {
141        value.0.into()
142    }
143}
144
145impl<'borrow, B> From<HipStr<'borrow, B>> for Cow<'borrow, str>
146where
147    B: Backend,
148{
149    #[inline]
150    fn from(value: HipStr<'borrow, B>) -> Self {
151        value
152            .into_borrowed()
153            .map_or_else(|value| Cow::Owned(value.into()), Cow::Borrowed)
154    }
155}
156
157// Fallible conversions
158
159impl<'borrow, B> TryFrom<HipByt<'borrow, B>> for HipStr<'borrow, B>
160where
161    B: Backend,
162{
163    type Error = super::FromUtf8Error<'borrow, B>;
164
165    #[inline]
166    fn try_from(value: HipByt<'borrow, B>) -> Result<Self, Self::Error> {
167        Self::from_utf8(value)
168    }
169}
170
171impl<'borrow, B> TryFrom<&HipByt<'borrow, B>> for HipStr<'borrow, B>
172where
173    B: Backend,
174{
175    type Error = super::FromUtf8Error<'borrow, B>;
176
177    #[inline]
178    fn try_from(value: &HipByt<'borrow, B>) -> Result<Self, Self::Error> {
179        Self::from_utf8(value.clone())
180    }
181}
182
183impl<B> TryFrom<&[u8]> for HipStr<'_, B>
184where
185    B: Backend,
186{
187    type Error = core::str::Utf8Error;
188
189    #[inline]
190    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
191        Ok(Self::from(core::str::from_utf8(value)?))
192    }
193}
194
195impl<B> TryFrom<Vec<u8>> for HipStr<'_, B>
196where
197    B: Backend,
198{
199    type Error = alloc::string::FromUtf8Error;
200
201    #[inline]
202    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
203        let s = String::from_utf8(value)?;
204        Ok(Self::from(s))
205    }
206}
207
208#[cfg(feature = "std")]
209impl<B> ToSocketAddrs for HipStr<'_, B>
210where
211    B: Backend,
212{
213    type Iter = <str as ToSocketAddrs>::Iter;
214
215    fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
216        self.as_str().to_socket_addrs()
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use alloc::borrow::Cow;
223    use alloc::boxed::Box;
224    use alloc::string::String;
225    use alloc::vec::Vec;
226    use core::ptr;
227    #[cfg(feature = "std")]
228    use std::net::ToSocketAddrs;
229
230    use crate::{HipByt, HipStr};
231
232    #[test]
233    fn test_as_ref() {
234        let a = HipStr::from("abc");
235        assert!(ptr::eq(a.as_str(), a.as_ref()));
236    }
237
238    #[test]
239    fn test_from() {
240        let slice = "abcdefghijklmnopqrstuvwxyz";
241        let string = String::from(slice);
242        let ptr_string = string.as_ptr();
243        let b: Box<str> = slice.into();
244        let ptr_b = b.as_ptr();
245        let c1: Cow<str> = Cow::Borrowed(slice);
246        let c2: Cow<str> = String::from(slice).into();
247        let ptr_c2 = c2.as_ptr();
248
249        let fs = HipStr::from(slice);
250        assert_eq!(fs.as_str(), slice);
251
252        let fv = HipStr::from(string);
253        assert_eq!(fv.as_str(), slice);
254        assert!(ptr::eq(fv.as_ptr(), ptr_string));
255
256        let fv = HipStr::from(b);
257        assert_eq!(fv.as_str(), slice);
258        assert!(ptr::eq(fv.as_ptr(), ptr_b));
259
260        let fc1 = HipStr::from(c1);
261        assert_eq!(fc1.as_str(), slice);
262
263        let fc2 = HipStr::from(c2);
264        assert_eq!(fc2.as_str(), slice);
265        assert!(ptr::eq(fc2.as_ptr(), ptr_c2));
266    }
267
268    #[test]
269    fn test_into_string() {
270        let v = "a".repeat(42); // string's length > inline capacity
271        let p = v.as_ptr();
272        let a = HipStr::from(v);
273        let v: String = a.into();
274        assert_eq!(v.as_ptr(), p);
275
276        let a = HipStr::from("abc");
277        let v: String = a.into();
278        assert_eq!(v.as_str(), "abc");
279
280        let a = HipStr::borrowed("abc");
281        let v: String = a.into();
282        assert_eq!(v.as_str(), "abc");
283    }
284
285    #[test]
286    fn test_into_cow() {
287        let h = HipStr::from_static("abc");
288        let c: Cow<'static, str> = h.into();
289        assert_eq!(c, Cow::Borrowed("abc"));
290
291        let h = HipStr::from("abc");
292        let c: Cow<'static, str> = h.into();
293        assert_eq!(c, Cow::<'static, str>::Owned("abc".into()));
294    }
295
296    #[test]
297    #[cfg(feature = "std")]
298    fn into_os_string() {
299        let h = HipStr::from("abc");
300        let os_string: std::ffi::OsString = h.into();
301        assert_eq!(os_string, "abc");
302    }
303
304    #[test]
305    fn test_into_hipbyt() {
306        let v = "a".repeat(42); // string's length > inline capacity
307        let p = v.as_ptr();
308        let hs = HipStr::from(v);
309        let hb: HipByt = hs.into();
310        assert_eq!(hb, b"a".repeat(42));
311        assert_eq!(hb.as_ptr(), p);
312
313        let a = HipStr::from("abc");
314        let v: HipByt = a.into();
315        assert_eq!(v, b"abc");
316
317        let a = HipStr::borrowed("abc");
318        let v: HipByt = a.into();
319        assert_eq!(v, b"abc");
320    }
321
322    #[test]
323    fn test_into_vec() {
324        let v = "a".repeat(42); // string's length > inline capacity
325        let p = v.as_ptr();
326        let hs = HipStr::from(v);
327        let v: Vec<u8> = hs.into();
328        assert_eq!(v, b"a".repeat(42));
329        assert_eq!(v.as_ptr(), p);
330    }
331
332    #[test]
333    fn test_try_from() {
334        let slice: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
335
336        let hb = HipByt::borrowed(slice);
337        let hs: HipStr = hb.try_into().unwrap();
338        assert_eq!(hs, "abcdefghijklmnopqrstuvwxyz");
339        assert!(hs.is_borrowed());
340
341        let hb = HipByt::from(slice);
342        let hs: HipStr = hb.try_into().unwrap();
343        assert_eq!(hs, "abcdefghijklmnopqrstuvwxyz");
344
345        let hb = HipByt::borrowed(slice);
346        let hs: HipStr = (&hb).try_into().unwrap();
347        assert_eq!(hs, "abcdefghijklmnopqrstuvwxyz");
348
349        let hs: HipStr = slice.try_into().unwrap();
350        assert_eq!(hs, "abcdefghijklmnopqrstuvwxyz");
351
352        let v = b"a".repeat(42);
353        let p = v.as_ptr();
354        let hs: HipStr = v.try_into().unwrap();
355        assert_eq!(hs, "a".repeat(42));
356        assert_eq!(hs.as_ptr(), p);
357    }
358
359    #[test]
360    fn test_try_from_err() {
361        let slice: &[u8] = b"abc\x80";
362        let hb = HipByt::borrowed(slice);
363        assert!(HipStr::try_from(slice).is_err());
364        assert!(HipStr::try_from(slice.to_vec()).is_err());
365        assert!(HipStr::try_from(&hb).is_err());
366        assert!(HipStr::try_from(hb).is_err());
367    }
368
369    #[test]
370    fn as_ref_bytes() {
371        let h = HipStr::from("abc");
372        let b: &[u8] = h.as_ref();
373        assert!(ptr::eq(h.as_bytes(), b));
374    }
375
376    #[cfg(feature = "std")]
377    #[test]
378    fn as_ref_os_str() {
379        let h = HipStr::from("abc");
380        let o: &std::ffi::OsStr = h.as_ref();
381        assert_eq!(o, "abc");
382        assert!(ptr::eq(h.as_str().as_ref(), o));
383    }
384
385    #[cfg(feature = "std")]
386    #[test]
387    fn as_ref_path() {
388        let h = HipStr::from("abc");
389        let p: &std::path::Path = h.as_ref();
390        assert_eq!(p, std::path::Path::new("abc"));
391        assert!(ptr::eq(h.as_str().as_ref(), p));
392    }
393
394    #[cfg(feature = "std")]
395    #[test]
396    fn to_sock_addrs() {
397        let h = HipStr::from("0.0.0.0:80");
398        let v: Vec<_> = h.to_socket_addrs().unwrap().collect();
399        let v2: Vec<_> = "0.0.0.0:80".to_socket_addrs().unwrap().collect();
400        assert_eq!(v, v2);
401    }
402}