]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/small_c_str.rs
Merge commit 'ac0e10aa68325235069a842f47499852b2dee79e' into clippyup
[rust.git] / compiler / rustc_data_structures / src / small_c_str.rs
1 use std::ffi;
2 use std::ops::Deref;
3
4 use smallvec::SmallVec;
5
6 #[cfg(test)]
7 mod tests;
8
9 const SIZE: usize = 36;
10
11 /// Like SmallVec but for C strings.
12 #[derive(Clone)]
13 pub struct SmallCStr {
14     data: SmallVec<[u8; SIZE]>,
15 }
16
17 impl SmallCStr {
18     #[inline]
19     pub fn new(s: &str) -> SmallCStr {
20         let len = s.len();
21         let len1 = len + 1;
22         let data = if len < SIZE {
23             let mut buf = [0; SIZE];
24             buf[..len].copy_from_slice(s.as_bytes());
25             SmallVec::from_buf_and_len(buf, len1)
26         } else {
27             let mut data = Vec::with_capacity(len1);
28             data.extend_from_slice(s.as_bytes());
29             data.push(0);
30             SmallVec::from_vec(data)
31         };
32         if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
33             panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
34         }
35         SmallCStr { data }
36     }
37
38     #[inline]
39     pub fn new_with_nul(s: &str) -> SmallCStr {
40         let b = s.as_bytes();
41         if let Err(e) = ffi::CStr::from_bytes_with_nul(b) {
42             panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
43         }
44         SmallCStr { data: SmallVec::from_slice(s.as_bytes()) }
45     }
46
47     #[inline]
48     pub fn as_c_str(&self) -> &ffi::CStr {
49         unsafe { ffi::CStr::from_bytes_with_nul_unchecked(&self.data) }
50     }
51
52     #[inline]
53     pub fn len_with_nul(&self) -> usize {
54         self.data.len()
55     }
56
57     pub fn spilled(&self) -> bool {
58         self.data.spilled()
59     }
60 }
61
62 impl Deref for SmallCStr {
63     type Target = ffi::CStr;
64
65     #[inline]
66     fn deref(&self) -> &ffi::CStr {
67         self.as_c_str()
68     }
69 }
70
71 impl<'a> FromIterator<&'a str> for SmallCStr {
72     fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
73         let mut data =
74             iter.into_iter().flat_map(|s| s.as_bytes()).copied().collect::<SmallVec<_>>();
75         data.push(0);
76         if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
77             panic!("The iterator {:?} cannot be converted into a CStr: {}", data, e);
78         }
79         Self { data }
80     }
81 }