]> git.lizzy.rs Git - rust.git/blob - src/libstd/ffi/c_str.rs
debuginfo: Make debuginfo source location assignment more stable (Pt. 1)
[rust.git] / src / libstd / ffi / c_str.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use fmt;
12 use iter::IteratorExt;
13 use libc;
14 use mem;
15 use ops::Deref;
16 use slice::{self, SliceExt, AsSlice};
17 use string::String;
18 use vec::Vec;
19
20 /// A type representing a C-compatible string
21 ///
22 /// This type serves the primary purpose of being able to generate a
23 /// C-compatible string from a Rust byte slice or vector. An instance of this
24 /// type is a static guarantee that the underlying bytes contain no interior 0
25 /// bytes and the final byte is 0.
26 ///
27 /// A `CString` is created from either a byte slice or a byte vector. After
28 /// being created, a `CString` predominately inherits all of its methods from
29 /// the `Deref` implementation to `[libc::c_char]`. Note that the underlying
30 /// array is represented as an array of `libc::c_char` as opposed to `u8`. A
31 /// `u8` slice can be obtained with the `as_bytes` method.  Slices produced from
32 /// a `CString` do *not* contain the trailing nul terminator unless otherwise
33 /// specified.
34 ///
35 /// # Example
36 ///
37 /// ```no_run
38 /// # extern crate libc;
39 /// # fn main() {
40 /// use std::ffi::CString;
41 /// use libc;
42 ///
43 /// extern {
44 ///     fn my_printer(s: *const libc::c_char);
45 /// }
46 ///
47 /// let to_print = "Hello, world!";
48 /// let c_to_print = CString::from_slice(to_print.as_bytes());
49 /// unsafe {
50 ///     my_printer(c_to_print.as_ptr());
51 /// }
52 /// # }
53 /// ```
54 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
55 pub struct CString {
56     inner: Vec<libc::c_char>,
57 }
58
59 impl CString {
60     /// Create a new C-compatible string from a byte slice.
61     ///
62     /// This method will copy the data of the slice provided into a new
63     /// allocation, ensuring that there is a trailing 0 byte.
64     ///
65     /// # Panics
66     ///
67     /// This function will panic if there are any 0 bytes already in the slice
68     /// provided.
69     pub fn from_slice(v: &[u8]) -> CString {
70         CString::from_vec(v.to_vec())
71     }
72
73     /// Create a C-compatible string from a byte vector.
74     ///
75     /// This method will consume ownership of the provided vector, appending a 0
76     /// byte to the end after verifying that there are no interior 0 bytes.
77     ///
78     /// # Panics
79     ///
80     /// This function will panic if there are any 0 bytes already in the vector
81     /// provided.
82     pub fn from_vec(v: Vec<u8>) -> CString {
83         assert!(!v.iter().any(|&x| x == 0));
84         unsafe { CString::from_vec_unchecked(v) }
85     }
86
87     /// Create a C-compatible string from a byte vector without checking for
88     /// interior 0 bytes.
89     ///
90     /// This method is equivalent to `from_vec` except that no runtime assertion
91     /// is made that `v` contains no 0 bytes.
92     pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
93         v.push(0);
94         CString { inner: mem::transmute(v) }
95     }
96
97     /// Create a view into this C string which includes the trailing nul
98     /// terminator at the end of the string.
99     pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() }
100
101     /// Similar to the `as_slice` method, but returns a `u8` slice instead of a
102     /// `libc::c_char` slice.
103     pub fn as_bytes(&self) -> &[u8] {
104         unsafe { mem::transmute(self.as_slice()) }
105     }
106
107     /// Equivalent to `as_slice_with_nul` except that the type returned is a
108     /// `u8` slice instead of a `libc::c_char` slice.
109     pub fn as_bytes_with_nul(&self) -> &[u8] {
110         unsafe { mem::transmute(self.as_slice_with_nul()) }
111     }
112 }
113
114 impl Deref for CString {
115     type Target = [libc::c_char];
116
117     fn deref(&self) -> &[libc::c_char] {
118         self.inner.slice_to(self.inner.len() - 1)
119     }
120 }
121
122 impl fmt::Show for CString {
123     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124         String::from_utf8_lossy(self.as_bytes()).fmt(f)
125     }
126 }
127
128 /// Interpret a C string as a byte slice.
129 ///
130 /// This function will calculate the length of the C string provided, and it
131 /// will then return a corresponding slice for the contents of the C string not
132 /// including the nul terminator.
133 ///
134 /// This function will tie the lifetime of the returned slice to the lifetime of
135 /// the pointer provided. This is done to help prevent the slice from escaping
136 /// the lifetime of the pointer itself. If a longer lifetime is needed, then
137 /// `mem::copy_lifetime` should be used.
138 ///
139 /// This function is unsafe because there is no guarantee of the validity of the
140 /// pointer `raw` or a guarantee that a nul terminator will be found.
141 ///
142 /// # Example
143 ///
144 /// ```no_run
145 /// # extern crate libc;
146 /// # fn main() {
147 /// use std::ffi;
148 /// use std::str;
149 /// use libc;
150 ///
151 /// extern {
152 ///     fn my_string() -> *const libc::c_char;
153 /// }
154 ///
155 /// unsafe {
156 ///     let to_print = my_string();
157 ///     let slice = ffi::c_str_to_bytes(&to_print);
158 ///     println!("string returned: {}", str::from_utf8(slice).unwrap());
159 /// }
160 /// # }
161 /// ```
162 pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
163     let len = libc::strlen(*raw);
164     slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
165 }
166
167 /// Interpret a C string as a byte slice with the nul terminator.
168 ///
169 /// This function is identical to `from_raw_buf` except that the returned slice
170 /// will include the nul terminator of the string.
171 pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
172     let len = libc::strlen(*raw) + 1;
173     slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
174 }
175
176 #[cfg(test)]
177 mod tests {
178     use prelude::v1::*;
179     use super::*;
180     use libc;
181     use mem;
182
183     #[test]
184     fn c_to_rust() {
185         let data = b"123\0";
186         let ptr = data.as_ptr() as *const libc::c_char;
187         unsafe {
188             assert_eq!(c_str_to_bytes(&ptr), b"123");
189             assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0");
190         }
191     }
192
193     #[test]
194     fn simple() {
195         let s = CString::from_slice(b"1234");
196         assert_eq!(s.as_bytes(), b"1234");
197         assert_eq!(s.as_bytes_with_nul(), b"1234\0");
198         unsafe {
199             assert_eq!(s.as_slice(),
200                        mem::transmute::<_, &[libc::c_char]>(b"1234"));
201             assert_eq!(s.as_slice_with_nul(),
202                        mem::transmute::<_, &[libc::c_char]>(b"1234\0"));
203         }
204     }
205
206     #[should_fail] #[test]
207     fn build_with_zero1() { CString::from_slice(b"\0"); }
208     #[should_fail] #[test]
209     fn build_with_zero2() { CString::from_vec(vec![0]); }
210
211     #[test]
212     fn build_with_zero3() {
213         unsafe {
214             let s = CString::from_vec_unchecked(vec![0]);
215             assert_eq!(s.as_bytes(), b"\0");
216         }
217     }
218 }