tomsg_rs/
line.rs

1use std::borrow::{Borrow, Cow};
2use std::convert::TryFrom;
3use std::fmt;
4use std::mem;
5use std::ops::Deref;
6
7/// A `Line` is a `str` which does not contain newlines.
8///
9/// You can obtain a `Line` by calling `try_from`:
10/// ```
11/// use tomsg_rs::Line;
12/// use std::convert::TryFrom;
13///
14/// let valid = "this is a valid line";
15/// let invalid = "this is not\na valid line";
16///
17/// assert!(<&Line>::try_from(valid).is_ok());
18/// assert!(<&Line>::try_from(invalid).is_err());
19/// ```
20#[repr(transparent)]
21#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct Line(str);
23
24impl Line {
25    /// Create an `Word` from the given `val`.
26    ///
27    /// # Safety
28    /// This function is `unsafe` because the `val` is not checked on conformity, only use this
29    /// function if you're sure that the given `val` does not contain spaces or newlines.
30    #[must_use]
31    pub unsafe fn from_str_unchecked(val: &str) -> &Self {
32        mem::transmute(val)
33    }
34
35    /// Create an `Line` from the given `val`.
36    ///
37    /// # Safety
38    /// This function is `unsafe` because the `val` is not checked on conformity, only use this
39    /// function if you're sure that the given `val` does not contain newlines.
40    #[must_use]
41    pub unsafe fn from_string_unchecked(val: String) -> Box<Self> {
42        let s: Box<str> = val.into_boxed_str();
43        mem::transmute(s)
44    }
45
46    /// Extracts a string slice containing the contents of the `Line`.
47    #[must_use]
48    pub fn as_str(&self) -> &str {
49        &self.0
50    }
51
52    /// Converts this `Box<Line>` into a `String`.
53    #[must_use]
54    pub fn into_string(self: Box<Self>) -> String {
55        let s: Box<str> = unsafe { mem::transmute(self) };
56        String::from(s)
57    }
58}
59
60impl fmt::Display for Line {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        write!(f, "{}", &self.0)
63    }
64}
65
66impl From<Box<Line>> for Cow<'_, Line> {
67    fn from(line: Box<Line>) -> Self {
68        Self::Owned(line)
69    }
70}
71impl<'a> From<&'a Line> for Cow<'a, Line> {
72    fn from(line: &'a Line) -> Self {
73        Self::Borrowed(line)
74    }
75}
76
77impl TryFrom<String> for Box<Line> {
78    type Error = &'static str;
79
80    fn try_from(val: String) -> Result<Self, Self::Error> {
81        if val.contains('\n') {
82            Err("string contains newlines")
83        } else {
84            Ok(unsafe { Line::from_string_unchecked(val) })
85        }
86    }
87}
88
89impl<'a> TryFrom<&'a str> for &'a Line {
90    type Error = &'static str;
91
92    fn try_from(val: &'a str) -> Result<Self, Self::Error> {
93        if val.contains('\n') {
94            Err("string contains newlines")
95        } else {
96            Ok(unsafe { Line::from_str_unchecked(val) })
97        }
98    }
99}
100
101impl Borrow<str> for Line {
102    fn borrow(&self) -> &str {
103        self.as_str()
104    }
105}
106
107impl Deref for Line {
108    type Target = str;
109
110    fn deref(&self) -> &Self::Target {
111        &self.0
112    }
113}
114
115impl ToOwned for Line {
116    type Owned = Box<Line>;
117
118    fn to_owned(&self) -> Self::Owned {
119        unsafe { Self::from_string_unchecked(self.0.to_owned()) }
120    }
121}
122
123impl Clone for Box<Line> {
124    fn clone(&self) -> Self {
125        (**self).to_owned()
126    }
127}