]> git.lizzy.rs Git - rust.git/blob - src/librustrt/c_str.rs
auto merge of #15565 : alexcrichton/rust/issue-15475, r=huonw
[rust.git] / src / librustrt / 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 /*!
12
13 C-string manipulation and management
14
15 This modules provides the basic methods for creating and manipulating
16 null-terminated strings for use with FFI calls (back to C). Most C APIs require
17 that the string being passed to them is null-terminated, and by default rust's
18 string types are *not* null terminated.
19
20 The other problem with translating Rust strings to C strings is that Rust
21 strings can validly contain a null-byte in the middle of the string (0 is a
22 valid unicode codepoint). This means that not all Rust strings can actually be
23 translated to C strings.
24
25 # Creation of a C string
26
27 A C string is managed through the `CString` type defined in this module. It
28 "owns" the internal buffer of characters and will automatically deallocate the
29 buffer when the string is dropped. The `ToCStr` trait is implemented for `&str`
30 and `&[u8]`, but the conversions can fail due to some of the limitations
31 explained above.
32
33 This also means that currently whenever a C string is created, an allocation
34 must be performed to place the data elsewhere (the lifetime of the C string is
35 not tied to the lifetime of the original string/data buffer). If C strings are
36 heavily used in applications, then caching may be advisable to prevent
37 unnecessary amounts of allocations.
38
39 An example of creating and using a C string would be:
40
41 ```rust
42 extern crate libc;
43
44 extern {
45     fn puts(s: *const libc::c_char);
46 }
47
48 fn main() {
49     let my_string = "Hello, world!";
50
51     // Allocate the C string with an explicit local that owns the string. The
52     // `c_buffer` pointer will be deallocated when `my_c_string` goes out of scope.
53     let my_c_string = my_string.to_c_str();
54     unsafe {
55         puts(my_c_string.as_ptr());
56     }
57
58     // Don't save/return the pointer to the C string, the `c_buffer` will be
59     // deallocated when this block returns!
60     my_string.with_c_str(|c_buffer| {
61         unsafe { puts(c_buffer); }
62     });
63 }
64 ```
65
66 */
67
68 use core::prelude::*;
69
70 use alloc::libc_heap::malloc_raw;
71 use collections::string::String;
72 use collections::hash;
73 use core::kinds::marker;
74 use core::mem;
75 use core::ptr;
76 use core::raw::Slice;
77 use core::slice;
78 use core::str;
79 use libc;
80
81 /// The representation of a C String.
82 ///
83 /// This structure wraps a `*libc::c_char`, and will automatically free the
84 /// memory it is pointing to when it goes out of scope.
85 pub struct CString {
86     buf: *const libc::c_char,
87     owns_buffer_: bool,
88 }
89
90 impl Clone for CString {
91     /// Clone this CString into a new, uniquely owned CString. For safety
92     /// reasons, this is always a deep clone, rather than the usual shallow
93     /// clone.
94     fn clone(&self) -> CString {
95         if self.buf.is_null() {
96             CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
97         } else {
98             let len = self.len() + 1;
99             let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
100             unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
101             CString { buf: buf as *const libc::c_char, owns_buffer_: true }
102         }
103     }
104 }
105
106 impl PartialEq for CString {
107     fn eq(&self, other: &CString) -> bool {
108         if self.buf as uint == other.buf as uint {
109             true
110         } else if self.buf.is_null() || other.buf.is_null() {
111             false
112         } else {
113             unsafe {
114                 libc::strcmp(self.buf, other.buf) == 0
115             }
116         }
117     }
118 }
119
120 impl PartialOrd for CString {
121     #[inline]
122     fn partial_cmp(&self, other: &CString) -> Option<Ordering> {
123         self.as_bytes().partial_cmp(&other.as_bytes())
124     }
125 }
126
127 impl Eq for CString {}
128
129 impl<S: hash::Writer> hash::Hash<S> for CString {
130     #[inline]
131     fn hash(&self, state: &mut S) {
132         self.as_bytes().hash(state)
133     }
134 }
135
136 impl CString {
137     /// Create a C String from a pointer.
138     pub unsafe fn new(buf: *const libc::c_char, owns_buffer: bool) -> CString {
139         CString { buf: buf, owns_buffer_: owns_buffer }
140     }
141
142     /// Return a pointer to the NUL-terminated string data.
143     ///
144     /// `.as_ptr` returns an internal pointer into the `CString`, and
145     /// may be invalidated when the `CString` falls out of scope (the
146     /// destructor will run, freeing the allocation if there is
147     /// one).
148     ///
149     /// ```rust
150     /// let foo = "some string";
151     ///
152     /// // right
153     /// let x = foo.to_c_str();
154     /// let p = x.as_ptr();
155     ///
156     /// // wrong (the CString will be freed, invalidating `p`)
157     /// let p = foo.to_c_str().as_ptr();
158     /// ```
159     ///
160     /// # Failure
161     ///
162     /// Fails if the CString is null.
163     ///
164     /// # Example
165     ///
166     /// ```rust
167     /// extern crate libc;
168     ///
169     /// fn main() {
170     ///     let c_str = "foo bar".to_c_str();
171     ///     unsafe {
172     ///         libc::puts(c_str.as_ptr());
173     ///     }
174     /// }
175     /// ```
176     pub fn as_ptr(&self) -> *const libc::c_char {
177         if self.buf.is_null() { fail!("CString is null!"); }
178
179         self.buf
180     }
181
182     /// Return a mutable pointer to the NUL-terminated string data.
183     ///
184     /// `.as_mut_ptr` returns an internal pointer into the `CString`, and
185     /// may be invalidated when the `CString` falls out of scope (the
186     /// destructor will run, freeing the allocation if there is
187     /// one).
188     ///
189     /// ```rust
190     /// let foo = "some string";
191     ///
192     /// // right
193     /// let mut x = foo.to_c_str();
194     /// let p = x.as_mut_ptr();
195     ///
196     /// // wrong (the CString will be freed, invalidating `p`)
197     /// let p = foo.to_c_str().as_mut_ptr();
198     /// ```
199     ///
200     /// # Failure
201     ///
202     /// Fails if the CString is null.
203     pub fn as_mut_ptr(&mut self) -> *mut libc::c_char {
204         if self.buf.is_null() { fail!("CString is null!") }
205
206         self.buf as *mut _
207     }
208
209     /// Calls a closure with a reference to the underlying `*libc::c_char`.
210     ///
211     /// # Failure
212     ///
213     /// Fails if the CString is null.
214     #[deprecated="use `.as_ptr()`"]
215     pub fn with_ref<T>(&self, f: |*const libc::c_char| -> T) -> T {
216         if self.buf.is_null() { fail!("CString is null!"); }
217         f(self.buf)
218     }
219
220     /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
221     ///
222     /// # Failure
223     ///
224     /// Fails if the CString is null.
225     #[deprecated="use `.as_mut_ptr()`"]
226     pub fn with_mut_ref<T>(&mut self, f: |*mut libc::c_char| -> T) -> T {
227         if self.buf.is_null() { fail!("CString is null!"); }
228         f(self.buf as *mut libc::c_char)
229     }
230
231     /// Returns true if the CString is a null.
232     pub fn is_null(&self) -> bool {
233         self.buf.is_null()
234     }
235
236     /// Returns true if the CString is not null.
237     pub fn is_not_null(&self) -> bool {
238         self.buf.is_not_null()
239     }
240
241     /// Returns whether or not the `CString` owns the buffer.
242     pub fn owns_buffer(&self) -> bool {
243         self.owns_buffer_
244     }
245
246     /// Converts the CString into a `&[u8]` without copying.
247     /// Includes the terminating NUL byte.
248     ///
249     /// # Failure
250     ///
251     /// Fails if the CString is null.
252     #[inline]
253     pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
254         if self.buf.is_null() { fail!("CString is null!"); }
255         unsafe {
256             mem::transmute(Slice { data: self.buf, len: self.len() + 1 })
257         }
258     }
259
260     /// Converts the CString into a `&[u8]` without copying.
261     /// Does not include the terminating NUL byte.
262     ///
263     /// # Failure
264     ///
265     /// Fails if the CString is null.
266     #[inline]
267     pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] {
268         if self.buf.is_null() { fail!("CString is null!"); }
269         unsafe {
270             mem::transmute(Slice { data: self.buf, len: self.len() })
271         }
272     }
273
274     /// Converts the CString into a `&str` without copying.
275     /// Returns None if the CString is not UTF-8.
276     ///
277     /// # Failure
278     ///
279     /// Fails if the CString is null.
280     #[inline]
281     pub fn as_str<'a>(&'a self) -> Option<&'a str> {
282         let buf = self.as_bytes_no_nul();
283         str::from_utf8(buf)
284     }
285
286     /// Return a CString iterator.
287     ///
288     /// # Failure
289     ///
290     /// Fails if the CString is null.
291     pub fn iter<'a>(&'a self) -> CChars<'a> {
292         if self.buf.is_null() { fail!("CString is null!"); }
293         CChars {
294             ptr: self.buf,
295             marker: marker::ContravariantLifetime,
296         }
297     }
298
299     /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
300     ///
301     /// Any ownership of the buffer by the `CString` wrapper is
302     /// forgotten, meaning that the backing allocation of this
303     /// `CString` is not automatically freed if it owns the
304     /// allocation. In this case, a user of `.unwrap()` should ensure
305     /// the allocation is freed, to avoid leaking memory.
306     ///
307     /// Prefer `.as_ptr()` when just retrieving a pointer to the
308     /// string data, as that does not relinquish ownership.
309     pub unsafe fn unwrap(mut self) -> *const libc::c_char {
310         self.owns_buffer_ = false;
311         self.buf
312     }
313
314 }
315
316 impl Drop for CString {
317     fn drop(&mut self) {
318         if self.owns_buffer_ {
319             unsafe {
320                 libc::free(self.buf as *mut libc::c_void)
321             }
322         }
323     }
324 }
325
326 impl Collection for CString {
327     /// Return the number of bytes in the CString (not including the NUL terminator).
328     ///
329     /// # Failure
330     ///
331     /// Fails if the CString is null.
332     #[inline]
333     fn len(&self) -> uint {
334         if self.buf.is_null() { fail!("CString is null!"); }
335         let mut cur = self.buf;
336         let mut len = 0;
337         unsafe {
338             while *cur != 0 {
339                 len += 1;
340                 cur = cur.offset(1);
341             }
342         }
343         return len;
344     }
345 }
346
347 /// A generic trait for converting a value to a CString.
348 pub trait ToCStr {
349     /// Copy the receiver into a CString.
350     ///
351     /// # Failure
352     ///
353     /// Fails the task if the receiver has an interior null.
354     fn to_c_str(&self) -> CString;
355
356     /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
357     unsafe fn to_c_str_unchecked(&self) -> CString;
358
359     /// Work with a temporary CString constructed from the receiver.
360     /// The provided `*libc::c_char` will be freed immediately upon return.
361     ///
362     /// # Example
363     ///
364     /// ```rust
365     /// extern crate libc;
366     ///
367     /// fn main() {
368     ///     let s = "PATH".with_c_str(|path| unsafe {
369     ///         libc::getenv(path)
370     ///     });
371     /// }
372     /// ```
373     ///
374     /// # Failure
375     ///
376     /// Fails the task if the receiver has an interior null.
377     #[inline]
378     fn with_c_str<T>(&self, f: |*const libc::c_char| -> T) -> T {
379         let c_str = self.to_c_str();
380         f(c_str.as_ptr())
381     }
382
383     /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
384     #[inline]
385     unsafe fn with_c_str_unchecked<T>(&self, f: |*const libc::c_char| -> T) -> T {
386         let c_str = self.to_c_str_unchecked();
387         f(c_str.as_ptr())
388     }
389 }
390
391 // FIXME (#12938): Until DST lands, we cannot decompose &str into &
392 // and str, so we cannot usefully take ToCStr arguments by reference
393 // (without forcing an additional & around &str). So we are instead
394 // temporarily adding an instance for ~str and String, so that we can
395 // take ToCStr as owned. When DST lands, the string instances should
396 // be revisited, and arguments bound by ToCStr should be passed by
397 // reference.
398
399 impl<'a> ToCStr for &'a str {
400     #[inline]
401     fn to_c_str(&self) -> CString {
402         self.as_bytes().to_c_str()
403     }
404
405     #[inline]
406     unsafe fn to_c_str_unchecked(&self) -> CString {
407         self.as_bytes().to_c_str_unchecked()
408     }
409
410     #[inline]
411     fn with_c_str<T>(&self, f: |*const libc::c_char| -> T) -> T {
412         self.as_bytes().with_c_str(f)
413     }
414
415     #[inline]
416     unsafe fn with_c_str_unchecked<T>(&self, f: |*const libc::c_char| -> T) -> T {
417         self.as_bytes().with_c_str_unchecked(f)
418     }
419 }
420
421 impl ToCStr for String {
422     #[inline]
423     fn to_c_str(&self) -> CString {
424         self.as_bytes().to_c_str()
425     }
426
427     #[inline]
428     unsafe fn to_c_str_unchecked(&self) -> CString {
429         self.as_bytes().to_c_str_unchecked()
430     }
431
432     #[inline]
433     fn with_c_str<T>(&self, f: |*const libc::c_char| -> T) -> T {
434         self.as_bytes().with_c_str(f)
435     }
436
437     #[inline]
438     unsafe fn with_c_str_unchecked<T>(&self, f: |*const libc::c_char| -> T) -> T {
439         self.as_bytes().with_c_str_unchecked(f)
440     }
441 }
442
443 // The length of the stack allocated buffer for `vec.with_c_str()`
444 static BUF_LEN: uint = 128;
445
446 impl<'a> ToCStr for &'a [u8] {
447     fn to_c_str(&self) -> CString {
448         let mut cs = unsafe { self.to_c_str_unchecked() };
449         check_for_null(*self, cs.as_mut_ptr());
450         cs
451     }
452
453     unsafe fn to_c_str_unchecked(&self) -> CString {
454         let self_len = self.len();
455         let buf = malloc_raw(self_len + 1);
456
457         ptr::copy_memory(buf, self.as_ptr(), self_len);
458         *buf.offset(self_len as int) = 0;
459
460         CString::new(buf as *const libc::c_char, true)
461     }
462
463     fn with_c_str<T>(&self, f: |*const libc::c_char| -> T) -> T {
464         unsafe { with_c_str(*self, true, f) }
465     }
466
467     unsafe fn with_c_str_unchecked<T>(&self, f: |*const libc::c_char| -> T) -> T {
468         with_c_str(*self, false, f)
469     }
470 }
471
472 // Unsafe function that handles possibly copying the &[u8] into a stack array.
473 unsafe fn with_c_str<T>(v: &[u8], checked: bool,
474                         f: |*const libc::c_char| -> T) -> T {
475     let c_str = if v.len() < BUF_LEN {
476         let mut buf: [u8, .. BUF_LEN] = mem::uninitialized();
477         slice::bytes::copy_memory(buf, v);
478         buf[v.len()] = 0;
479
480         let buf = buf.as_mut_ptr();
481         if checked {
482             check_for_null(v, buf as *mut libc::c_char);
483         }
484
485         return f(buf as *const libc::c_char)
486     } else if checked {
487         v.to_c_str()
488     } else {
489         v.to_c_str_unchecked()
490     };
491
492     f(c_str.as_ptr())
493 }
494
495 #[inline]
496 fn check_for_null(v: &[u8], buf: *mut libc::c_char) {
497     for i in range(0, v.len()) {
498         unsafe {
499             let p = buf.offset(i as int);
500             assert!(*p != 0);
501         }
502     }
503 }
504
505 /// External iterator for a CString's bytes.
506 ///
507 /// Use with the `std::iter` module.
508 pub struct CChars<'a> {
509     ptr: *const libc::c_char,
510     marker: marker::ContravariantLifetime<'a>,
511 }
512
513 impl<'a> Iterator<libc::c_char> for CChars<'a> {
514     fn next(&mut self) -> Option<libc::c_char> {
515         let ch = unsafe { *self.ptr };
516         if ch == 0 {
517             None
518         } else {
519             self.ptr = unsafe { self.ptr.offset(1) };
520             Some(ch)
521         }
522     }
523 }
524
525 /// Parses a C "multistring", eg windows env values or
526 /// the req->ptr result in a uv_fs_readdir() call.
527 ///
528 /// Optionally, a `count` can be passed in, limiting the
529 /// parsing to only being done `count`-times.
530 ///
531 /// The specified closure is invoked with each string that
532 /// is found, and the number of strings found is returned.
533 pub unsafe fn from_c_multistring(buf: *const libc::c_char,
534                                  count: Option<uint>,
535                                  f: |&CString|) -> uint {
536
537     let mut curr_ptr: uint = buf as uint;
538     let mut ctr = 0;
539     let (limited_count, limit) = match count {
540         Some(limit) => (true, limit),
541         None => (false, 0)
542     };
543     while ((limited_count && ctr < limit) || !limited_count)
544           && *(curr_ptr as *const libc::c_char) != 0 as libc::c_char {
545         let cstr = CString::new(curr_ptr as *const libc::c_char, false);
546         f(&cstr);
547         curr_ptr += cstr.len() + 1;
548         ctr += 1;
549     }
550     return ctr;
551 }
552
553 #[cfg(test)]
554 mod tests {
555     use std::prelude::*;
556     use std::ptr;
557     use std::task;
558     use libc;
559
560     use super::*;
561
562     #[test]
563     fn test_str_multistring_parsing() {
564         unsafe {
565             let input = b"zero\0one\0\0";
566             let ptr = input.as_ptr();
567             let expected = ["zero", "one"];
568             let mut it = expected.iter();
569             let result = from_c_multistring(ptr as *const libc::c_char, None, |c| {
570                 let cbytes = c.as_bytes_no_nul();
571                 assert_eq!(cbytes, it.next().unwrap().as_bytes());
572             });
573             assert_eq!(result, 2);
574             assert!(it.next().is_none());
575         }
576     }
577
578     #[test]
579     fn test_str_to_c_str() {
580         let c_str = "".to_c_str();
581         unsafe {
582             assert_eq!(*c_str.as_ptr().offset(0), 0);
583         }
584
585         let c_str = "hello".to_c_str();
586         let buf = c_str.as_ptr();
587         unsafe {
588             assert_eq!(*buf.offset(0), 'h' as libc::c_char);
589             assert_eq!(*buf.offset(1), 'e' as libc::c_char);
590             assert_eq!(*buf.offset(2), 'l' as libc::c_char);
591             assert_eq!(*buf.offset(3), 'l' as libc::c_char);
592             assert_eq!(*buf.offset(4), 'o' as libc::c_char);
593             assert_eq!(*buf.offset(5), 0);
594         }
595     }
596
597     #[test]
598     fn test_vec_to_c_str() {
599         let b: &[u8] = [];
600         let c_str = b.to_c_str();
601         unsafe {
602             assert_eq!(*c_str.as_ptr().offset(0), 0);
603         }
604
605         let c_str = b"hello".to_c_str();
606         let buf = c_str.as_ptr();
607         unsafe {
608             assert_eq!(*buf.offset(0), 'h' as libc::c_char);
609             assert_eq!(*buf.offset(1), 'e' as libc::c_char);
610             assert_eq!(*buf.offset(2), 'l' as libc::c_char);
611             assert_eq!(*buf.offset(3), 'l' as libc::c_char);
612             assert_eq!(*buf.offset(4), 'o' as libc::c_char);
613             assert_eq!(*buf.offset(5), 0);
614         }
615
616         let c_str = b"foo\xFF".to_c_str();
617         let buf = c_str.as_ptr();
618         unsafe {
619             assert_eq!(*buf.offset(0), 'f' as libc::c_char);
620             assert_eq!(*buf.offset(1), 'o' as libc::c_char);
621             assert_eq!(*buf.offset(2), 'o' as libc::c_char);
622             assert_eq!(*buf.offset(3), 0xffu8 as i8);
623             assert_eq!(*buf.offset(4), 0);
624         }
625     }
626
627     #[test]
628     fn test_is_null() {
629         let c_str = unsafe { CString::new(ptr::null(), false) };
630         assert!(c_str.is_null());
631         assert!(!c_str.is_not_null());
632     }
633
634     #[test]
635     fn test_unwrap() {
636         let c_str = "hello".to_c_str();
637         unsafe { libc::free(c_str.unwrap() as *mut libc::c_void) }
638     }
639
640     #[test]
641     fn test_as_ptr() {
642         let c_str = "hello".to_c_str();
643         let len = unsafe { libc::strlen(c_str.as_ptr()) };
644         assert!(!c_str.is_null());
645         assert!(c_str.is_not_null());
646         assert_eq!(len, 5);
647     }
648     #[test]
649     #[should_fail]
650     fn test_as_ptr_empty_fail() {
651         let c_str = unsafe { CString::new(ptr::null(), false) };
652         c_str.as_ptr();
653     }
654
655     #[test]
656     fn test_iterator() {
657         let c_str = "".to_c_str();
658         let mut iter = c_str.iter();
659         assert_eq!(iter.next(), None);
660
661         let c_str = "hello".to_c_str();
662         let mut iter = c_str.iter();
663         assert_eq!(iter.next(), Some('h' as libc::c_char));
664         assert_eq!(iter.next(), Some('e' as libc::c_char));
665         assert_eq!(iter.next(), Some('l' as libc::c_char));
666         assert_eq!(iter.next(), Some('l' as libc::c_char));
667         assert_eq!(iter.next(), Some('o' as libc::c_char));
668         assert_eq!(iter.next(), None);
669     }
670
671     #[test]
672     fn test_to_c_str_fail() {
673         assert!(task::try(proc() { "he\x00llo".to_c_str() }).is_err());
674     }
675
676     #[test]
677     fn test_to_c_str_unchecked() {
678         unsafe {
679             let c_string = "he\x00llo".to_c_str_unchecked();
680             let buf = c_string.as_ptr();
681             assert_eq!(*buf.offset(0), 'h' as libc::c_char);
682             assert_eq!(*buf.offset(1), 'e' as libc::c_char);
683             assert_eq!(*buf.offset(2), 0);
684             assert_eq!(*buf.offset(3), 'l' as libc::c_char);
685             assert_eq!(*buf.offset(4), 'l' as libc::c_char);
686             assert_eq!(*buf.offset(5), 'o' as libc::c_char);
687             assert_eq!(*buf.offset(6), 0);
688         }
689     }
690
691     #[test]
692     fn test_as_bytes() {
693         let c_str = "hello".to_c_str();
694         assert_eq!(c_str.as_bytes(), b"hello\0");
695         let c_str = "".to_c_str();
696         assert_eq!(c_str.as_bytes(), b"\0");
697         let c_str = b"foo\xFF".to_c_str();
698         assert_eq!(c_str.as_bytes(), b"foo\xFF\0");
699     }
700
701     #[test]
702     fn test_as_bytes_no_nul() {
703         let c_str = "hello".to_c_str();
704         assert_eq!(c_str.as_bytes_no_nul(), b"hello");
705         let c_str = "".to_c_str();
706         let exp: &[u8] = [];
707         assert_eq!(c_str.as_bytes_no_nul(), exp);
708         let c_str = b"foo\xFF".to_c_str();
709         assert_eq!(c_str.as_bytes_no_nul(), b"foo\xFF");
710     }
711
712     #[test]
713     #[should_fail]
714     fn test_as_bytes_fail() {
715         let c_str = unsafe { CString::new(ptr::null(), false) };
716         c_str.as_bytes();
717     }
718
719     #[test]
720     #[should_fail]
721     fn test_as_bytes_no_nul_fail() {
722         let c_str = unsafe { CString::new(ptr::null(), false) };
723         c_str.as_bytes_no_nul();
724     }
725
726     #[test]
727     fn test_as_str() {
728         let c_str = "hello".to_c_str();
729         assert_eq!(c_str.as_str(), Some("hello"));
730         let c_str = "".to_c_str();
731         assert_eq!(c_str.as_str(), Some(""));
732         let c_str = b"foo\xFF".to_c_str();
733         assert_eq!(c_str.as_str(), None);
734     }
735
736     #[test]
737     #[should_fail]
738     fn test_as_str_fail() {
739         let c_str = unsafe { CString::new(ptr::null(), false) };
740         c_str.as_str();
741     }
742
743     #[test]
744     #[should_fail]
745     fn test_len_fail() {
746         let c_str = unsafe { CString::new(ptr::null(), false) };
747         c_str.len();
748     }
749
750     #[test]
751     #[should_fail]
752     fn test_iter_fail() {
753         let c_str = unsafe { CString::new(ptr::null(), false) };
754         c_str.iter();
755     }
756
757     #[test]
758     fn test_clone() {
759         let a = "hello".to_c_str();
760         let b = a.clone();
761         assert!(a == b);
762     }
763
764     #[test]
765     fn test_clone_noleak() {
766         fn foo(f: |c: &CString|) {
767             let s = "test".to_string();
768             let c = s.to_c_str();
769             // give the closure a non-owned CString
770             let mut c_ = unsafe { CString::new(c.as_ptr(), false) };
771             f(&c_);
772             // muck with the buffer for later printing
773             unsafe { *c_.as_mut_ptr() = 'X' as libc::c_char }
774         }
775
776         let mut c_: Option<CString> = None;
777         foo(|c| {
778             c_ = Some(c.clone());
779             c.clone();
780             // force a copy, reading the memory
781             c.as_bytes().to_owned();
782         });
783         let c_ = c_.unwrap();
784         // force a copy, reading the memory
785         c_.as_bytes().to_owned();
786     }
787
788     #[test]
789     fn test_clone_eq_null() {
790         let x = unsafe { CString::new(ptr::null(), false) };
791         let y = x.clone();
792         assert!(x == y);
793     }
794 }
795
796 #[cfg(test)]
797 mod bench {
798     use test::Bencher;
799     use libc;
800     use std::prelude::*;
801
802     #[inline]
803     fn check(s: &str, c_str: *const libc::c_char) {
804         let s_buf = s.as_ptr();
805         for i in range(0, s.len()) {
806             unsafe {
807                 assert_eq!(
808                     *s_buf.offset(i as int) as libc::c_char,
809                     *c_str.offset(i as int));
810             }
811         }
812     }
813
814     static s_short: &'static str = "Mary";
815     static s_medium: &'static str = "Mary had a little lamb";
816     static s_long: &'static str = "\
817         Mary had a little lamb, Little lamb
818         Mary had a little lamb, Little lamb
819         Mary had a little lamb, Little lamb
820         Mary had a little lamb, Little lamb
821         Mary had a little lamb, Little lamb
822         Mary had a little lamb, Little lamb";
823
824     fn bench_to_string(b: &mut Bencher, s: &str) {
825         b.iter(|| {
826             let c_str = s.to_c_str();
827             check(s, c_str.as_ptr());
828         })
829     }
830
831     #[bench]
832     fn bench_to_c_str_short(b: &mut Bencher) {
833         bench_to_string(b, s_short)
834     }
835
836     #[bench]
837     fn bench_to_c_str_medium(b: &mut Bencher) {
838         bench_to_string(b, s_medium)
839     }
840
841     #[bench]
842     fn bench_to_c_str_long(b: &mut Bencher) {
843         bench_to_string(b, s_long)
844     }
845
846     fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) {
847         b.iter(|| {
848             let c_str = unsafe { s.to_c_str_unchecked() };
849             check(s, c_str.as_ptr())
850         })
851     }
852
853     #[bench]
854     fn bench_to_c_str_unchecked_short(b: &mut Bencher) {
855         bench_to_c_str_unchecked(b, s_short)
856     }
857
858     #[bench]
859     fn bench_to_c_str_unchecked_medium(b: &mut Bencher) {
860         bench_to_c_str_unchecked(b, s_medium)
861     }
862
863     #[bench]
864     fn bench_to_c_str_unchecked_long(b: &mut Bencher) {
865         bench_to_c_str_unchecked(b, s_long)
866     }
867
868     fn bench_with_c_str(b: &mut Bencher, s: &str) {
869         b.iter(|| {
870             s.with_c_str(|c_str_buf| check(s, c_str_buf))
871         })
872     }
873
874     #[bench]
875     fn bench_with_c_str_short(b: &mut Bencher) {
876         bench_with_c_str(b, s_short)
877     }
878
879     #[bench]
880     fn bench_with_c_str_medium(b: &mut Bencher) {
881         bench_with_c_str(b, s_medium)
882     }
883
884     #[bench]
885     fn bench_with_c_str_long(b: &mut Bencher) {
886         bench_with_c_str(b, s_long)
887     }
888
889     fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) {
890         b.iter(|| {
891             unsafe {
892                 s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf))
893             }
894         })
895     }
896
897     #[bench]
898     fn bench_with_c_str_unchecked_short(b: &mut Bencher) {
899         bench_with_c_str_unchecked(b, s_short)
900     }
901
902     #[bench]
903     fn bench_with_c_str_unchecked_medium(b: &mut Bencher) {
904         bench_with_c_str_unchecked(b, s_medium)
905     }
906
907     #[bench]
908     fn bench_with_c_str_unchecked_long(b: &mut Bencher) {
909         bench_with_c_str_unchecked(b, s_long)
910     }
911 }