2018-08-07 16:04:34 +02:00
|
|
|
use std::ffi;
|
|
|
|
use std::ops::Deref;
|
|
|
|
|
2018-08-23 20:22:22 +02:00
|
|
|
use smallvec::SmallVec;
|
|
|
|
|
2019-08-01 23:57:23 +03:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2018-08-23 20:22:22 +02:00
|
|
|
const SIZE: usize = 36;
|
2018-08-07 16:04:34 +02:00
|
|
|
|
|
|
|
/// Like SmallVec but for C strings.
|
|
|
|
#[derive(Clone)]
|
2018-08-23 20:22:22 +02:00
|
|
|
pub struct SmallCStr {
|
|
|
|
data: SmallVec<[u8; SIZE]>,
|
2018-08-07 16:04:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SmallCStr {
|
|
|
|
#[inline]
|
|
|
|
pub fn new(s: &str) -> SmallCStr {
|
2018-08-23 20:22:22 +02:00
|
|
|
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)
|
2018-08-07 16:04:34 +02:00
|
|
|
} else {
|
2018-08-23 20:22:22 +02:00
|
|
|
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);
|
2018-08-07 16:04:34 +02:00
|
|
|
}
|
2018-08-23 20:22:22 +02:00
|
|
|
SmallCStr { data }
|
2018-08-07 16:04:34 +02:00
|
|
|
}
|
|
|
|
|
2018-08-23 20:22:22 +02:00
|
|
|
#[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()) }
|
|
|
|
}
|
|
|
|
|
2018-08-07 16:04:34 +02:00
|
|
|
#[inline]
|
|
|
|
pub fn as_c_str(&self) -> &ffi::CStr {
|
2021-12-03 03:06:36 +01:00
|
|
|
unsafe { ffi::CStr::from_bytes_with_nul_unchecked(&self.data) }
|
2018-08-07 16:04:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn len_with_nul(&self) -> usize {
|
2018-08-23 20:22:22 +02:00
|
|
|
self.data.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn spilled(&self) -> bool {
|
|
|
|
self.data.spilled()
|
2018-08-07 16:04:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Deref for SmallCStr {
|
|
|
|
type Target = ffi::CStr;
|
|
|
|
|
2022-03-03 00:00:00 +00:00
|
|
|
#[inline]
|
2018-08-07 16:04:34 +02:00
|
|
|
fn deref(&self) -> &ffi::CStr {
|
|
|
|
self.as_c_str()
|
|
|
|
}
|
|
|
|
}
|
2021-09-24 18:02:02 +03:00
|
|
|
|
|
|
|
impl<'a> FromIterator<&'a str> for SmallCStr {
|
|
|
|
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
|
|
|
|
let mut data =
|
|
|
|
iter.into_iter().flat_map(|s| s.as_bytes()).copied().collect::<SmallVec<_>>();
|
|
|
|
data.push(0);
|
|
|
|
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data) {
|
|
|
|
panic!("The iterator {:?} cannot be converted into a CStr: {}", data, e);
|
|
|
|
}
|
|
|
|
Self { data }
|
|
|
|
}
|
|
|
|
}
|