Use SmallVec for SmallCStr
This commit is contained in:
parent
e5284b0b57
commit
25a83e3a88
@ -11,69 +11,61 @@
|
||||
use std::ffi;
|
||||
use std::ops::Deref;
|
||||
|
||||
const SIZE: usize = 38;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
const SIZE: usize = 36;
|
||||
|
||||
/// Like SmallVec but for C strings.
|
||||
#[derive(Clone)]
|
||||
pub enum SmallCStr {
|
||||
OnStack {
|
||||
data: [u8; SIZE],
|
||||
len_with_nul: u8,
|
||||
},
|
||||
OnHeap {
|
||||
data: ffi::CString,
|
||||
}
|
||||
pub struct SmallCStr {
|
||||
data: SmallVec<[u8; SIZE]>,
|
||||
}
|
||||
|
||||
impl SmallCStr {
|
||||
#[inline]
|
||||
pub fn new(s: &str) -> SmallCStr {
|
||||
if s.len() < SIZE {
|
||||
let mut data = [0; SIZE];
|
||||
data[.. s.len()].copy_from_slice(s.as_bytes());
|
||||
let len_with_nul = s.len() + 1;
|
||||
|
||||
// Make sure once that this is a valid CStr
|
||||
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data[.. len_with_nul]) {
|
||||
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
|
||||
}
|
||||
|
||||
SmallCStr::OnStack {
|
||||
data,
|
||||
len_with_nul: len_with_nul as u8,
|
||||
}
|
||||
let len = s.len();
|
||||
let len1 = len + 1;
|
||||
let data = if len < SIZE {
|
||||
let mut buf = [0; SIZE];
|
||||
buf[..len].copy_from_slice(s.as_bytes());
|
||||
SmallVec::from_buf_and_len(buf, len1)
|
||||
} else {
|
||||
SmallCStr::OnHeap {
|
||||
data: ffi::CString::new(s).unwrap()
|
||||
}
|
||||
let mut data = Vec::with_capacity(len1);
|
||||
data.extend_from_slice(s.as_bytes());
|
||||
data.push(0);
|
||||
SmallVec::from_vec(data)
|
||||
};
|
||||
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
|
||||
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
|
||||
}
|
||||
SmallCStr { data }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_with_nul(s: &str) -> SmallCStr {
|
||||
let b = s.as_bytes();
|
||||
if let Err(e) = ffi::CStr::from_bytes_with_nul(b) {
|
||||
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
|
||||
}
|
||||
SmallCStr { data: SmallVec::from_slice(s.as_bytes()) }
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn as_c_str(&self) -> &ffi::CStr {
|
||||
match *self {
|
||||
SmallCStr::OnStack { ref data, len_with_nul } => {
|
||||
unsafe {
|
||||
let slice = &data[.. len_with_nul as usize];
|
||||
ffi::CStr::from_bytes_with_nul_unchecked(slice)
|
||||
}
|
||||
}
|
||||
SmallCStr::OnHeap { ref data } => {
|
||||
data.as_c_str()
|
||||
}
|
||||
unsafe {
|
||||
ffi::CStr::from_bytes_with_nul_unchecked(&self.data[..])
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len_with_nul(&self) -> usize {
|
||||
match *self {
|
||||
SmallCStr::OnStack { len_with_nul, .. } => {
|
||||
len_with_nul as usize
|
||||
}
|
||||
SmallCStr::OnHeap { ref data } => {
|
||||
data.as_bytes_with_nul().len()
|
||||
}
|
||||
}
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
pub fn spilled(&self) -> bool {
|
||||
self.data.spilled()
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +77,6 @@ impl Deref for SmallCStr {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn short() {
|
||||
const TEXT: &str = "abcd";
|
||||
@ -95,7 +86,7 @@ fn short() {
|
||||
|
||||
assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
|
||||
assert_eq!(scs.as_c_str(), reference.as_c_str());
|
||||
assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
|
||||
assert!(!scs.spilled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -107,7 +98,7 @@ fn empty() {
|
||||
|
||||
assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
|
||||
assert_eq!(scs.as_c_str(), reference.as_c_str());
|
||||
assert!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
|
||||
assert!(!scs.spilled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -121,7 +112,7 @@ fn long() {
|
||||
|
||||
assert_eq!(scs.len_with_nul(), TEXT.len() + 1);
|
||||
assert_eq!(scs.as_c_str(), reference.as_c_str());
|
||||
assert!(if let SmallCStr::OnHeap { .. } = scs { true } else { false });
|
||||
assert!(scs.spilled());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
x
Reference in New Issue
Block a user