rustc-ap-rustc_data_structures 429.0.0

Automatically published version of the package `rustc_data_structures` in the rust-lang/rust repository from commit 314a79cd80ed905f80d24b79fd7acb4c8c72789b The publishing script for this crate lives at: https://github.com/alexcrichton/rustc-auto-publish
use std::ffi;
use std::ops::Deref;

use smallvec::SmallVec;

const SIZE: usize = 36;

/// Like SmallVec but for C strings.
#[derive(Clone)]
pub struct SmallCStr {
    data: SmallVec<[u8; SIZE]>,
}

impl SmallCStr {
    #[inline]
    pub fn new(s: &str) -> SmallCStr {
        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)
        } else {
            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);
        }
        SmallCStr { data }
    }

    #[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()) }
    }


    #[inline]
    pub fn as_c_str(&self) -> &ffi::CStr {
        unsafe {
            ffi::CStr::from_bytes_with_nul_unchecked(&self.data[..])
        }
    }

    #[inline]
    pub fn len_with_nul(&self) -> usize {
        self.data.len()
    }

    pub fn spilled(&self) -> bool {
        self.data.spilled()
    }
}

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!(!scs.spilled());
}

#[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!(!scs.spilled());
}

#[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!(scs.spilled());
}

#[test]
#[should_panic]
fn internal_nul() {
    let _ = SmallCStr::new("abcd\0def");
}