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()
}
}
}
}
-
#[test]
fn short() {
const TEXT: &str = "abcd";
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]
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]
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]