use std::fmt;
use std::io::Write;
use std::mem::transmute;
use std::ops;
use std::ptr;
use std::str;
#[derive(Clone, Copy, Default)]
pub struct StringWrapper<T> where T: Buffer {
len: usize,
buffer: T,
}
pub unsafe trait Buffer {
fn as_ref(&self) -> &[u8];
fn as_mut(&mut self) -> &mut [u8];
}
impl<T> StringWrapper<T> where T: Buffer {
pub fn new(buffer: T) -> Self {
StringWrapper {
len: 0,
buffer: buffer,
}
}
pub unsafe fn from_raw_parts(buffer: T, len: usize) -> Self {
StringWrapper {
len: len,
buffer: buffer,
}
}
pub fn into_buffer(self) -> T {
self.buffer
}
pub fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
pub unsafe fn buffer_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut()
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub unsafe fn set_len(&mut self, new_len: usize) {
self.len = new_len
}
pub fn truncate(&mut self, new_len: usize) {
assert!(new_len <= self.len);
if new_len < self.len {
assert!(starts_well_formed_utf8_sequence(self.buffer.as_ref()[new_len]));
}
self.len = new_len;
}
pub fn capacity(&self) -> usize {
self.buffer.as_ref().len()
}
pub fn extra_capacity(&self) -> usize {
self.capacity() - self.len
}
pub fn extra_bytes_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[self.len..]
}
pub fn push(&mut self, c: char) -> Result<(), ()> {
let new_len = self.len + c.len_utf8();
if new_len <= self.capacity() {
write!(self.extra_bytes_mut(), "{}", c).unwrap();
self.len = new_len;
Ok(())
} else {
Err(())
}
}
pub fn push_str(&mut self, s: &str) {
copy_memory(s.as_bytes(), self.extra_bytes_mut());
self.len += s.len();
}
pub fn push_partial_str(&mut self, s: &str) -> Result<(), usize> {
let mut i = self.extra_capacity();
let (s, result) = if i < s.len() {
while !starts_well_formed_utf8_sequence(s.as_bytes()[i]) {
i -= 1
}
(&s[..i], Err(i))
} else {
(s, Ok(()))
};
self.push_str(s);
result
}
}
fn starts_well_formed_utf8_sequence(byte: u8) -> bool {
byte < 128 || byte >= 192
}
fn copy_memory(src: &[u8], dst: &mut [u8]) {
let len_src = src.len();
assert!(dst.len() >= len_src);
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(),
dst.as_mut_ptr(),
len_src);
}
}
impl<T> ops::Deref for StringWrapper<T> where T: Buffer {
type Target = str;
fn deref(&self) -> &str {
unsafe {
str::from_utf8_unchecked(&self.buffer.as_ref()[..self.len])
}
}
}
impl<T> ops::DerefMut for StringWrapper<T> where T: Buffer {
fn deref_mut(&mut self) -> &mut str {
unsafe {
transmute::<&mut [u8], &mut str>(&mut self.buffer.as_mut()[..self.len])
}
}
}
impl<T> fmt::Display for StringWrapper<T> where T: Buffer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<T> fmt::Debug for StringWrapper<T> where T: Buffer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
unsafe impl<'a, T: ?Sized + Buffer> Buffer for &'a mut T {
fn as_ref(&self) -> &[u8] { (**self).as_ref() }
fn as_mut(&mut self) -> &mut [u8] { (**self).as_mut() }
}
unsafe impl<'a, T: ?Sized + Buffer> Buffer for Box<T> {
fn as_ref(&self) -> &[u8] { (**self).as_ref() }
fn as_mut(&mut self) -> &mut [u8] { (**self).as_mut() }
}
unsafe impl Buffer for Vec<u8> {
fn as_ref(&self) -> &[u8] { self }
fn as_mut(&mut self) -> &mut [u8] { self }
}
unsafe impl Buffer for [u8] {
fn as_ref(&self) -> &[u8] { self }
fn as_mut(&mut self) -> &mut [u8] { self }
}
macro_rules! array_impl {
($($N: expr)+) => {
$(
unsafe impl Buffer for [u8; $N] {
fn as_ref(&self) -> &[u8] { self }
fn as_mut(&mut self) -> &mut [u8] { self }
}
)+
}
}
array_impl! {
0 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
64 128 256 512 1024
2 * 1024
4 * 1024
8 * 1024
16 * 1024
32 * 1024
64 * 1024
128 * 1024
256 * 1024
512 * 1024
1024 * 1024
2 * 1024 * 1024
4 * 1024 * 1024
8 * 1024 * 1024
16 * 1024 * 1024
32 * 1024 * 1024
64 * 1024 * 1024
128 * 1024 * 1024
256 * 1024 * 1024
512 * 1024 * 1024
1024 * 1024 * 1024
100 1_000 10_000 100_000 1_000_000
10_000_000 100_000_000 1_000_000_000
}
#[test]
fn it_works() {
let mut s = StringWrapper::new([0; 10]);
assert_eq!(&*s, "");
assert_eq!(s.len(), 0);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 10);
assert_eq!(&*s, "");
assert_eq!(s.len(), 0);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 10);
s.push_str("a");
assert_eq!(&*s, "a");
assert_eq!(s.len(), 1);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 9);
assert_eq!(s.push('é'), Ok(()));
assert_eq!(&*s, "aé");
assert_eq!(s.len(), 3);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 7);
assert_eq!(s.push_partial_str("~~~"), Ok(()));
assert_eq!(&*s, "aé~~~");
assert_eq!(s.len(), 6);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 4);
assert_eq!(s.push_partial_str("hello"), Err(4));
assert_eq!(&*s, "aé~~~hell");
assert_eq!(s.len(), 10);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 0);
s.truncate(6);
assert_eq!(&*s, "aé~~~");
assert_eq!(s.len(), 6);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 4);
s.truncate(8);
assert_eq!(&*s, "aé~~~");
assert_eq!(s.len(), 6);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 4);
assert_eq!(s.push_partial_str("_🌠"), Err(1));
assert_eq!(&*s, "aé~~~_");
assert_eq!(s.len(), 7);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 3);
assert_eq!(s.push('🌠'), Err(()));
assert_eq!(&*s, "aé~~~_");
assert_eq!(s.len(), 7);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 3);
let buffer: [u8; 10] = s.clone().into_buffer();
assert_eq!(&buffer, b"a\xC3\xA9~~~_ell");
assert_eq!(format!("{}", s), "aé~~~_");
assert_eq!(format!("{:?}", s), r#""a\u{e9}~~~_""#);
assert_eq!(s.push_partial_str("ô!?"), Err(3));
assert_eq!(&*s, "aé~~~_ô!");
assert_eq!(s.len(), 10);
assert_eq!(s.capacity(), 10);
assert_eq!(s.extra_capacity(), 0);
}