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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
#![deny(warnings, missing_docs, missing_debug_implementations)]
#![doc(html_root_url = "https://docs.rs/string/0.1.2")]
//! A UTF-8 encoded string with configurable byte storage.
//!
//! This crate provides `String`, a type similar to its std counterpart, but
//! with one significant difference: the underlying byte storage is
//! configurable. In other words, `String<T>` is a marker type wrapping `T`,
//! indicating that it represents a UTF-8 encoded string.
//!
//! For example, one can represent small strings (stack allocated) by wrapping
//! an array:
//!
//! ```
//! # use string::*;
//! let s: String<[u8; 2]> = String::try_from([b'h', b'i']).unwrap();
//! assert_eq!(&s[..], "hi");
//! ```
use std::{fmt, ops, str};
/// A UTF-8 encoded string with configurable byte storage.
///
/// This type differs from `std::String` in that it is generic over the
/// underlying byte storage, enabling it to use `Vec<[u8]>`, `&[u8]`, or third
/// party types, such as [`Bytes`].
///
/// [`Bytes`]: https://docs.rs/bytes/0.4.8/bytes/struct.Bytes.html
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct String<T = Vec<u8>> {
value: T,
}
impl<T> String<T> {
/// Get a reference to the underlying byte storage.
///
/// # Examples
///
/// ```
/// # use string::*;
/// let s = String::new();
/// let vec = s.get_ref();
/// ```
pub fn get_ref(&self) -> &T {
&self.value
}
/// Get a mutable reference to the underlying byte storage.
///
/// It is inadvisable to directly manipulate the byte storage. This function
/// is unsafe as the bytes could no longer be valid UTF-8 after mutation.
///
/// # Examples
///
/// ```
/// # use string::*;
/// let mut s = String::new();
///
/// unsafe {
/// let vec = s.get_mut();
/// }
/// ```
pub unsafe fn get_mut(&mut self) -> &mut T {
&mut self.value
}
/// Unwraps this `String`, returning the underlying byte storage.
///
/// # Examples
///
/// ```
/// # use string::*;
/// let s = String::new();
/// let vec = s.into_inner();
/// ```
pub fn into_inner(self) -> T {
self.value
}
/// Creates a new `String` from a &str.
///
/// Use `TryFrom` for conversion from &[u8].
///
/// ```
/// # use string::*;
/// let _: String<Vec<u8>> = String::from_str("nice str");
/// ```
pub fn from_str<'a>(src: &'a str) -> String<T>
where T: From<&'a [u8]>,
{
let value: T = src.as_bytes().into();
Self { value }
}
}
impl String {
/// Creates a new empty `String`.
///
/// Given that the `String` is empty, this will not allocate.
///
/// # Examples
///
/// Basic usage
///
/// ```
/// let s = String::new();
/// assert_eq!(s, "");
/// ```
pub fn new() -> String {
String::default()
}
}
impl<T> String<T>
where T: AsRef<[u8]>,
{
/// Converts the provided value to a `String` without checking that the
/// given value is valid UTF-8.
///
/// Use `TryFrom` for a safe conversion.
pub unsafe fn from_utf8_unchecked(value: T) -> String<T> {
String { value }
}
}
impl<T> ops::Deref for String<T>
where T: AsRef<[u8]>
{
type Target = str;
#[inline]
fn deref(&self) -> &str {
let b = self.value.as_ref();
unsafe { str::from_utf8_unchecked(b) }
}
}
impl<T> ops::DerefMut for String<T>
where T: AsRef<[u8]> + AsMut<[u8]>
{
#[inline]
fn deref_mut(&mut self) -> &mut str {
let b = self.value.as_mut();
unsafe { str::from_utf8_unchecked_mut(b) }
}
}
impl From<::std::string::String> for String<::std::string::String> {
fn from(value: ::std::string::String) -> Self {
String { value }
}
}
impl<'a> From<&'a str> for String<&'a str> {
fn from(value: &'a str) -> Self {
String { value }
}
}
impl<T> TryFrom<T> for String<T>
where T: AsRef<[u8]>
{
type Error = str::Utf8Error;
fn try_from(value: T) -> Result<Self, Self::Error> {
let _ = str::from_utf8(value.as_ref())?;
Ok(String { value })
}
}
impl<T: AsRef<[u8]>> fmt::Debug for String<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(fmt)
}
}
impl<T: AsRef<[u8]>> fmt::Display for String<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(fmt)
}
}
/// Attempt to construct `Self` via a conversion.
///
/// This trait will be deprecated in favor of [std::convert::TryFrom] once it
/// reaches stable Rust.
pub trait TryFrom<T>: Sized + sealed::Sealed {
/// The type returned in the event of a conversion error.
type Error;
/// Performs the conversion.
fn try_from(value: T) -> Result<Self, Self::Error>;
}
impl<T> sealed::Sealed for String<T> {}
mod sealed {
/// Private trait to this crate to prevent traits from being implemented in
/// downstream crates.
pub trait Sealed {}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_from_std_string() {
let s: String<_> = "hello".to_string().into();
assert_eq!(&s[..], "hello");
}
#[test]
fn test_from_str() {
let _: String<Vec<u8>> = String::from_str("nice str");
}
#[test]
fn test_try_from_bytes() {
let _ = String::try_from(b"nice bytes").unwrap();
}
}