diff options
| author | Michael Woerister <michaelwoerister@posteo> | 2018-08-07 16:04:34 +0200 |
|---|---|---|
| committer | Michael Woerister <michaelwoerister@posteo> | 2018-08-10 11:13:00 +0200 |
| commit | 88d84b38f19eff3c25ec88931f04bf2640edf2b5 (patch) | |
| tree | 1b161e6842a4e32c29ba92332eb5b28f81d0e3ec /src/librustc_data_structures | |
| parent | 9585c5dc1fa3cef34ebdc5a5d39af88db60c6f15 (diff) | |
Introduce SmallCStr and use it where applicable.
Diffstat (limited to 'src/librustc_data_structures')
| -rw-r--r-- | src/librustc_data_structures/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc_data_structures/small_c_str.rs | 131 |
2 files changed, 132 insertions, 0 deletions
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index bd11a2977ff..8a586d8c233 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -70,6 +70,7 @@ pub mod obligation_forest; pub mod owning_ref; pub mod ptr_key; pub mod sip128; +pub mod small_c_str; pub mod small_vec; pub mod snapshot_map; pub use ena::snapshot_vec; diff --git a/src/librustc_data_structures/small_c_str.rs b/src/librustc_data_structures/small_c_str.rs new file mode 100644 index 00000000000..b0ad83e4979 --- /dev/null +++ b/src/librustc_data_structures/small_c_str.rs @@ -0,0 +1,131 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ffi; +use std::ops::Deref; + +const SIZE: usize = 38; + +/// Like SmallVec but for C strings. +#[derive(Clone)] +pub enum SmallCStr { + OnStack { + data: [u8; SIZE], + len_with_nul: u8, + }, + OnHeap { + data: ffi::CString, + } +} + +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, + } + } else { + SmallCStr::OnHeap { + data: ffi::CString::new(s).unwrap() + } + } + } + + #[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() + } + } + } + + #[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() + } + } + } +} + +impl Deref for SmallCStr { + type Target = ffi::CStr; + + fn deref(&self) -> &ffi::CStr { + self.as_c_str() + } +} + + +#[test] +fn short() { + const TEXT: &str = "abcd"; + let reference = ffi::CString::new(TEXT.to_string()).unwrap(); + + let scs = SmallCStr::new(TEXT); + + 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 }); +} + +#[test] +fn empty() { + const TEXT: &str = ""; + let reference = ffi::CString::new(TEXT.to_string()).unwrap(); + + let scs = SmallCStr::new(TEXT); + + 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 }); +} + +#[test] +fn long() { + const TEXT: &str = "01234567890123456789012345678901234567890123456789\ + 01234567890123456789012345678901234567890123456789\ + 01234567890123456789012345678901234567890123456789"; + let reference = ffi::CString::new(TEXT.to_string()).unwrap(); + + let scs = SmallCStr::new(TEXT); + + 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 }); +} + +#[test] +#[should_panic] +fn internal_nul() { + let _ = SmallCStr::new("abcd\0def"); +} |
