detached_str/
lib.rs

1//! A crate for borrowing strings without a lifetime.
2//!
3//! ## Example
4//!
5//! ```
6//! use detached_str::{Str, StrSlice};
7//!
8//! let string: Str = "Hello, world!".into();
9//! let slice: StrSlice = string.get(7..);
10//! assert_eq!(slice.to_str(&string), "world!");
11//! ```
12//!
13//! A `StrSlice` is "detached", i.e. the string content can only be accessed
14//! when you have a reference to the owned string. The owned string is immutable
15//! to ensure that string slices remain valid.
16
17use std::borrow::Cow;
18use std::fmt;
19use std::iter::FromIterator;
20use std::ops::Deref;
21use std::path::PathBuf;
22
23mod slice;
24#[cfg(test)]
25mod tests;
26
27pub use slice::{StrSlice, StrSliceIndex};
28
29/// An immutable string. It dereferences to a `&str` and can also be borrowed as
30/// a [`StrSlice`].
31#[derive(Clone, PartialEq, Eq, Default, Hash, PartialOrd, Ord)]
32pub struct Str(Box<str>);
33
34impl Str {
35    pub fn get<T>(&self, index: T) -> StrSlice
36    where
37        StrSlice: StrSliceIndex<T>,
38    {
39        StrSlice::new(0..self.len()).index(index)
40    }
41}
42
43impl From<String> for Str {
44    fn from(s: String) -> Self {
45        Str(s.into_boxed_str())
46    }
47}
48
49impl<'a> From<&'a str> for Str {
50    fn from(s: &'a str) -> Self {
51        Str(s.to_string().into_boxed_str())
52    }
53}
54
55impl<'a> From<Cow<'a, str>> for Str {
56    fn from(s: Cow<'a, str>) -> Self {
57        Str(s.to_string().into_boxed_str())
58    }
59}
60
61impl FromIterator<char> for Str {
62    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
63        let s: String = iter.into_iter().collect();
64        s.into()
65    }
66}
67
68impl<'a> FromIterator<&'a str> for Str {
69    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
70        let s: String = iter.into_iter().collect();
71        s.into()
72    }
73}
74
75impl FromIterator<String> for Str {
76    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
77        let s: String = iter.into_iter().collect();
78        s.into()
79    }
80}
81
82impl From<Str> for Box<str> {
83    fn from(s: Str) -> Self {
84        s.0
85    }
86}
87
88impl From<Str> for String {
89    fn from(s: Str) -> Self {
90        s.0.into()
91    }
92}
93
94impl From<Str> for Cow<'_, str> {
95    fn from(s: Str) -> Self {
96        Cow::Owned(s.0.into())
97    }
98}
99
100impl From<Str> for PathBuf {
101    fn from(s: Str) -> Self {
102        s.0.to_string().into()
103    }
104}
105
106impl AsRef<str> for Str {
107    fn as_ref(&self) -> &str {
108        self.0.as_ref()
109    }
110}
111
112impl fmt::Debug for Str {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        fmt::Debug::fmt(&self.0, f)
115    }
116}
117
118impl fmt::Display for Str {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        fmt::Display::fmt(&self.0, f)
121    }
122}
123
124impl Deref for Str {
125    type Target = str;
126
127    fn deref(&self) -> &Self::Target {
128        &self.0
129    }
130}