diff --git a/src/librustc_data_structures/small_c_str.rs b/src/librustc_data_structures/small_c_str.rs index b0ad83e497938..08794fbec8dc5 100644 --- a/src/librustc_data_structures/small_c_str.rs +++ b/src/librustc_data_structures/small_c_str.rs @@ -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]