Introduce SmallCStr and use it where applicable.

This commit is contained in:
Michael Woerister 2018-08-07 16:04:34 +02:00
parent 9585c5dc1f
commit 88d84b38f1
13 changed files with 200 additions and 75 deletions

View File

@ -128,7 +128,7 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
llvm::AddFunctionAttrStringValue(
llfn,
llvm::AttributePlace::Function,
cstr("target-cpu\0"),
const_cstr!("target-cpu"),
target_cpu.as_c_str());
}

View File

@ -31,6 +31,7 @@
use rustc::ty::TyCtxt;
use rustc::util::common::{time_ext, time_depth, set_time_depth, print_time_passes_entry};
use rustc_fs_util::{path2cstr, link_or_copy};
use rustc_data_structures::small_c_str::SmallCStr;
use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
use errors::emitter::{Emitter};
use syntax::attr;
@ -170,11 +171,8 @@ pub fn target_machine_factory(sess: &Session, find_features: bool)
let singlethread = sess.target.target.options.singlethread;
let triple = &sess.target.target.llvm_target;
let triple = CString::new(triple.as_bytes()).unwrap();
let cpu = sess.target_cpu();
let cpu = CString::new(cpu.as_bytes()).unwrap();
let triple = SmallCStr::new(&sess.target.target.llvm_target);
let cpu = SmallCStr::new(sess.target_cpu());
let features = attributes::llvm_target_features(sess)
.collect::<Vec<_>>()
.join(",");
@ -522,7 +520,7 @@ unsafe fn optimize(cgcx: &CodegenContext,
// If we're verifying or linting, add them to the function pass
// manager.
let addpass = |pass_name: &str| {
let pass_name = CString::new(pass_name).unwrap();
let pass_name = SmallCStr::new(pass_name);
let pass = match llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()) {
Some(pass) => pass,
None => return false,

View File

@ -73,6 +73,7 @@
use type_of::LayoutLlvmExt;
use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet};
use CrateInfo;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_data_structures::sync::Lrc;
use std::any::Any;
@ -533,7 +534,7 @@ pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
None => return,
};
unsafe {
let buf = CString::new(sect.as_str().as_bytes()).unwrap();
let buf = SmallCStr::new(&sect.as_str());
llvm::LLVMSetSection(llval, buf.as_ptr());
}
}
@ -681,7 +682,7 @@ enum MetadataKind {
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
let name = CString::new(section_name).unwrap();
let name = SmallCStr::new(section_name);
llvm::LLVMSetSection(llglobal, name.as_ptr());
// Also generate a .section directive to force no

View File

@ -18,9 +18,9 @@
use rustc::ty::TyCtxt;
use rustc::ty::layout::{Align, Size};
use rustc::session::{config, Session};
use rustc_data_structures::small_c_str::SmallCStr;
use std::borrow::Cow;
use std::ffi::CString;
use std::ops::Range;
use std::ptr;
@ -58,7 +58,7 @@ impl Builder<'a, 'll, 'tcx> {
pub fn new_block<'b>(cx: &'a CodegenCx<'ll, 'tcx>, llfn: &'ll Value, name: &'b str) -> Self {
let bx = Builder::with_cx(cx);
let llbb = unsafe {
let name = CString::new(name).unwrap();
let name = SmallCStr::new(name);
llvm::LLVMAppendBasicBlockInContext(
cx.llcx,
llfn,
@ -118,7 +118,7 @@ fn count_insn(&self, category: &str) {
}
pub fn set_value_name(&self, value: &'ll Value, name: &str) {
let cname = CString::new(name.as_bytes()).unwrap();
let cname = SmallCStr::new(name);
unsafe {
llvm::LLVMSetValueName(value, cname.as_ptr());
}
@ -436,7 +436,7 @@ pub fn dynamic_alloca(&self, ty: &'ll Type, name: &str, align: Align) -> &'ll Va
let alloca = if name.is_empty() {
llvm::LLVMBuildAlloca(self.llbuilder, ty, noname())
} else {
let name = CString::new(name).unwrap();
let name = SmallCStr::new(name);
llvm::LLVMBuildAlloca(self.llbuilder, ty,
name.as_ptr())
};

View File

@ -26,6 +26,7 @@
use type_of::PointeeInfo;
use rustc_data_structures::base_n;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc::mir::mono::Stats;
use rustc::session::config::{self, DebugInfo};
use rustc::session::Session;
@ -34,7 +35,7 @@
use rustc::util::nodemap::FxHashMap;
use rustc_target::spec::{HasTargetSpec, Target};
use std::ffi::{CStr, CString};
use std::ffi::CStr;
use std::cell::{Cell, RefCell};
use std::iter;
use std::str;
@ -161,7 +162,7 @@ pub unsafe fn create_module(
llcx: &'ll llvm::Context,
mod_name: &str,
) -> &'ll llvm::Module {
let mod_name = CString::new(mod_name).unwrap();
let mod_name = SmallCStr::new(mod_name);
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
// Ensure the data-layout values hardcoded remain the defaults.
@ -201,11 +202,10 @@ pub unsafe fn create_module(
}
}
let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap();
let data_layout = SmallCStr::new(&sess.target.target.data_layout);
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
let llvm_target = sess.target.target.llvm_target.as_bytes();
let llvm_target = CString::new(llvm_target).unwrap();
let llvm_target = SmallCStr::new(&sess.target.target.llvm_target);
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
if is_pie_binary(sess) {

View File

@ -37,6 +37,7 @@
use rustc::session::config;
use rustc::util::nodemap::FxHashMap;
use rustc_fs_util::path2cstr;
use rustc_data_structures::small_c_str::SmallCStr;
use libc::{c_uint, c_longlong};
use std::ffi::CString;
@ -274,7 +275,7 @@ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
// ... and attach them to the stub to complete it.
set_members_of_composite_type(cx,
metadata_stub,
&member_descriptions[..]);
member_descriptions);
return MetadataCreationResult::new(metadata_stub, true);
}
}
@ -349,7 +350,7 @@ fn vec_slice_metadata(
let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
let member_descriptions = [
let member_descriptions = vec![
MemberDescription {
name: "data_ptr".to_string(),
type_metadata: data_ptr_metadata,
@ -374,7 +375,7 @@ fn vec_slice_metadata(
slice_ptr_type,
&slice_type_name[..],
unique_type_id,
&member_descriptions,
member_descriptions,
NO_SCOPE_METADATA,
file_metadata,
span);
@ -460,7 +461,7 @@ fn trait_pointer_metadata(
let data_ptr_field = layout.field(cx, 0);
let vtable_field = layout.field(cx, 1);
let member_descriptions = [
let member_descriptions = vec![
MemberDescription {
name: "pointer".to_string(),
type_metadata: type_metadata(cx,
@ -485,7 +486,7 @@ fn trait_pointer_metadata(
trait_object_type,
&trait_type_name[..],
unique_type_id,
&member_descriptions,
member_descriptions,
containing_scope,
file_metadata,
syntax_pos::DUMMY_SP)
@ -746,8 +747,8 @@ fn file_metadata_raw(cx: &CodegenCx<'ll, '_>,
debug!("file_metadata: file_name: {}, directory: {}", file_name, directory);
let file_name = CString::new(file_name).unwrap();
let directory = CString::new(directory).unwrap();
let file_name = SmallCStr::new(file_name);
let directory = SmallCStr::new(directory);
let file_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateFile(DIB(cx),
@ -782,7 +783,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
};
let (size, align) = cx.size_and_align_of(t);
let name = CString::new(name).unwrap();
let name = SmallCStr::new(name);
let ty_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateBasicType(
DIB(cx),
@ -813,7 +814,7 @@ fn pointer_type_metadata(
) -> &'ll DIType {
let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
let name = compute_debuginfo_type_name(cx, pointer_type, false);
let name = CString::new(name).unwrap();
let name = SmallCStr::new(&name);
unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
DIB(cx),
@ -847,9 +848,9 @@ pub fn compile_unit_metadata(tcx: TyCtxt,
let producer = format!("clang LLVM (rustc version {})",
(option_env!("CFG_VERSION")).expect("CFG_VERSION"));
let name_in_debuginfo = name_in_debuginfo.to_string_lossy().into_owned();
let name_in_debuginfo = CString::new(name_in_debuginfo).unwrap();
let work_dir = CString::new(&tcx.sess.working_dir.0.to_string_lossy()[..]).unwrap();
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo);
let work_dir = SmallCStr::new(&tcx.sess.working_dir.0.to_string_lossy());
let producer = CString::new(producer).unwrap();
let flags = "\0";
let split_name = "\0";
@ -1187,7 +1188,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
set_members_of_composite_type(cx,
variant_type_metadata,
&member_descriptions[..]);
member_descriptions);
vec![
MemberDescription {
name: "".to_string(),
@ -1217,7 +1218,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
set_members_of_composite_type(cx,
variant_type_metadata,
&member_descriptions);
member_descriptions);
MemberDescription {
name: "".to_string(),
type_metadata: variant_type_metadata,
@ -1244,7 +1245,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>)
set_members_of_composite_type(cx,
variant_type_metadata,
&variant_member_descriptions[..]);
variant_member_descriptions);
// Encode the information about the null variant in the union
// member's name.
@ -1416,8 +1417,7 @@ fn prepare_enum_metadata(
let enumerators_metadata: Vec<_> = def.discriminants(cx.tcx)
.zip(&def.variants)
.map(|(discr, v)| {
let token = v.name.as_str();
let name = CString::new(token.as_bytes()).unwrap();
let name = SmallCStr::new(&v.name.as_str());
unsafe {
Some(llvm::LLVMRustDIBuilderCreateEnumerator(
DIB(cx),
@ -1442,7 +1442,7 @@ fn prepare_enum_metadata(
type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP);
let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str();
let name = CString::new(discriminant_name.as_bytes()).unwrap();
let name = SmallCStr::new(&discriminant_name);
let discriminant_type_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateEnumerationType(
DIB(cx),
@ -1482,10 +1482,10 @@ fn prepare_enum_metadata(
let (enum_type_size, enum_type_align) = layout.size_and_align();
let enum_name = CString::new(enum_name).unwrap();
let unique_type_id_str = CString::new(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
).unwrap();
let enum_name = SmallCStr::new(&enum_name);
let unique_type_id_str = SmallCStr::new(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
);
let enum_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateUnionType(
DIB(cx),
@ -1531,7 +1531,7 @@ fn composite_type_metadata(
composite_type: Ty<'tcx>,
composite_type_name: &str,
composite_type_unique_id: UniqueTypeId,
member_descriptions: &[MemberDescription<'ll>],
member_descriptions: Vec<MemberDescription<'ll>>,
containing_scope: Option<&'ll DIScope>,
// Ignore source location information as long as it
@ -1555,7 +1555,7 @@ fn composite_type_metadata(
fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
composite_type_metadata: &'ll DICompositeType,
member_descriptions: &[MemberDescription<'ll>]) {
member_descriptions: Vec<MemberDescription<'ll>>) {
// In some rare cases LLVM metadata uniquing would lead to an existing type
// description being used instead of a new one created in
// create_struct_stub. This would cause a hard to trace assertion in
@ -1574,10 +1574,9 @@ fn set_members_of_composite_type(cx: &CodegenCx<'ll, '_>,
}
let member_metadata: Vec<_> = member_descriptions
.iter()
.into_iter()
.map(|member_description| {
let member_name = member_description.name.as_bytes();
let member_name = CString::new(member_name).unwrap();
let member_name = CString::new(member_description.name).unwrap();
unsafe {
Some(llvm::LLVMRustDIBuilderCreateMemberType(
DIB(cx),
@ -1613,10 +1612,10 @@ fn create_struct_stub(
) -> &'ll DICompositeType {
let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
let name = CString::new(struct_type_name).unwrap();
let unique_type_id = CString::new(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
).unwrap();
let name = SmallCStr::new(struct_type_name);
let unique_type_id = SmallCStr::new(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
);
let metadata_stub = unsafe {
// LLVMRustDIBuilderCreateStructType() wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
@ -1651,10 +1650,10 @@ fn create_union_stub(
) -> &'ll DICompositeType {
let (union_size, union_align) = cx.size_and_align_of(union_type);
let name = CString::new(union_type_name).unwrap();
let unique_type_id = CString::new(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id).as_bytes()
).unwrap();
let name = SmallCStr::new(union_type_name);
let unique_type_id = SmallCStr::new(
debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id)
);
let metadata_stub = unsafe {
// LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
@ -1713,13 +1712,12 @@ pub fn create_global_var_metadata(
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx);
let type_metadata = type_metadata(cx, variable_type, span);
let var_name = tcx.item_name(def_id).to_string();
let var_name = CString::new(var_name).unwrap();
let var_name = SmallCStr::new(&tcx.item_name(def_id).as_str());
let linkage_name = if no_mangle {
None
} else {
let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id));
Some(CString::new(linkage_name.to_string()).unwrap())
Some(SmallCStr::new(&linkage_name.as_str()))
};
let global_align = cx.align_of(variable_type);

View File

@ -34,6 +34,7 @@
use rustc::mir;
use rustc::session::config::{self, DebugInfo};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
use rustc_data_structures::small_c_str::SmallCStr;
use value::Value;
use libc::c_uint;
@ -265,7 +266,7 @@ pub fn create_function_debug_context(
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
let function_name = CString::new(name).unwrap();
let linkage_name = CString::new(linkage_name.to_string()).unwrap();
let linkage_name = SmallCStr::new(&linkage_name.as_str());
let mut flags = DIFlags::FlagPrototyped;
@ -407,7 +408,7 @@ fn get_template_parameters(
let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let actual_type_metadata =
type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
let name = CString::new(name.as_str().as_bytes()).unwrap();
let name = SmallCStr::new(&name.as_str());
Some(unsafe {
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
@ -510,7 +511,7 @@ pub fn declare_local(
};
let align = cx.align_of(variable_type);
let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
let name = SmallCStr::new(&variable_name.as_str());
match (variable_access, &[][..]) {
(DirectVariable { alloca }, address_operations) |
(IndirectVariable {alloca, address_operations}, _) => {

View File

@ -21,7 +21,7 @@
use rustc::hir::map::DefPathData;
use common::CodegenCx;
use std::ffi::CString;
use rustc_data_structures::small_c_str::SmallCStr;
pub fn mangled_name_of_instance<'a, 'tcx>(
cx: &CodegenCx<'a, 'tcx>,
@ -49,7 +49,7 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
data => data.as_interned_str().as_str()
};
let namespace_name = CString::new(namespace_name.as_bytes()).unwrap();
let namespace_name = SmallCStr::new(&namespace_name);
let scope = unsafe {
llvm::LLVMRustDIBuilderCreateNameSpace(

View File

@ -25,6 +25,7 @@
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, LayoutOf};
use rustc::session::config::Sanitizer;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_target::spec::PanicStrategy;
use abi::{Abi, FnType, FnTypeExt};
use attributes;
@ -33,7 +34,6 @@
use type_::Type;
use value::Value;
use std::ffi::CString;
/// Declare a global value.
///
@ -41,9 +41,7 @@
/// return its Value instead.
pub fn declare_global(cx: &CodegenCx<'ll, '_>, name: &str, ty: &'ll Type) -> &'ll Value {
debug!("declare_global(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
bug!("name {:?} contains an interior null byte", name)
});
let namebuf = SmallCStr::new(name);
unsafe {
llvm::LLVMRustGetOrInsertGlobal(cx.llmod, namebuf.as_ptr(), ty)
}
@ -61,9 +59,7 @@ fn declare_raw_fn(
ty: &'ll Type,
) -> &'ll Value {
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
let namebuf = CString::new(name).unwrap_or_else(|_|{
bug!("name {:?} contains an interior null byte", name)
});
let namebuf = SmallCStr::new(name);
let llfn = unsafe {
llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty)
};
@ -214,9 +210,7 @@ pub fn define_internal_fn(
/// Get declared value by name.
pub fn get_declared_value(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
debug!("get_declared_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
bug!("name {:?} contains an interior null byte", name)
});
let namebuf = SmallCStr::new(name);
unsafe { llvm::LLVMRustGetNamedValue(cx.llmod, namebuf.as_ptr()) }
}

View File

@ -24,9 +24,10 @@
use std::str::FromStr;
use std::string::FromUtf8Error;
use std::slice;
use std::ffi::{CString, CStr};
use std::ffi::CStr;
use std::cell::RefCell;
use libc::{self, c_uint, c_char, size_t};
use rustc_data_structures::small_c_str::SmallCStr;
pub mod archive_ro;
pub mod diagnostic;
@ -264,7 +265,7 @@ pub struct OperandBundleDef<'a> {
impl OperandBundleDef<'a> {
pub fn new(name: &str, vals: &[&'a Value]) -> Self {
let name = CString::new(name).unwrap();
let name = SmallCStr::new(name);
let def = unsafe {
LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
};

View File

@ -19,8 +19,8 @@
use syntax::ast;
use rustc::ty::layout::{self, Align, Size};
use rustc_data_structures::small_c_str::SmallCStr;
use std::ffi::CString;
use std::fmt;
use libc::c_uint;
@ -201,7 +201,7 @@ pub fn struct_(cx: &CodegenCx<'ll, '_>, els: &[&'ll Type], packed: bool) -> &'ll
}
pub fn named_struct(cx: &CodegenCx<'ll, '_>, name: &str) -> &'ll Type {
let name = CString::new(name).unwrap();
let name = SmallCStr::new(name);
unsafe {
llvm::LLVMStructCreateNamed(cx.llcx, name.as_ptr())
}

View File

@ -70,6 +70,7 @@
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod small_vec;
pub mod snapshot_map;
pub use ena::snapshot_vec;

View File

@ -0,0 +1,131 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ffi;
use std::ops::Deref;
const SIZE: usize = 38;
/// Like SmallVec but for C strings.
#[derive(Clone)]
pub enum SmallCStr {
OnStack {
data: [u8; SIZE],
len_with_nul: u8,
},
OnHeap {
data: ffi::CString,
}
}
impl SmallCStr {
#[inline]
pub fn new(s: &str) -> SmallCStr {
if s.len() < SIZE {
let mut data = [0; SIZE];
data[.. s.len()].copy_from_slice(s.as_bytes());
let len_with_nul = s.len() + 1;
// Make sure once that this is a valid CStr
if let Err(e) = ffi::CStr::from_bytes_with_nul(&data[.. len_with_nul]) {
panic!("The string \"{}\" cannot be converted into a CStr: {}", s, e);
}
SmallCStr::OnStack {
data,
len_with_nul: len_with_nul as u8,
}
} else {
SmallCStr::OnHeap {
data: ffi::CString::new(s).unwrap()
}
}
}
#[inline]
pub fn as_c_str(&self) -> &ffi::CStr {
match *self {
SmallCStr::OnStack { ref data, len_with_nul } => {
unsafe {
let slice = &data[.. len_with_nul as usize];
ffi::CStr::from_bytes_with_nul_unchecked(slice)
}
}
SmallCStr::OnHeap { ref data } => {
data.as_c_str()
}
}
}
#[inline]
pub fn len_with_nul(&self) -> usize {
match *self {
SmallCStr::OnStack { len_with_nul, .. } => {
len_with_nul as usize
}
SmallCStr::OnHeap { ref data } => {
data.as_bytes_with_nul().len()
}
}
}
}
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!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
}
#[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!(if let SmallCStr::OnStack { .. } = scs { true } else { false });
}
#[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!(if let SmallCStr::OnHeap { .. } = scs { true } else { false });
}
#[test]
#[should_panic]
fn internal_nul() {
let _ = SmallCStr::new("abcd\0def");
}