about summary refs log tree commit diff
path: root/src/librustc_data_structures
diff options
context:
space:
mode:
authorMichael Woerister <michaelwoerister@posteo>2018-08-07 16:04:34 +0200
committerMichael Woerister <michaelwoerister@posteo>2018-08-10 11:13:00 +0200
commit88d84b38f19eff3c25ec88931f04bf2640edf2b5 (patch)
tree1b161e6842a4e32c29ba92332eb5b28f81d0e3ec /src/librustc_data_structures
parent9585c5dc1fa3cef34ebdc5a5d39af88db60c6f15 (diff)
Introduce SmallCStr and use it where applicable.
Diffstat (limited to 'src/librustc_data_structures')
-rw-r--r--src/librustc_data_structures/lib.rs1
-rw-r--r--src/librustc_data_structures/small_c_str.rs131
2 files changed, 132 insertions, 0 deletions
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index bd11a2977ff..8a586d8c233 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -70,6 +70,7 @@ pub mod obligation_forest;
 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;
diff --git a/src/librustc_data_structures/small_c_str.rs b/src/librustc_data_structures/small_c_str.rs
new file mode 100644
index 00000000000..b0ad83e4979
--- /dev/null
+++ b/src/librustc_data_structures/small_c_str.rs
@@ -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");
+}