@@ -18,105 +18,77 @@ use ptr;
18
18
use str:: StrSlice ;
19
19
use vec:: ImmutableVector ;
20
20
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.
27
25
pub struct CString {
28
26
priv buf: * libc:: c_char ,
27
+ priv owns_buffer_ : bool ,
29
28
}
30
29
31
30
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 }
37
34
}
38
35
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
71
41
}
72
42
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.
76
48
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!" ) ; }
80
50
f ( self . buf )
81
51
}
82
52
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.
86
58
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!" ) ; }
90
60
f ( unsafe { cast:: transmute ( self . buf ) } )
91
61
}
92
62
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 {
97
65
self . buf . is_null ( )
98
66
}
99
67
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 {
104
70
self . buf . is_not_null ( )
105
71
}
106
72
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.
110
83
pub fn as_bytes ( & self ) -> & ' self [ u8 ] {
84
+ if self . buf . is_null ( ) { fail ! ( "CString is null!" ) ; }
111
85
unsafe {
112
86
let len = libc:: strlen ( self . buf ) as uint ;
113
87
cast:: transmute ( ( self . buf , len + 1 ) )
114
88
}
115
89
}
116
90
117
- /**
118
- * Return a CString iterator.
119
- */
91
+ /// Return a CString iterator.
120
92
fn iter ( & self ) -> CStringIterator < ' self > {
121
93
CStringIterator {
122
94
ptr : self . buf ,
@@ -127,37 +99,28 @@ impl<'self> CString {
127
99
128
100
impl Drop for CString {
129
101
fn drop ( & self ) {
130
- if self . buf . is_not_null ( ) {
102
+ if self . owns_buffer_ && self . buf . is_not_null ( ) {
131
103
unsafe {
132
104
libc:: free ( self . buf as * libc:: c_void )
133
- } ;
105
+ }
134
106
}
135
107
}
136
108
}
137
109
138
- /**
139
- * A generic trait for converting a value to a CString.
140
- */
110
+ /// A generic trait for converting a value to a CString.
141
111
pub trait ToCStr {
142
- /**
143
- * Create a C String.
144
- */
112
+ /// Create a C String.
145
113
fn to_c_str ( & self ) -> CString ;
146
114
}
147
115
148
116
impl < ' self > ToCStr for & ' self str {
149
- /**
150
- * Create a C String from a `&str`.
151
- */
117
+ #[ inline]
152
118
fn to_c_str ( & self ) -> CString {
153
119
self . as_bytes ( ) . to_c_str ( )
154
120
}
155
121
}
156
122
157
123
impl < ' self > ToCStr for & ' self [ u8 ] {
158
- /**
159
- * Create a C String from a `&[u8]`.
160
- */
161
124
fn to_c_str ( & self ) -> CString {
162
125
do self . as_imm_buf |self_buf, self_len| {
163
126
unsafe {
@@ -168,26 +131,22 @@ impl<'self> ToCStr for &'self [u8] {
168
131
169
132
ptr:: copy_memory ( buf, self_buf, self_len) ;
170
133
* 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 )
172
136
}
173
137
}
174
138
}
175
139
}
176
140
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.
182
144
pub struct CStringIterator < ' self > {
183
145
priv ptr: * libc:: c_char ,
184
146
priv lifetime : & ' self libc:: c_char , // FIXME: #5922
185
147
}
186
148
187
149
impl < ' self > Iterator < libc:: c_char > for CStringIterator < ' self > {
188
- /**
189
- * Advance the iterator.
190
- */
191
150
fn next ( & mut self ) -> Option < libc:: c_char > {
192
151
if self . ptr . is_null ( ) {
193
152
None
@@ -226,66 +185,32 @@ mod tests {
226
185
}
227
186
228
187
#[ 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( ) ) ;
258
192
}
259
193
260
194
#[ 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 ) }
266
198
}
267
199
268
200
#[ 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 ( ) {
277
202
let c_str = "hello" . to_c_str ( ) ;
278
203
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( ) ) ;
280
206
assert_eq ! ( len, 5 ) ;
281
207
}
282
208
283
209
#[ test]
284
210
#[ should_fail]
285
211
#[ 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 ) ;
289
214
c_str. with_ref ( |_| ( ) ) ;
290
215
}
291
216
}
0 commit comments