Skip to content

Commit 986ba9c

Browse files
committed
std: Update the c_str docs, and support CString not owning the pointer
1 parent 3c94b50 commit 986ba9c

File tree

1 file changed

+63
-138
lines changed

1 file changed

+63
-138
lines changed

src/libstd/c_str.rs

Lines changed: 63 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -18,105 +18,77 @@ use ptr;
1818
use str::StrSlice;
1919
use vec::ImmutableVector;
2020

21-
/**
22-
* The representation of a C String.
23-
*
24-
* This structure wraps a `*libc::c_char`, and will automatically free the
25-
* memory it is pointing to when it goes out of scope.
26-
*/
21+
/// The representation of a C String.
22+
///
23+
/// This structure wraps a `*libc::c_char`, and will automatically free the
24+
/// memory it is pointing to when it goes out of scope.
2725
pub struct CString {
2826
priv buf: *libc::c_char,
27+
priv owns_buffer_: bool,
2928
}
3029

3130
impl<'self> CString {
32-
/**
33-
* Create a C String from a str.
34-
*/
35-
pub fn from_str(s: &str) -> CString {
36-
s.to_c_str()
31+
/// Create a C String from a pointer.
32+
pub fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
33+
CString { buf: buf, owns_buffer_: owns_buffer }
3734
}
3835

