use std::iter;
use std::io::Write;
use std::string::FromUtf8Error;
const DEFAULT_CAPACITY: usize = 1024;
const MAX_UNICODE_WIDTH: usize = 4;
#[derive(Debug)]
pub struct Builder(Vec<u8>);
impl Default for Builder {
fn default() -> Builder {
let inner = Vec::with_capacity(DEFAULT_CAPACITY);
Builder(inner)
}
}
impl Builder {
pub fn new(size: usize) -> Builder {
let inner = Vec::with_capacity(size);
Builder(inner)
}
pub fn append<T: ToBytes>(&mut self, buf: T) {
self.0.write_all(&buf.to_bytes()).unwrap()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn string(self) -> Result<String, FromUtf8Error> {
String::from_utf8(self.0)
}
}
pub trait ToBytes {
fn to_bytes(&self) -> Vec<u8>;
}
fn make_copyable_buf(len: usize) -> Vec<u8> {
iter::repeat(0).take(len).collect::<Vec<u8>>()
}
fn slice_to_vec(s: &[u8]) -> Vec<u8> {
let mut res = make_copyable_buf(s.len());
res.copy_from_slice(s);
res
}
impl ToBytes for String {
fn to_bytes(&self) -> Vec<u8> {
slice_to_vec(self.as_bytes())
}
}
impl<'a> ToBytes for &'a str {
fn to_bytes(&self) -> Vec<u8> {
slice_to_vec(self.as_bytes())
}
}
impl ToBytes for u8 {
fn to_bytes(&self) -> Vec<u8> {
vec![*self]
}
}
impl ToBytes for char {
fn to_bytes(&self) -> Vec<u8> {
let mut buf = [0; MAX_UNICODE_WIDTH];
slice_to_vec(self.encode_utf8(&mut buf).as_bytes())
}
}
impl<'a> ToBytes for &'a [u8] {
fn to_bytes(&self) -> Vec<u8> {
slice_to_vec(self)
}
}
#[cfg(test)]
mod tests {
use super::Builder;
#[test]
fn test_all_supported_types() {
let mut b = Builder::default();
b.append(String::from("hello"));
b.append(',');
b.append(b' ');
b.append("world");
b.append(" it works".as_bytes());
assert_eq!(b.string().unwrap(), "hello, world it works");
}
#[test]
fn test_individual_unicode_characters() {
let mut b = Builder::default();
b.append('‘');
b.append("starts with and ends with");
b.append('‗');
assert_eq!(b.string().unwrap(), "‘starts with and ends with‗");
}
#[test]
fn test_tool_album() {
let mut b = Builder::default();
b.append('\u{00C6}');
b.append("nima");
assert_eq!(b.string().unwrap(), "\u{00C6}nima");
}
}