1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! A crate for borrowing strings without a lifetime.
//!
//! ## Example
//!
//! ```
//! use detached_str::{Str, StrSlice};
//!
//! let string: Str = "Hello, world!".into();
//! let slice: StrSlice = string.get(7..);
//! assert_eq!(slice.to_str(&string), "world!");
//! ```
//!
//! A `StrSlice` is "detached", i.e. the string content can only be accessed
//! when you have a reference to the owned string. The owned string is immutable
//! to ensure that string slices remain valid.

use std::borrow::Cow;
use std::fmt;
use std::iter::FromIterator;
use std::ops::Deref;
use std::path::PathBuf;

mod slice;
#[cfg(test)]
mod tests;

pub use slice::{StrSlice, StrSliceIndex};

/// An immutable string. It dereferences to a `&str` and can also be borrowed as
/// a [`StrSlice`].
#[derive(Clone, PartialEq, Eq, Default, Hash, PartialOrd, Ord)]
pub struct Str(Box<str>);

impl Str {
    pub fn get<T>(&self, index: T) -> StrSlice
    where
        StrSlice: StrSliceIndex<T>,
    {
        StrSlice::new(0..self.len()).index(index)
    }
}

impl From<String> for Str {
    fn from(s: String) -> Self {
        Str(s.into_boxed_str())
    }
}

impl<'a> From<&'a str> for Str {
    fn from(s: &'a str) -> Self {
        Str(s.to_string().into_boxed_str())
    }
}

impl<'a> From<Cow<'a, str>> for Str {
    fn from(s: Cow<'a, str>) -> Self {
        Str(s.to_string().into_boxed_str())
    }
}

impl FromIterator<char> for Str {
    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
        let s: String = iter.into_iter().collect();
        s.into()
    }
}

impl<'a> FromIterator<&'a str> for Str {
    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
        let s: String = iter.into_iter().collect();
        s.into()
    }
}

impl FromIterator<String> for Str {
    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
        let s: String = iter.into_iter().collect();
        s.into()
    }
}

impl From<Str> for Box<str> {
    fn from(s: Str) -> Self {
        s.0
    }
}

impl From<Str> for String {
    fn from(s: Str) -> Self {
        s.0.into()
    }
}

impl From<Str> for Cow<'_, str> {
    fn from(s: Str) -> Self {
        Cow::Owned(s.0.into())
    }
}

impl From<Str> for PathBuf {
    fn from(s: Str) -> Self {
        s.0.to_string().into()
    }
}

impl AsRef<str> for Str {
    fn as_ref(&self) -> &str {
        self.0.as_ref()
    }
}

impl fmt::Debug for Str {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl fmt::Display for Str {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl Deref for Str {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}