use std::ops::{Deref, DerefMut, Drop};
use std::borrow::{Cow, Borrow};
use std::hash::{Hash, Hasher};
use ::utils::BytesExt;
pub type MaybeUtf8Owned = MaybeUtf8<String, Vec<u8>>;
pub type MaybeUtf8Slice<'a> = MaybeUtf8<&'a str, &'a [u8]>;
#[derive(Debug, Clone)]
pub enum MaybeUtf8<S, V> {
Utf8(S),
NotUtf8(V)
}
impl<S, V> MaybeUtf8<S, V> {
pub fn new() -> MaybeUtf8<S, V> where S: From<&'static str> {
MaybeUtf8::Utf8("".into())
}
pub fn as_slice<Sref: ?Sized, Vref: ?Sized>(&self) -> MaybeUtf8<&Sref, &Vref> where S: AsRef<Sref>, V: AsRef<Vref> {
match *self {
MaybeUtf8::Utf8(ref s) => MaybeUtf8::Utf8(s.as_ref()),
MaybeUtf8::NotUtf8(ref v) => MaybeUtf8::NotUtf8(v.as_ref())
}
}
pub fn as_utf8<'a>(&'a self) -> Option<&'a str> where S: AsRef<str> {
match *self {
MaybeUtf8::Utf8(ref s) => Some(s.as_ref()),
MaybeUtf8::NotUtf8(_) => None
}
}
pub fn as_utf8_lossy<'a>(&'a self) -> Cow<'a, str> where S: AsRef<str>, V: AsRef<[u8]> {
match *self {
MaybeUtf8::Utf8(ref s) => s.as_ref().into(),
MaybeUtf8::NotUtf8(ref v) => String::from_utf8_lossy(v.as_ref())
}
}
pub fn as_bytes(&self) -> &[u8] where S: AsRef<[u8]>, V: AsRef<[u8]> {
match *self {
MaybeUtf8::Utf8(ref s) => s.as_ref(),
MaybeUtf8::NotUtf8(ref v) => v.as_ref()
}
}
pub fn is_utf8(&self) -> bool {
match *self {
MaybeUtf8::Utf8(_) => true,
MaybeUtf8::NotUtf8(_) => false
}
}
}
impl MaybeUtf8<String, Vec<u8>> {
pub fn push_char(&mut self, c: char) {
match *self {
MaybeUtf8::Utf8(ref mut s) => s.push(c),
MaybeUtf8::NotUtf8(ref mut v) => {
let string: &mut String = unsafe { ::std::mem::transmute(v) };
string.push(c);
}
}
}
pub fn push_byte(&mut self, byte: u8) {
self.push_bytes(&[byte])
}
pub fn push_str(&mut self, string: &str) {
match *self {
MaybeUtf8::Utf8(ref mut s) => s.push_str(string),
MaybeUtf8::NotUtf8(ref mut v) => v.push_bytes(string.as_bytes())
}
}
pub fn push_bytes(&mut self, bytes: &[u8]) {
match ::std::str::from_utf8(bytes) {
Ok(string) => self.push_str(string),
Err(_) => {
self.as_buffer().push_bytes(bytes);
}
}
}
pub fn as_buffer(&mut self) -> Buffer {
let mut v = MaybeUtf8::NotUtf8(vec![]);
::std::mem::swap(self, &mut v);
Buffer {
bytes: v.into(),
source: self
}
}
}
impl<V> From<String> for MaybeUtf8<String, V> {
fn from(string: String) -> MaybeUtf8<String, V> {
MaybeUtf8::Utf8(string)
}
}
impl<'a, S: From<&'a str>, V> From<&'a str> for MaybeUtf8<S, V> {
fn from(string: &'a str) -> MaybeUtf8<S, V> {
MaybeUtf8::Utf8(string.into())
}
}
impl From<Vec<u8>> for MaybeUtf8<String, Vec<u8>> {
fn from(bytes: Vec<u8>) -> MaybeUtf8<String, Vec<u8>> {
match String::from_utf8(bytes) {
Ok(string) => MaybeUtf8::Utf8(string),
Err(e) => MaybeUtf8::NotUtf8(e.into_bytes())
}
}
}
impl<S: AsRef<[u8]>, V: AsRef<[u8]>> AsRef<[u8]> for MaybeUtf8<S, V> {
fn as_ref(&self) -> &[u8] {
match *self {
MaybeUtf8::Utf8(ref s) => s.as_ref(),
MaybeUtf8::NotUtf8(ref v) => v.as_ref()
}
}
}
impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Borrow<[u8]> for MaybeUtf8<S, V> {
fn borrow(&self) -> &[u8] {
self.as_ref()
}
}
impl<S, V, B: ?Sized> PartialEq<B> for MaybeUtf8<S, V> where
S: AsRef<[u8]>,
V: AsRef<[u8]>,
B: AsRef<[u8]>
{
fn eq(&self, other: &B) -> bool {
self.as_ref().eq(other.as_ref())
}
}
impl<S, V> PartialEq<MaybeUtf8<S, V>> for str where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self)
}
}
impl<'a, S, V> PartialEq<MaybeUtf8<S, V>> for &'a str where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self)
}
}
impl<S, V> PartialEq<MaybeUtf8<S, V>> for String where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self)
}
}
impl<'a, S, V> PartialEq<MaybeUtf8<S, V>> for Cow<'a, str> where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self.as_ref())
}
}
impl<S, V> PartialEq<MaybeUtf8<S, V>> for [u8] where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self)
}
}
impl<'a, S, V> PartialEq<MaybeUtf8<S, V>> for &'a [u8] where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self)
}
}
impl<S, V> PartialEq<MaybeUtf8<S, V>> for Vec<u8> where
S: AsRef<[u8]>,
V: AsRef<[u8]>
{
fn eq(&self, other: &MaybeUtf8<S, V>) -> bool {
other.eq(self)
}
}
impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Eq for MaybeUtf8<S, V> {}
impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Hash for MaybeUtf8<S, V> {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_ref().hash(hasher)
}
}
impl<S: Into<String>, V: Into<Vec<u8>>> Into<String> for MaybeUtf8<S, V> {
fn into(self) -> String {
match self {
MaybeUtf8::Utf8(s) => s.into(),
MaybeUtf8::NotUtf8(v) => {
let bytes = v.into();
match String::from_utf8_lossy(&bytes) {
Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(bytes) },
Cow::Owned(s) => s
}
}
}
}
}
impl<S: Into<Vec<u8>>, V: Into<Vec<u8>>> Into<Vec<u8>> for MaybeUtf8<S, V> {
fn into(self) -> Vec<u8> {
match self {
MaybeUtf8::Utf8(s) => s.into(),
MaybeUtf8::NotUtf8(v) => v.into()
}
}
}
impl<S: AsRef<[u8]>, V: AsRef<[u8]>> Deref for MaybeUtf8<S, V> {
type Target=[u8];
fn deref(&self) -> &[u8] {
self.as_ref()
}
}
pub struct Buffer<'a> {
bytes: Vec<u8>,
source: &'a mut MaybeUtf8<String, Vec<u8>>
}
impl<'a> Buffer<'a> {
pub fn push_bytes(&mut self, bytes: &[u8]) {
self.bytes.push_bytes(bytes)
}
pub fn push_char(&mut self, c: char) {
let string: &mut String = unsafe { ::std::mem::transmute(&mut self.bytes) };
string.push(c);
}
}
impl<'a> Deref for Buffer<'a> {
type Target = Vec<u8>;
fn deref(&self) -> &Vec<u8> {
&self.bytes
}
}
impl<'a> DerefMut for Buffer<'a> {
fn deref_mut(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
}
impl<'a> Drop for Buffer<'a> {
fn drop(&mut self) {
let mut v = vec![];
::std::mem::swap(&mut v, &mut self.bytes);
*self.source = v.into();
}
}