use std::borrow::Cow;
use std::fmt;
use std::ops::{Deref, Index, RangeFull};
use std::os::raw::c_char;
use std::str;
#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
pub struct ImString(pub(crate) Vec<u8>);
impl ImString {
pub fn new<T: Into<String>>(value: T) -> ImString {
let value = value.into();
assert!(!value.contains('\0'), "ImString contained null byte");
unsafe {
let mut s = ImString::from_utf8_unchecked(value.into_bytes());
s.refresh_len();
s
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> ImString {
let mut v = Vec::with_capacity(capacity + 1);
v.push(b'\0');
ImString(v)
}
#[inline]
pub unsafe fn from_utf8_unchecked(mut v: Vec<u8>) -> ImString {
v.push(b'\0');
ImString(v)
}
#[inline]
pub unsafe fn from_utf8_with_nul_unchecked(v: Vec<u8>) -> ImString {
ImString(v)
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
self.0.push(b'\0');
}
#[inline]
pub fn push(&mut self, ch: char) {
let mut buf = [0; 4];
self.push_str(ch.encode_utf8(&mut buf));
}
#[inline]
pub fn push_str(&mut self, string: &str) {
assert!(!string.contains('\0'), "ImString contained null byte");
self.0.pop();
self.0.extend(string.bytes());
self.0.push(b'\0');
unsafe {
self.refresh_len();
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.0.capacity() - 1
}
#[inline]
pub fn capacity_with_nul(&self) -> usize {
self.0.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn reserve_exact(&mut self, additional: usize) {
self.0.reserve_exact(additional);
}
#[inline]
pub fn as_ptr(&self) -> *const c_char {
self.0.as_ptr() as *const c_char
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut c_char {
self.0.as_mut_ptr() as *mut c_char
}
pub(crate) fn ensure_buf_size(&mut self, buf_size: usize) {
if self.0.len() < buf_size {
self.0.resize(buf_size, 0);
} else if self.0.len() > buf_size {
self.0.truncate(buf_size);
if let Some(last) = self.0.last_mut() {
*last = 0;
} else {
self.0.push(0);
}
} else if let Some(last) = self.0.last_mut() {
*last = 0;
}
}
pub unsafe fn refresh_len(&mut self) {
if let Some(pos) = self.0.iter().position(|&b| b == 0) {
self.0.truncate(pos + 1);
} else {
self.0.push(0);
}
}
pub fn len(&self) -> usize {
self.0.len().saturating_sub(1)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn to_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.0[..self.len()]) }
}
}
impl Default for ImString {
fn default() -> Self {
ImString::with_capacity(0)
}
}
impl fmt::Display for ImString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.to_str(), f)
}
}
impl fmt::Debug for ImString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.to_str(), f)
}
}
impl Deref for ImString {
type Target = str;
fn deref(&self) -> &str {
self.to_str()
}
}
impl AsRef<str> for ImString {
fn as_ref(&self) -> &str {
self.to_str()
}
}
impl From<String> for ImString {
fn from(s: String) -> ImString {
ImString::new(s)
}
}
impl From<&str> for ImString {
fn from(s: &str) -> ImString {
ImString::new(s)
}
}
impl Index<RangeFull> for ImString {
type Output = str;
fn index(&self, _index: RangeFull) -> &str {
self.to_str()
}
}
pub type ImStr<'a> = Cow<'a, str>;