summary refs log tree commit diff
path: root/src/libstd/ffi/c_str.rs
blob: d7f8eb2e4158bf448242c57000b635b5395fa8d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright 2012 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 fmt;
use iter::IteratorExt;
use libc;
use mem;
use ops::Deref;
use slice::{self, SliceExt, AsSlice};
use string::String;
use vec::Vec;

/// A type representing a C-compatible string
///
/// This type serves the primary purpose of being able to generate a
/// C-compatible string from a Rust byte slice or vector. An instance of this
/// type is a static guarantee that the underlying bytes contain no interior 0
/// bytes and the final byte is 0.
///
/// A `CString` is created from either a byte slice or a byte vector. After
/// being created, a `CString` predominately inherits all of its methods from
/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying
/// array is represented as an array of `libc::c_char` as opposed to `u8`. A
/// `u8` slice can be obtained with the `as_bytes` method.  Slices produced from
/// a `CString` do *not* contain the trailing nul terminator unless otherwise
/// specified.
///
/// # Example
///
/// ```no_run
/// # extern crate libc;
/// # fn main() {
/// use std::ffi::CString;
/// use libc;
///
/// extern {
///     fn my_printer(s: *const libc::c_char);
/// }
///
/// let to_print = "Hello, world!";
/// let c_to_print = CString::from_slice(to_print.as_bytes());
/// unsafe {
///     my_printer(c_to_print.as_ptr());
/// }
/// # }
/// ```
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct CString {
    inner: Vec<libc::c_char>,
}

impl CString {
    /// Create a new C-compatible string from a byte slice.
    ///
    /// This method will copy the data of the slice provided into a new
    /// allocation, ensuring that there is a trailing 0 byte.
    ///
    /// # Panics
    ///
    /// This function will panic if there are any 0 bytes already in the slice
    /// provided.
    pub fn from_slice(v: &[u8]) -> CString {
        CString::from_vec(v.to_vec())
    }

    /// Create a C-compatible string from a byte vector.
    ///
    /// This method will consume ownership of the provided vector, appending a 0
    /// byte to the end after verifying that there are no interior 0 bytes.
    ///
    /// # Panics
    ///
    /// This function will panic if there are any 0 bytes already in the vector
    /// provided.
    pub fn from_vec(v: Vec<u8>) -> CString {
        assert!(!v.iter().any(|&x| x == 0));
        unsafe { CString::from_vec_unchecked(v) }
    }

    /// Create a C-compatible string from a byte vector without checking for
    /// interior 0 bytes.
    ///
    /// This method is equivalent to `from_vec` except that no runtime assertion
    /// is made that `v` contains no 0 bytes.
    pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
        v.push(0);
        CString { inner: mem::transmute(v) }
    }

    /// Create a view into this C string which includes the trailing nul
    /// terminator at the end of the string.
    pub fn as_slice_with_nul(&self) -> &[libc::c_char] { self.inner.as_slice() }

    /// Similar to the `as_slice` method, but returns a `u8` slice instead of a
    /// `libc::c_char` slice.
    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(self.as_slice()) }
    }

    /// Equivalent to `as_slice_with_nul` except that the type returned is a
    /// `u8` slice instead of a `libc::c_char` slice.
    pub fn as_bytes_with_nul(&self) -> &[u8] {
        unsafe { mem::transmute(self.as_slice_with_nul()) }
    }
}

impl Deref for CString {
    type Target = [libc::c_char];

    fn deref(&self) -> &[libc::c_char] {
        self.inner.slice_to(self.inner.len() - 1)
    }
}

impl fmt::Show for CString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        String::from_utf8_lossy(self.as_bytes()).fmt(f)
    }
}

/// Interpret a C string as a byte slice.
///
/// This function will calculate the length of the C string provided, and it
/// will then return a corresponding slice for the contents of the C string not
/// including the nul terminator.
///
/// This function will tie the lifetime of the returned slice to the lifetime of
/// the pointer provided. This is done to help prevent the slice from escaping
/// the lifetime of the pointer itself. If a longer lifetime is needed, then
/// `mem::copy_lifetime` should be used.
///
/// This function is unsafe because there is no guarantee of the validity of the
/// pointer `raw` or a guarantee that a nul terminator will be found.
///
/// # Example
///
/// ```no_run
/// # extern crate libc;
/// # fn main() {
/// use std::ffi;
/// use std::str;
/// use libc;
///
/// extern {
///     fn my_string() -> *const libc::c_char;
/// }
///
/// unsafe {
///     let to_print = my_string();
///     let slice = ffi::c_str_to_bytes(&to_print);
///     println!("string returned: {}", str::from_utf8(slice).unwrap());
/// }
/// # }
/// ```
pub unsafe fn c_str_to_bytes<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
    let len = libc::strlen(*raw);
    slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
}

/// Interpret a C string as a byte slice with the nul terminator.
///
/// This function is identical to `from_raw_buf` except that the returned slice
/// will include the nul terminator of the string.
pub unsafe fn c_str_to_bytes_with_nul<'a>(raw: &'a *const libc::c_char) -> &'a [u8] {
    let len = libc::strlen(*raw) + 1;
    slice::from_raw_buf(&*(raw as *const _ as *const *const u8), len as uint)
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;
    use super::*;
    use libc;
    use mem;

    #[test]
    fn c_to_rust() {
        let data = b"123\0";
        let ptr = data.as_ptr() as *const libc::c_char;
        unsafe {
            assert_eq!(c_str_to_bytes(&ptr), b"123");
            assert_eq!(c_str_to_bytes_with_nul(&ptr), b"123\0");
        }
    }

    #[test]
    fn simple() {
        let s = CString::from_slice(b"1234");
        assert_eq!(s.as_bytes(), b"1234");
        assert_eq!(s.as_bytes_with_nul(), b"1234\0");
        unsafe {
            assert_eq!(s.as_slice(),
                       mem::transmute::<_, &[libc::c_char]>(b"1234"));
            assert_eq!(s.as_slice_with_nul(),
                       mem::transmute::<_, &[libc::c_char]>(b"1234\0"));
        }
    }

    #[should_fail] #[test]
    fn build_with_zero1() { CString::from_slice(b"\0"); }
    #[should_fail] #[test]
    fn build_with_zero2() { CString::from_vec(vec![0]); }

    #[test]
    fn build_with_zero3() {
        unsafe {
            let s = CString::from_vec_unchecked(vec![0]);
            assert_eq!(s.as_bytes(), b"\0");
        }
    }
}