39-
/**
40-
* Take the wrapped `*libc::c_char` from the `CString` wrapper.
41-
*
42-
* # Failure
43-
*
44-
* If the wrapper is empty.
45-
*/
46-
pub unsafe fn take(&mut self) -> *libc::c_char {
47-
if self.buf.is_null() {
48-
fail!("CString has no wrapped `*libc::c_char`");
49-
}
50-
let buf = self.buf;
51-
self.buf = ptr::null();
52-
buf
53-
}
54-
55-
/**
56-
* Puts a `*libc::c_char` into the `CString` wrapper.
57-
*
58-
* # Failure
59-
*
60-
* If the `*libc::c_char` is null.
61-
* If the wrapper is not empty.
62-
*/
63-
pub fn put_back(&mut self, buf: *libc::c_char) {
64-
if buf.is_null() {
65-
fail!("attempt to put a null pointer into a CString");
66-
}
67-
if self.buf.is_not_null() {
68-
fail!("CString already wraps a `*libc::c_char`");
69-
}
70-
self.buf = buf;
36+
/// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
37+
pub unsafe fn unwrap(self) -> *libc::c_char {
38+
let mut c_str = self;
39+
c_str.owns_buffer_ = false;
40+
c_str.buf
7141
}
7242

73-
/**
74-
* Calls a closure with a reference to the underlying `*libc::c_char`.
75-
*/
43+
/// Calls a closure with a reference to the underlying `*libc::c_char`.
44+
///
45+
/// # Failure
46+
///
47+
/// Fails if the CString is null.
7648
pub fn with_ref<T>(&self, f: &fn(*libc::c_char) -> T) -> T {
77-
if self.buf.is_null() {
78-
fail!("CString already wraps a `*libc::c_char`");
79-
}
49+
if self.buf.is_null() { fail!("CString is null!"); }
8050
f(self.buf)
8151
}
8252

83-
/**
84-
* Calls a closure with a mutable reference to the underlying `*libc::c_char`.
85-
*/
53+
/// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
54+
///
55+
/// # Failure
56+
///
57+
/// Fails if the CString is null.
8658
pub fn with_mut_ref<T>(&mut self, f: &fn(*mut libc::c_char) -> T) -> T {
87-
if self.buf.is_not_null() {
88-
fail!("CString already wraps a `*libc::c_char`");
89-
}
59+
if self.buf.is_null() { fail!("CString is null!"); }
9060
f(unsafe { cast::transmute(self.buf) })
9161
}
9262

93-
/**
94-
* Returns true if the CString does not wrap a `*libc::c_char`.
95-
*/
96-
pub fn is_empty(&self) -> bool {
63+
/// Returns true if the CString is a null.
64+
pub fn is_null(&self) -> bool {
9765
self.buf.is_null()
9866
}
9967

100-
/**
101-
* Returns true if the CString wraps a `*libc::c_char`.
102-
*/
103-
pub fn is_not_empty(&self) -> bool {
68+
/// Returns true if the CString is not null.
69+
pub fn is_not_null(&self) -> bool {
10470
self.buf.is_not_null()
10571
}
10672

107-
/**
108-
* Converts the CString into a `&[u8]` without copying.
109-
*/
73+
/// Returns whether or not the `CString` owns the buffer.
74+
pub fn owns_buffer(&self) -> bool {
75+
self.owns_buffer_
76+
}
77+
78+
/// Converts the CString into a `&[u8]` without copying.
79+
///
80+
/// # Failure
81+
///
82+
/// Fails if the CString is null.
11083
pub fn as_bytes(&self) -> &'self [u8] {
84+
if self.buf.is_null() { fail!("CString is null!"); }
11185
unsafe {
11286
let len = libc::strlen(self.buf) as uint;
11387
cast::transmute((self.buf, len + 1))
11488
}
11589
}
11690

117-
/**
118-
* Return a CString iterator.
119-
*/
91+
/// Return a CString iterator.
12092
fn iter(&self) -> CStringIterator<'self> {
12193
CStringIterator {
12294
ptr: self.buf,
@@ -127,37 +99,28 @@ impl<'self> CString {
12799

128100
impl Drop for CString {
129101
fn drop(&self) {
130-
if self.buf.is_not_null() {
102+
if self.owns_buffer_ && self.buf.is_not_null() {
131103
unsafe {
132104
libc::free(self.buf as *libc::c_void)
133-
};
105+
}
134106
}
135107
}
136108
}
137109

138-
/**
139-
* A generic trait for converting a value to a CString.
140-
*/
110+
/// A generic trait for converting a value to a CString.
141111
pub trait ToCStr {
142-
/**
143-
* Create a C String.
144-
*/
112+
/// Create a C String.
145113
fn to_c_str(&self) -> CString;
146114
}
147115

148116
impl<'self> ToCStr for &'self str {
149-
/**
150-
* Create a C String from a `&str`.
151-
*/
117+
#[inline]
152118
fn to_c_str(&self) -> CString {
153119
self.as_bytes().to_c_str()
154120
}
155121
}
156122

157123
impl<'self> ToCStr for &'self [u8] {
158-
/**
159-
* Create a C String from a `&[u8]`.
160-
*/
161124
fn to_c_str(&self) -> CString {
162125
do self.as_imm_buf |self_buf, self_len| {
163126
unsafe {
@@ -168,26 +131,22 @@ impl<'self> ToCStr for &'self [u8] {
168131

169132
ptr::copy_memory(buf, self_buf, self_len);
170133
*ptr::mut_offset(buf, self_len as int) = 0;
171-
CString { buf: buf as *libc::c_char }
134+
135+
CString::new(buf as *libc::c_char, true)
172136
}
173137
}
174138
}
175139
}
176140

177-
/**
178-
* External iterator for a CString's bytes.
179-
*
180-
* Use with the `std::iterator` module.
181-
*/
141+
/// External iterator for a CString's bytes.
142+
///
143+
/// Use with the `std::iterator` module.
182144
pub struct CStringIterator<'self> {
183145
priv ptr: *libc::c_char,
184146
priv lifetime: &'self libc::c_char, // FIXME: #5922
185147
}
186148

187149
impl<'self> Iterator<libc::c_char> for CStringIterator<'self> {
188-
/**
189-
* Advance the iterator.
190-
*/
191150
fn next(&mut self) -> Option<libc::c_char> {
192151
if self.ptr.is_null() {
193152
None
@@ -226,66 +185,32 @@ mod tests {
226185
}
227186

228187
#[test]
229-
fn test_take() {
230-
let mut c_str = "hello".to_c_str();
231-
unsafe { libc::free(c_str.take() as *libc::c_void) }
232-
assert!(c_str.is_empty());
233-
}
234-
235-
#[test]
236-
fn test_take_and_put_back() {
237-
let mut c_str = "hello".to_c_str();
238-
assert!(c_str.is_not_empty());
239-
240-
let buf = unsafe { c_str.take() };
241-
242-
assert!(c_str.is_empty());
243-
244-
c_str.put_back(buf);
245-
246-
assert!(c_str.is_not_empty());
247-
}
248-
249-
#[test]
250-
#[should_fail]
251-
#[ignore(cfg(windows))]
252-
fn test_take_empty_fail() {
253-
let mut c_str = "hello".to_c_str();
254-
unsafe {
255-
libc::free(c_str.take() as *libc::c_void);
256-
c_str.take();
257-
}
188+
fn test_is_null() {
189+
let c_str = CString::new(ptr::null(), false);
190+
assert!(c_str.is_null());
191+
assert!(!c_str.is_not_null());
258192
}
259193

260194
#[test]
261-
#[should_fail]
262-
#[ignore(cfg(windows))]
263-
fn test_put_back_null_fail() {
264-
let mut c_str = "hello".to_c_str();
265-
c_str.put_back(ptr::null());
195+
fn test_unwrap() {
196+
let c_str = "hello".to_c_str();
197+
unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
266198
}
267199

268200
#[test]
269-
#[should_fail]
270-
#[ignore(cfg(windows))]
271-
fn test_put_back_full_fail() {
272-
let mut c_str = "hello".to_c_str();
273-
c_str.put_back(0xdeadbeef as *libc::c_char);
274-
}
275-
276-
fn test_with() {
201+
fn test_with_ref() {
277202
let c_str = "hello".to_c_str();
278203
let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
279-
assert!(c_str.is_not_empty());
204+
assert!(!c_str.is_null());
205+
assert!(c_str.is_not_null());
280206
assert_eq!(len, 5);
281207
}
282208

283209
#[test]
284210
#[should_fail]
285211
#[ignore(cfg(windows))]
286-
fn test_with_empty_fail() {
287-
let mut c_str = "hello".to_c_str();
288-
unsafe { libc::free(c_str.take() as *libc::c_void) }
212+
fn test_with_ref_empty_fail() {
213+
let c_str = CString::new(ptr::null(), false);
289214
c_str.with_ref(|_| ());
290215
}
291216
}

0 commit comments

Comments
 (0)