1 #![deny(warnings, missing_docs, missing_debug_implementations)]
2 #![doc(html_root_url = "https://docs.rs/string/0.2.1")]
3 
4 //! A UTF-8 encoded string with configurable byte storage.
5 //!
6 //! This crate provides `String`, a type similar to its std counterpart, but
7 //! with one significant difference: the underlying byte storage is
8 //! configurable. In other words, `String<T>` is a marker type wrapping `T`,
9 //! indicating that it represents a UTF-8 encoded string.
10 //!
11 //! For example, one can represent small strings (stack allocated) by wrapping
12 //! an array:
13 //!
14 //! ```
15 //! # use string::*;
16 //! let s: String<[u8; 2]> = String::try_from([b'h', b'i']).unwrap();
17 //! assert_eq!(&s[..], "hi");
18 //! ```
19 
20 #[cfg(feature = "bytes")]
21 extern crate bytes;
22 
23 use std::{borrow, fmt, hash, ops, str};
24 use std::default::Default;
25 
26 /// A UTF-8 encoded string with configurable byte storage.
27 ///
28 /// This type differs from `std::String` in that it is generic over the
29 /// underlying byte storage, enabling it to use `Vec<[u8]>`, `&[u8]`, or third
30 /// party types, such as [`Bytes`].
31 ///
32 /// In order to construct `String` via any of the non-unsafe constructors,
33 /// the backing storage needs to implement the `StableAsRef` marker trait.
34 /// If you wish to construct `String` with a type that does not implement `StableAsRef`,
35 /// you can use the `from_utf8_unchecked` constructor.
36 ///
37 /// [`Bytes`]: https://docs.rs/bytes/0.4.8/bytes/struct.Bytes.html
38 #[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
39 pub struct String<T = Vec<u8>> {
40     value: T,
41 }
42 
43 impl<T> String<T> {
44     /// Get a reference to the underlying byte storage.
45     ///
46     /// # Examples
47     ///
48     /// ```
49     /// # use string::*;
50     /// let s = String::new();
51     /// let vec = s.get_ref();
52     /// ```
get_ref(&self) -> &T53     pub fn get_ref(&self) -> &T {
54         &self.value
55     }
56 
57     /// Get a mutable reference to the underlying byte storage.
58     ///
59     /// It is inadvisable to directly manipulate the byte storage. This function
60     /// is unsafe as the bytes could no longer be valid UTF-8 after mutation.
61     ///
62     /// # Examples
63     ///
64     /// ```
65     /// # use string::*;
66     /// let mut s = String::new();
67     ///
68     /// unsafe {
69     ///     let vec = s.get_mut();
70     /// }
71     /// ```
get_mut(&mut self) -> &mut T72     pub unsafe fn get_mut(&mut self) -> &mut T {
73         &mut self.value
74     }
75 
76     /// Unwraps this `String`, returning the underlying byte storage.
77     ///
78     /// # Examples
79     ///
80     /// ```
81     /// # use string::*;
82     /// let s = String::new();
83     /// let vec = s.into_inner();
84     /// ```
into_inner(self) -> T85     pub fn into_inner(self) -> T {
86         self.value
87     }
88 
89     /// Creates a new `String` from a &str.
90     ///
91     /// Use `TryFrom` for conversion from &[u8].
92     ///
93     /// ```
94     /// # use string::*;
95     /// let _: String<Vec<u8>> = String::from_str("nice str");
96     /// ```
from_str<'a>(src: &'a str) -> String<T> where T: From<&'a [u8]> + StableAsRef,97     pub fn from_str<'a>(src: &'a str) -> String<T>
98         where T: From<&'a [u8]> + StableAsRef,
99     {
100         let value: T = src.as_bytes().into();
101         Self { value }
102     }
103 }
104 
105 impl String {
106     /// Creates a new empty `String`.
107     ///
108     /// Given that the `String` is empty, this will not allocate.
109     ///
110     /// # Examples
111     ///
112     /// Basic usage
113     ///
114     /// ```
115     /// let s = String::new();
116     /// assert_eq!(s, "");
117     /// ```
new() -> String118     pub fn new() -> String {
119         String::default()
120     }
121 }
122 
123 impl<T> String<T>
124     where T: AsRef<[u8]>,
125 {
126     /// Converts the provided value to a `String` without checking that the
127     /// given value is valid UTF-8.
128     ///
129     /// Use `TryFrom` for a safe conversion.
130     ///
131     /// # Safety
132     ///
133     /// You must ensure that:
134     ///
135     /// 1. The backing storage type `T` adheres to the contract as documented on the `StableAsRef`
136     ///    marker trait.
137     /// 2. If `T` implements `AsRef<[u8]>` and/or `AsMut<[u8]>`, the byte slice returned
138     ///    by calling `as_ref` and/or `as_mut` on the provided value represents valid utf-8.
from_utf8_unchecked(value: T) -> String<T>139     pub unsafe fn from_utf8_unchecked(value: T) -> String<T> {
140         String { value }
141     }
142 }
143 
144 impl<T> PartialEq<str> for String<T>
145     where T: AsRef<[u8]>
146 {
eq(&self, other: &str) -> bool147     fn eq(&self, other: &str) -> bool {
148         &self[..] == other
149     }
150 }
151 
152 impl<T> hash::Hash for String<T>
153     where T: AsRef<[u8]>
154 {
hash<H: hash::Hasher>(&self, state: &mut H)155     fn hash<H: hash::Hasher>(&self, state: &mut H) {
156         ops::Deref::deref(self).hash(state);
157     }
158 }
159 
160 impl<T> ops::Deref for String<T>
161     where T: AsRef<[u8]>
162 {
163     type Target = str;
164 
165     #[inline]
deref(&self) -> &str166     fn deref(&self) -> &str {
167         let b = self.value.as_ref();
168         // SAFETY: The `StableAsRef` marker trait ensures that
169         //         the impl of `AsRef<[u8]>` for `T` behaves sanely.
170         unsafe { str::from_utf8_unchecked(b) }
171     }
172 }
173 
174 impl<T> ops::DerefMut for String<T>
175     where T: AsRef<[u8]> + AsMut<[u8]>
176 {
177     #[inline]
deref_mut(&mut self) -> &mut str178     fn deref_mut(&mut self) -> &mut str {
179         let b = self.value.as_mut();
180         // SAFETY: The `StableAsRef` marker trait ensures that
181         //         the impl of `AsMut<[u8]>` for `T` behaves sanely.
182         unsafe { str::from_utf8_unchecked_mut(b) }
183     }
184 }
185 
186 impl<T> borrow::Borrow<str> for String<T>
187     where T: AsRef<[u8]>
188 {
borrow(&self) -> &str189     fn borrow(&self) -> &str {
190         &*self
191     }
192 }
193 
194 impl From<::std::string::String> for String<::std::string::String> {
from(value: ::std::string::String) -> Self195     fn from(value: ::std::string::String) -> Self {
196         String { value }
197     }
198 }
199 
200 impl<T> Default for String<T>
201     where T: Default + StableAsRef
202 {
default() -> Self203     fn default() -> Self {
204         String { value: T::default() }
205     }
206 }
207 
208 impl<T> TryFrom<T> for String<T>
209     where T: AsRef<[u8]> + StableAsRef
210 {
211     type Error = str::Utf8Error;
212 
try_from(value: T) -> Result<Self, Self::Error>213     fn try_from(value: T) -> Result<Self, Self::Error> {
214         let _ = str::from_utf8(value.as_ref())?;
215         Ok(String { value })
216     }
217 }
218 
219 impl<T: AsRef<[u8]>> fmt::Debug for String<T> {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result220     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
221         (**self).fmt(fmt)
222     }
223 }
224 
225 impl<T: AsRef<[u8]>> fmt::Display for String<T> {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result226     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
227         (**self).fmt(fmt)
228     }
229 }
230 
231 /// Attempt to construct `Self` via a conversion.
232 ///
233 /// This trait will be deprecated in favor of [std::convert::TryFrom] once it
234 /// reaches stable Rust.
235 pub trait TryFrom<T>: Sized + sealed::Sealed {
236     /// The type returned in the event of a conversion error.
237     type Error;
238 
239     /// Performs the conversion.
try_from(value: T) -> Result<Self, Self::Error>240     fn try_from(value: T) -> Result<Self, Self::Error>;
241 }
242 
243 impl<T> sealed::Sealed for String<T> {}
244 
245 mod sealed {
246     /// Private trait to this crate to prevent traits from being implemented in
247     /// downstream crates.
248     pub trait Sealed {}
249 }
250 
251 /// Marker trait that indicates that a type is guaranteed safe to use as backing storage
252 /// for `String`.
253 ///
254 /// In order to be safe, a storage type `T` needs to guarantee the following:
255 ///
256 /// - If `T` implements `AsRef<[u8]>` and/or `AsMut<[u8]>`, the contents of `T` as visible
257 ///   the byte slice returned by `as_ref` and `as_mut` may only be mutated through mutable
258 ///   references or owned access. In other words, no use of interior mutability.
259 ///
260 /// - If `T` implements `AsRef<[u8]>`, the `as_ref` method must always return the same
261 ///   slice of bytes (unless the storage is mutated).
262 ///
263 /// - If `T` implements `AsRef<[u8]>` and `AsMut<[u8]>`, the `as_mut` method must return
264 ///   a mutable reference to the same slice of bytes as the `as_ref` method returns.
265 ///
266 /// - If `T` implements `AsRef<[u8]>` and `Default`, the default value must represent the
267 ///   empty byte sequence. In other words, `T::default().as_ref().len() == 0`.
268 ///
269 /// - If `T` implements `AsRef<[u8]>` and `From<&[u8]>`, it must do so in such a way that
270 ///   the byte slice returned by `as_ref` is equal to the byte slice provided to the `from`
271 ///   method.
272 pub unsafe trait StableAsRef {}
273 
274 unsafe impl<'a, T> StableAsRef for &'a T where T: StableAsRef {}
275 unsafe impl<'a, T> StableAsRef for &'a mut T where T: StableAsRef {}
276 unsafe impl<T> StableAsRef for Box<T> where T: StableAsRef {}
277 unsafe impl<T> StableAsRef for std::rc::Rc<T> where T: StableAsRef {}
278 unsafe impl<T> StableAsRef for std::sync::Arc<T> where T: StableAsRef {}
279 
280 unsafe impl StableAsRef for std::string::String {}
281 unsafe impl StableAsRef for str {}
282 unsafe impl StableAsRef for Vec<u8> {}
283 unsafe impl StableAsRef for [u8] {}
284 
285 #[cfg(feature = "bytes")]
286 unsafe impl StableAsRef for bytes::Bytes {}
287 
288 #[cfg(feature = "bytes")]
289 unsafe impl StableAsRef for bytes::BytesMut {}
290 
291 macro_rules! array_impls {
292     ($($len:expr)+) => {
293         $(
294             unsafe impl StableAsRef for [u8; $len] {}
295         )+
296     }
297 }
298 
299 array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
300 
301 #[cfg(test)]
302 mod test {
303     use super::*;
304 
305     #[test]
test_from_std_string()306     fn test_from_std_string() {
307         let s: String<_> = "hello".to_string().into();
308         assert_eq!(&s, "hello");
309     }
310 
311     #[test]
test_from_str()312     fn test_from_str() {
313         let _: String<Vec<u8>> = String::from_str("nice str");
314     }
315 
316     #[test]
test_try_from_bytes()317     fn test_try_from_bytes() {
318         let _ = String::try_from(b"nice bytes").unwrap();
319     }
320 }
321