]>
Commit | Line | Data |
---|---|---|
b7449926 XL |
1 | use std::ffi; |
2 | use std::ops::Deref; | |
3 | ||
4 | use smallvec::SmallVec; | |
5 | ||
416331ca XL |
6 | #[cfg(test)] |
7 | mod tests; | |
8 | ||
b7449926 XL |
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 | ||
b7449926 XL |
47 | #[inline] |
48 | pub fn as_c_str(&self) -> &ffi::CStr { | |
a2a8927a | 49 | unsafe { ffi::CStr::from_bytes_with_nul_unchecked(&self.data) } |
b7449926 XL |
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 | ||
5e7ed085 | 65 | #[inline] |
b7449926 XL |
66 | fn deref(&self) -> &ffi::CStr { |
67 | self.as_c_str() | |
68 | } | |
69 | } | |
5e7ed085 FG |
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 | } |