rustc_data_structures/
small_c_str.rs

1use std::ffi;
2use std::ops::Deref;
3
4use smallvec::SmallVec;
5
6#[cfg(test)]
7mod tests;
8
9const SIZE: usize = 36;
10
11/// Like SmallVec but for C strings.
12#[derive(Clone)]
13pub struct SmallCStr {
14    data: SmallVec<[u8; SIZE]>,
15}
16
17impl 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 \"{s}\" cannot be converted into a CStr: {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 \"{s}\" cannot be converted into a CStr: {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
62impl 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
71impl<'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 {data:?} cannot be converted into a CStr: {e}");
78        }
79        Self { data }
80    }
81}
82
83impl From<&ffi::CStr> for SmallCStr {
84    fn from(s: &ffi::CStr) -> Self {
85        Self { data: SmallVec::from_slice(s.to_bytes_with_nul()) }
86    }
87}