#![cfg_attr(feature="as-mut", feature(str_mut_extras))]
extern crate smallvec;
use std::str;
use std::ffi::OsStr;
use std::ops::Deref;
use std::borrow::Borrow;
use std::iter::{FromIterator, IntoIterator};
use smallvec::{Array, SmallVec};
#[derive(Clone, Default)]
pub struct SmallString<B: Array<Item=u8> = [u8; 8]> {
buffer: SmallVec<B>,
}
impl<B: Array<Item=u8>> std::hash::Hash for SmallString<B> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let s: &str = self;
s.hash(state)
}
}
impl<B: Array<Item=u8>> std::cmp::PartialEq for SmallString<B> {
fn eq(&self, other: &Self) -> bool {
let (s1, s2): (&str, &str) = (self, other);
s1 == s2
}
}
impl<B: Array<Item=u8>> std::cmp::Eq for SmallString<B> {}
impl<'a, B: Array<Item=u8>> PartialEq<SmallString<B>> for &'a str {
fn eq(&self, other: &SmallString<B>) -> bool {
*self == (other as &str)
}
}
impl<B: Array<Item=u8>> std::fmt::Display for SmallString<B> {
fn fmt(&self, fm: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let s: &str = SmallString::deref(self);
s.fmt(fm)
}
}
impl<B: Array<Item=u8>> std::fmt::Debug for SmallString<B> {
fn fmt(&self, fm: &mut std::fmt::Formatter) -> std::fmt::Result {
let s: &str = SmallString::deref(self);
s.fmt(fm)
}
}
impl<B: Array<Item=u8>> SmallString<B> {
pub fn from_str(s: &str) -> Self {
SmallString {
buffer: s.as_bytes().into_iter()
.cloned()
.collect(),
}
}
}
impl<'a, B: Array<Item=u8>> From<&'a str> for SmallString<B> {
fn from(s: &str) -> Self {
Self::from_str(s)
}
}
impl<B: Array<Item=u8>> Deref for SmallString<B> {
type Target = str;
fn deref(&self) -> &str {
unsafe {
str::from_utf8_unchecked(self.buffer.as_ref())
}
}
}
impl AsRef<str> for SmallString {
fn as_ref(&self) -> &str {
unsafe {
str::from_utf8_unchecked(self.buffer.as_ref())
}
}
}
struct Utf8Iterator<I>(I, Option<smallvec::IntoIter<[u8; 4]>>);
impl<I: Iterator<Item=char>> Utf8Iterator<I> {
pub fn new<In: IntoIterator<IntoIter=I, Item=char>>(into: In) -> Self {
Utf8Iterator(into.into_iter(), None)
}
}
impl<I: Iterator<Item=char>> Iterator for Utf8Iterator<I> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if let Some(mut into) = self.1.take() {
if let Some(n) = into.next() {
self.1 = Some(into);
return Some(n);
}
}
let out = self.0.next();
out.and_then(|chr| {
let mut dest = [0u8; 4];
let outstr = chr.encode_utf8(&mut dest);
self.1 = Some(
outstr.as_bytes()
.into_iter()
.cloned()
.collect::<SmallVec<[u8; 4]>>()
.into_iter()
);
self.1.as_mut().and_then(|i| i.next())
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let hint = self.0.size_hint();
(hint.0, hint.1.map(|x| x * 4))
}
}
impl FromIterator<char> for SmallString {
fn from_iter<T: IntoIterator<Item=char>>(into_iter: T) -> Self {
let utf8 = Utf8Iterator::new(into_iter);
SmallString {
buffer: utf8.collect(),
}
}
}
#[cfg(feature="as-mut")]
impl AsMut<str> for SmallString {
fn as_mut(&mut self) -> &mut str {
unsafe {
str::from_utf8_unchecked_mut(self.buffer.as_mut())
}
}
}
impl AsRef<OsStr> for SmallString {
fn as_ref(&self) -> &OsStr {
let s: &str = self.as_ref();
s.as_ref()
}
}
impl Borrow<str> for SmallString {
fn borrow(&self) -> &str {
unsafe {
str::from_utf8_unchecked(self.buffer.as_ref())
}
}
}
impl From<String> for SmallString {
fn from(s: String) -> SmallString {
SmallString {
buffer: SmallVec::from_vec(s.into_bytes()),
}
}
}
impl From<SmallString> for String {
fn from(s: SmallString) -> String {
unsafe {
String::from_utf8_unchecked(s.buffer.into_vec())
}
}
}