use std::error;
use std::fmt;
use std::iter;
use std::ops;
use std::ptr;
use std::str;
use std::vec;
use bstr::BStr;
use utf8::{self, Utf8Error};
pub fn concat<T, I>(
elements: I,
) -> BString
where T: AsRef<[u8]>,
I: IntoIterator<Item=T>
{
let mut dest = BString::new();
for element in elements {
dest.push(element);
}
dest
}
pub fn join<B, T, I>(
separator: B,
elements: I,
) -> BString
where B: AsRef<[u8]>,
T: AsRef<[u8]>,
I: IntoIterator<Item=T>
{
let mut it = elements.into_iter();
let mut dest = BString::new();
match it.next() {
None => return dest,
Some(first) => {
dest.push(first);
}
}
for element in it {
dest.push(&separator);
dest.push(element);
}
dest
}
#[derive(Clone, Hash)]
pub struct BString {
bytes: Vec<u8>,
}
impl BString {
pub fn new() -> BString {
BString { bytes: vec![] }
}
pub fn with_capacity(capacity: usize) -> BString {
BString { bytes: Vec::with_capacity(capacity) }
}
pub fn from_vec(bytes: Vec<u8>) -> BString {
BString { bytes }
}
pub fn from_slice<B: AsRef<[u8]>>(slice: B) -> BString {
BString::from_vec(slice.as_ref().to_vec())
}
pub fn push_byte(&mut self, byte: u8) {
self.bytes.push(byte);
}
pub fn push_char(&mut self, ch: char) {
if ch.len_utf8() == 1 {
self.bytes.push(ch as u8);
return;
}
self.bytes.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes());
}
pub fn push<B: AsRef<[u8]>>(&mut self, bytes: B) {
self.bytes.extend_from_slice(bytes.as_ref());
}
pub fn as_bstr(&self) -> &BStr {
BStr::from_bytes(&self.bytes)
}
pub fn as_vec(&self) -> &Vec<u8> {
&self.bytes
}
pub fn as_mut_bstr(&mut self) -> &mut BStr {
BStr::from_bytes_mut(&mut self.bytes)
}
pub fn as_mut_vec(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
pub fn into_vec(self) -> Vec<u8> {
self.bytes
}
pub fn into_string(self) -> Result<String, FromUtf8Error> {
match utf8::validate(self.as_bytes()) {
Err(err) => {
Err(FromUtf8Error { original: self, err: err })
}
Ok(()) => {
unsafe { Ok(self.into_string_unchecked()) }
}
}
}
pub unsafe fn into_string_unchecked(self) -> String {
String::from_utf8_unchecked(self.into_vec())
}
pub fn into_boxed_bstr(self) -> Box<BStr> {
unsafe {
let slice = self.bytes.into_boxed_slice();
Box::from_raw(Box::into_raw(slice) as *mut BStr)
}
}
pub fn capacity(&self) -> usize {
self.bytes.capacity()
}
pub fn clear(&mut self) {
self.bytes.clear();
}
pub fn reserve(&mut self, additional: usize) {
self.bytes.reserve(additional);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.bytes.reserve_exact(additional);
}
pub fn shrink_to_fit(&mut self) {
self.bytes.shrink_to_fit();
}
pub fn truncate(&mut self, new_len: usize) {
if new_len < self.len() {
self.bytes.truncate(new_len);
}
}
pub fn resize(&mut self, new_len: usize, value: u8) {
self.bytes.resize(new_len, value);
}
pub fn pop(&mut self) -> Option<char> {
let (ch, size) = utf8::decode_last_lossy(self.as_bytes());
if size == 0 {
return None;
}
let new_len = self.len() - size;
self.truncate(new_len);
Some(ch)
}
pub fn remove(&mut self, at: usize) -> char {
let (ch, size) = utf8::decode_lossy(self[at..].as_bytes());
assert!(size > 0, "expected {} to be less than {}", at, self.len());
self.bytes.drain(at..at + size);
ch
}
pub fn insert_char(&mut self, at: usize, ch: char) {
self.insert(at, ch.encode_utf8(&mut [0; 4]).as_bytes());
}
pub fn insert<B: AsRef<[u8]>>(&mut self, at: usize, bytes: B) {
assert!(at <= self.len(), "expected {} to be <= {}", at, self.len());
let bytes = bytes.as_ref();
let len = self.len();
self.reserve(bytes.len());
unsafe {
ptr::copy(
self.bytes.as_ptr().add(at),
self.bytes.as_mut_ptr().add(at + bytes.len()),
len - at,
);
ptr::copy_nonoverlapping(
bytes.as_ptr(),
self.bytes.as_mut_ptr().add(at),
bytes.len(),
);
self.bytes.set_len(len + bytes.len());
}
}
pub fn split_off(&mut self, at: usize) -> BString {
BString::from(self.bytes.split_off(at))
}
pub fn replace_range<R, B>(
&mut self,
range: R,
replace_with: B,
) where R: ops::RangeBounds<usize>,
B: AsRef<[u8]>
{
self.bytes.splice(range, replace_with.as_ref().iter().cloned());
}
pub fn drain_bytes<R>(
&mut self,
range: R,
) -> DrainBytes
where R: ops::RangeBounds<usize>
{
DrainBytes { it: self.bytes.drain(range) }
}
}
#[derive(Debug)]
pub struct DrainBytes<'a> {
it: vec::Drain<'a, u8>,
}
impl<'a> iter::FusedIterator for DrainBytes<'a> {}
impl<'a> Iterator for DrainBytes<'a> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
self.it.next()
}
}
impl<'a> DoubleEndedIterator for DrainBytes<'a> {
fn next_back(&mut self) -> Option<u8> {
self.it.next_back()
}
}
impl<'a> ExactSizeIterator for DrainBytes<'a> {
fn len(&self) -> usize {
self.it.len()
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct FromUtf8Error {
original: BString,
err: Utf8Error,
}
impl FromUtf8Error {
pub fn as_bstr(&self) -> &BStr {
&self.original
}
pub fn into_bstring(self) -> BString {
self.original
}
pub fn utf8_error(&self) -> &Utf8Error {
&self.err
}
}
impl error::Error for FromUtf8Error {
fn description(&self) -> &str { "invalid UTF-8 vector" }
}
impl fmt::Display for FromUtf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.err)
}
}
#[cfg(test)]
mod tests {
use bstr::B;
use super::*;
#[test]
fn insert() {
let mut s = BString::new();
s.insert(0, "foo");
assert_eq!("foo", s);
let mut s = BString::from("a");
s.insert(0, "foo");
assert_eq!("fooa", s);
let mut s = BString::from("a");
s.insert(1, "foo");
assert_eq!("afoo", s);
let mut s = BString::from("foobar");
s.insert(3, "quux");
assert_eq!("fooquuxbar", s);
let mut s = BString::from("foobar");
s.insert(3, "x");
assert_eq!("fooxbar", s);
let mut s = BString::from("foobar");
s.insert(0, "x");
assert_eq!("xfoobar", s);
let mut s = BString::from("foobar");
s.insert(6, "x");
assert_eq!("foobarx", s);
let mut s = BString::from("foobar");
s.insert(3, "quuxbazquux");
assert_eq!("fooquuxbazquuxbar", s);
}
#[test]
#[should_panic]
fn insert_fail1() {
let mut s = BString::new();
s.insert(1, "foo");
}
#[test]
#[should_panic]
fn insert_fail2() {
let mut s = BString::from("a");
s.insert(2, "foo");
}
#[test]
#[should_panic]
fn insert_fail3() {
let mut s = BString::from("foobar");
s.insert(7, "foo");
}
#[test]
fn collect() {
let s: BString = vec!['a', 'b', 'c'].into_iter().collect();
assert_eq!(s, "abc");
let s: BString = vec!["a", "b", "c"].into_iter().collect();
assert_eq!(s, "abc");
let s: BString = vec![B("a"), B("b"), B("c")].into_iter().collect();
assert_eq!(s, "abc");
}
}