string-0.2.1/.gitignore010064400007650000024000000000361350520404500132240ustar0000000000000000target/ **/*.rs.bk Cargo.lock string-0.2.1/.travis.yml010064400007650000024000000004311350520404500133440ustar0000000000000000--- language: rust sudo: false rust: - stable os: - linux matrix: include: - os: linux rust: 1.20.0 script: - cargo build --no-default-features - cargo test --no-default-features - cargo build - cargo test notifications: email: on_success: never string-0.2.1/Cargo.toml.orig010064400007650000024000000013271350520456100141320ustar0000000000000000[package] name = "string" # When releasing to crates.io: # - Update html_root_url. # - Update CHANGELOG.md. # - Update README.md. # - Update doc URL. # - Create "v0.1.x" git tag. version = "0.2.1" license = "MIT" authors = ["Carl Lerche "] description = "A UTF-8 encoded string with configurable byte storage." documentation = "https://docs.rs/string/0.2.1/string/" homepage = "https://github.com/carllerche/string" repository = "https://github.com/carllerche/string" readme = "README.md" keywords = ["string"] categories = ["data-structures"] [features] default = ["bytes"] [badges.travis-ci] repository = "carllerche/string" branch = "master" [dependencies] bytes = { version = "0.4", optional = true } string-0.2.1/Cargo.toml0000644000000021020000000000000103720ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "string" version = "0.2.1" authors = ["Carl Lerche "] description = "A UTF-8 encoded string with configurable byte storage." homepage = "https://github.com/carllerche/string" documentation = "https://docs.rs/string/0.2.1/string/" readme = "README.md" keywords = ["string"] categories = ["data-structures"] license = "MIT" repository = "https://github.com/carllerche/string" [dependencies.bytes] version = "0.4" optional = true [features] default = ["bytes"] [badges.travis-ci] branch = "master" repository = "carllerche/string" string-0.2.1/CHANGELOG.md010064400007650000024000000006741350520456100130600ustar0000000000000000# 0.2.1 (June 27, 2019) ### Fixed - Stack overflow on `PartialEq` (#15). # 0.2.0 (March 6, 2019) ### Changed - Require byte store to implement `StableAsRef` (#10). # 0.1.3 (January 10, 2019) * Implement `Borrow`. * Implement `PartialEq`. # 0.1.2 (November 21, 2018) * Implement `DerefMut` and `Display` (#5). * Implement `from_str` (#7). # 0.1.1 (July 13, 2018) * Fix doc gen (#2). # 0.1.0 (January 11, 2018) * Initial release. string-0.2.1/LICENSE010064400007650000024000000020371350520404500122440ustar0000000000000000Copyright (c) 2019 Carl Lerche Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. string-0.2.1/README.md010064400007650000024000000015231350520456100125200ustar0000000000000000# String A UTF-8 encoded string with configurable byte storage. [![Build Status](https://travis-ci.org/carllerche/string.svg?branch=master)](https://travis-ci.org/carllerche/string) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Crates.io](https://img.shields.io/crates/v/string.svg?maxAge=2592000)](https://crates.io/crates/string) [![Documentation](https://docs.rs/string/badge.svg)](https://docs.rs/string/0.2.1/string/) ## Usage To use `string`, first add this to your `Cargo.toml`: ```toml [dependencies] string = "0.2.1" ``` Next, add this to your crate: ```rust extern crate string; use string::{String, TryFrom}; let s: String<[u8; 2]> = String::try_from([b'h', b'i']).unwrap(); assert_eq!(&s[..], "hi"); ``` See [documentation](https://docs.rs/string) for more details. string-0.2.1/src/lib.rs010064400007650000024000000214421350520456100131460ustar0000000000000000#![deny(warnings, missing_docs, missing_debug_implementations)] #![doc(html_root_url = "https://docs.rs/string/0.2.1")] //! 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` 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"); //! ``` #[cfg(feature = "bytes")] extern crate bytes; use std::{borrow, fmt, hash, ops, str}; use std::default::Default; /// 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`]. /// /// In order to construct `String` via any of the non-unsafe constructors, /// the backing storage needs to implement the `StableAsRef` marker trait. /// If you wish to construct `String` with a type that does not implement `StableAsRef`, /// you can use the `from_utf8_unchecked` constructor. /// /// [`Bytes`]: https://docs.rs/bytes/0.4.8/bytes/struct.Bytes.html #[derive(Clone, Eq, PartialEq, Ord, PartialOrd)] pub struct String> { value: T, } impl String { /// 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> = String::from_str("nice str"); /// ``` pub fn from_str<'a>(src: &'a str) -> String where T: From<&'a [u8]> + StableAsRef, { 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 String 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. /// /// # Safety /// /// You must ensure that: /// /// 1. The backing storage type `T` adheres to the contract as documented on the `StableAsRef` /// marker trait. /// 2. If `T` implements `AsRef<[u8]>` and/or `AsMut<[u8]>`, the byte slice returned /// by calling `as_ref` and/or `as_mut` on the provided value represents valid utf-8. pub unsafe fn from_utf8_unchecked(value: T) -> String { String { value } } } impl PartialEq for String where T: AsRef<[u8]> { fn eq(&self, other: &str) -> bool { &self[..] == other } } impl hash::Hash for String where T: AsRef<[u8]> { fn hash(&self, state: &mut H) { ops::Deref::deref(self).hash(state); } } impl ops::Deref for String where T: AsRef<[u8]> { type Target = str; #[inline] fn deref(&self) -> &str { let b = self.value.as_ref(); // SAFETY: The `StableAsRef` marker trait ensures that // the impl of `AsRef<[u8]>` for `T` behaves sanely. unsafe { str::from_utf8_unchecked(b) } } } impl ops::DerefMut for String where T: AsRef<[u8]> + AsMut<[u8]> { #[inline] fn deref_mut(&mut self) -> &mut str { let b = self.value.as_mut(); // SAFETY: The `StableAsRef` marker trait ensures that // the impl of `AsMut<[u8]>` for `T` behaves sanely. unsafe { str::from_utf8_unchecked_mut(b) } } } impl borrow::Borrow for String where T: AsRef<[u8]> { fn borrow(&self) -> &str { &*self } } impl From<::std::string::String> for String<::std::string::String> { fn from(value: ::std::string::String) -> Self { String { value } } } impl Default for String where T: Default + StableAsRef { fn default() -> Self { String { value: T::default() } } } impl TryFrom for String where T: AsRef<[u8]> + StableAsRef { type Error = str::Utf8Error; fn try_from(value: T) -> Result { let _ = str::from_utf8(value.as_ref())?; Ok(String { value }) } } impl> fmt::Debug for String { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(fmt) } } impl> fmt::Display for String { 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: Sized + sealed::Sealed { /// The type returned in the event of a conversion error. type Error; /// Performs the conversion. fn try_from(value: T) -> Result; } impl sealed::Sealed for String {} mod sealed { /// Private trait to this crate to prevent traits from being implemented in /// downstream crates. pub trait Sealed {} } /// Marker trait that indicates that a type is guaranteed safe to use as backing storage /// for `String`. /// /// In order to be safe, a storage type `T` needs to guarantee the following: /// /// - If `T` implements `AsRef<[u8]>` and/or `AsMut<[u8]>`, the contents of `T` as visible /// the byte slice returned by `as_ref` and `as_mut` may only be mutated through mutable /// references or owned access. In other words, no use of interior mutability. /// /// - If `T` implements `AsRef<[u8]>`, the `as_ref` method must always return the same /// slice of bytes (unless the storage is mutated). /// /// - If `T` implements `AsRef<[u8]>` and `AsMut<[u8]>`, the `as_mut` method must return /// a mutable reference to the same slice of bytes as the `as_ref` method returns. /// /// - If `T` implements `AsRef<[u8]>` and `Default`, the default value must represent the /// empty byte sequence. In other words, `T::default().as_ref().len() == 0`. /// /// - If `T` implements `AsRef<[u8]>` and `From<&[u8]>`, it must do so in such a way that /// the byte slice returned by `as_ref` is equal to the byte slice provided to the `from` /// method. pub unsafe trait StableAsRef {} unsafe impl<'a, T> StableAsRef for &'a T where T: StableAsRef {} unsafe impl<'a, T> StableAsRef for &'a mut T where T: StableAsRef {} unsafe impl StableAsRef for Box where T: StableAsRef {} unsafe impl StableAsRef for std::rc::Rc where T: StableAsRef {} unsafe impl StableAsRef for std::sync::Arc where T: StableAsRef {} unsafe impl StableAsRef for std::string::String {} unsafe impl StableAsRef for str {} unsafe impl StableAsRef for Vec {} unsafe impl StableAsRef for [u8] {} #[cfg(feature = "bytes")] unsafe impl StableAsRef for bytes::Bytes {} #[cfg(feature = "bytes")] unsafe impl StableAsRef for bytes::BytesMut {} macro_rules! array_impls { ($($len:expr)+) => { $( unsafe impl StableAsRef for [u8; $len] {} )+ } } array_impls!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16); #[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> = String::from_str("nice str"); } #[test] fn test_try_from_bytes() { let _ = String::try_from(b"nice bytes").unwrap(); } } string-0.2.1/.cargo_vcs_info.json0000644000000001120000000000000123730ustar00{ "git": { "sha1": "d0b7eb735c4fcf2ef070b3b863cf6ade96e9b348" } }