(index<- ) ./libstd/c_str.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
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: *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 my_c_string.with_ref(|c_buffer| {
55 unsafe { puts(c_buffer); }
56 });
57
58 // Don't save off the allocation of 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 cast;
69 use container::Container;
70 use iter::{Iterator, range};
71 use libc;
72 use kinds::marker;
73 use ops::Drop;
74 use cmp::Eq;
75 use clone::Clone;
76 use mem;
77 use option::{Option, Some, None};
78 use ptr::RawPtr;
79 use ptr;
80 use str::StrSlice;
81 use str;
82 use slice::{ImmutableVector, MutableVector};
83 use slice;
84 use rt::global_heap::malloc_raw;
85 use raw::Slice;
86
87 /// The representation of a C String.
88 ///
89 /// This structure wraps a `*libc::c_char`, and will automatically free the
90 /// memory it is pointing to when it goes out of scope.
91 pub struct CString {
92 buf: *libc::c_char,
93 owns_buffer_: bool,
94 }
95
96 impl Clone for CString {
97 /// Clone this CString into a new, uniquely owned CString. For safety
98 /// reasons, this is always a deep clone, rather than the usual shallow
99 /// clone.
100 fn clone(&self) -> CString {
101 if self.buf.is_null() {
102 CString { buf: self.buf, owns_buffer_: self.owns_buffer_ }
103 } else {
104 let len = self.len() + 1;
105 let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
106 unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
107 CString { buf: buf as *libc::c_char, owns_buffer_: true }
108 }
109 }
110 }
111
112 impl Eq for CString {
113 fn eq(&self, other: &CString) -> bool {
114 if self.buf as uint == other.buf as uint {
115 true
116 } else if self.buf.is_null() || other.buf.is_null() {
117 false
118 } else {
119 unsafe {
120 libc::strcmp(self.buf, other.buf) == 0
121 }
122 }
123 }
124 }
125
126 impl CString {
127 /// Create a C String from a pointer.
128 pub unsafe fn new(buf: *libc::c_char, owns_buffer: bool) -> CString {
129 CString { buf: buf, owns_buffer_: owns_buffer }
130 }
131
132 /// Unwraps the wrapped `*libc::c_char` from the `CString` wrapper.
133 /// Any ownership of the buffer by the `CString` wrapper is forgotten.
134 pub unsafe fn unwrap(self) -> *libc::c_char {
135 let mut c_str = self;
136 c_str.owns_buffer_ = false;
137 c_str.buf
138 }
139
140 /// Calls a closure with a reference to the underlying `*libc::c_char`.
141 ///
142 /// # Failure
143 ///
144 /// Fails if the CString is null.
145 pub fn with_ref<T>(&self, f: |*libc::c_char| -> T) -> T {
146 if self.buf.is_null() { fail!("CString is null!"); }
147 f(self.buf)
148 }
149
150 /// Calls a closure with a mutable reference to the underlying `*libc::c_char`.
151 ///
152 /// # Failure
153 ///
154 /// Fails if the CString is null.
155 pub fn with_mut_ref<T>(&mut self, f: |*mut libc::c_char| -> T) -> T {
156 if self.buf.is_null() { fail!("CString is null!"); }
157 f(unsafe { cast::transmute_mut_unsafe(self.buf) })
158 }
159
160 /// Returns true if the CString is a null.
161 pub fn is_null(&self) -> bool {
162 self.buf.is_null()
163 }
164
165 /// Returns true if the CString is not null.
166 pub fn is_not_null(&self) -> bool {
167 self.buf.is_not_null()
168 }
169
170 /// Returns whether or not the `CString` owns the buffer.
171 pub fn owns_buffer(&self) -> bool {
172 self.owns_buffer_
173 }
174
175 /// Converts the CString into a `&[u8]` without copying.
176 /// Includes the terminating NUL byte.
177 ///
178 /// # Failure
179 ///
180 /// Fails if the CString is null.
181 #[inline]
182 pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
183 if self.buf.is_null() { fail!("CString is null!"); }
184 unsafe {
185 cast::transmute(Slice { data: self.buf, len: self.len() + 1 })
186 }
187 }
188
189 /// Converts the CString into a `&[u8]` without copying.
190 /// Does not include the terminating NUL byte.
191 ///
192 /// # Failure
193 ///
194 /// Fails if the CString is null.
195 #[inline]
196 pub fn as_bytes_no_nul<'a>(&'a self) -> &'a [u8] {
197 if self.buf.is_null() { fail!("CString is null!"); }
198 unsafe {
199 cast::transmute(Slice { data: self.buf, len: self.len() })
200 }
201 }
202
203 /// Converts the CString into a `&str` without copying.
204 /// Returns None if the CString is not UTF-8.
205 ///
206 /// # Failure
207 ///
208 /// Fails if the CString is null.
209 #[inline]
210 pub fn as_str<'a>(&'a self) -> Option<&'a str> {
211 let buf = self.as_bytes_no_nul();
212 str::from_utf8(buf)
213 }
214
215 /// Return a CString iterator.
216 ///
217 /// # Failure
218 ///
219 /// Fails if the CString is null.
220 pub fn iter<'a>(&'a self) -> CChars<'a> {
221 if self.buf.is_null() { fail!("CString is null!"); }
222 CChars {
223 ptr: self.buf,
224 marker: marker::ContravariantLifetime,
225 }
226 }
227 }
228
229 impl Drop for CString {
230 fn drop(&mut self) {
231 if self.owns_buffer_ {
232 unsafe {
233 libc::free(self.buf as *mut libc::c_void)
234 }
235 }
236 }
237 }
238
239 impl Container for CString {
240 /// Return the number of bytes in the CString (not including the NUL terminator).
241 ///
242 /// # Failure
243 ///
244 /// Fails if the CString is null.
245 #[inline]
246 fn len(&self) -> uint {
247 if self.buf.is_null() { fail!("CString is null!"); }
248 unsafe {
249 ptr::position(self.buf, |c| *c == 0)
250 }
251 }
252 }
253
254 /// A generic trait for converting a value to a CString.
255 pub trait ToCStr {
256 /// Copy the receiver into a CString.
257 ///
258 /// # Failure
259 ///
260 /// Fails the task if the receiver has an interior null.
261 fn to_c_str(&self) -> CString;
262
263 /// Unsafe variant of `to_c_str()` that doesn't check for nulls.
264 unsafe fn to_c_str_unchecked(&self) -> CString;
265
266 /// Work with a temporary CString constructed from the receiver.
267 /// The provided `*libc::c_char` will be freed immediately upon return.
268 ///
269 /// # Example
270 ///
271 /// ```rust
272 /// extern crate libc;
273 ///
274 /// fn main() {
275 /// let s = "PATH".with_c_str(|path| unsafe {
276 /// libc::getenv(path)
277 /// });
278 /// }
279 /// ```
280 ///
281 /// # Failure
282 ///
283 /// Fails the task if the receiver has an interior null.
284 #[inline]
285 fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
286 self.to_c_str().with_ref(f)
287 }
288
289 /// Unsafe variant of `with_c_str()` that doesn't check for nulls.
290 #[inline]
291 unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
292 self.to_c_str_unchecked().with_ref(f)
293 }
294 }
295
296 impl<'a> ToCStr for &'a str {
297 #[inline]
298 fn to_c_str(&self) -> CString {
299 self.as_bytes().to_c_str()
300 }
301
302 #[inline]
303 unsafe fn to_c_str_unchecked(&self) -> CString {
304 self.as_bytes().to_c_str_unchecked()
305 }
306
307 #[inline]
308 fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
309 self.as_bytes().with_c_str(f)
310 }
311
312 #[inline]
313 unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
314 self.as_bytes().with_c_str_unchecked(f)
315 }
316 }
317
318 // The length of the stack allocated buffer for `vec.with_c_str()`
319 static BUF_LEN: uint = 128;
320
321 impl<'a> ToCStr for &'a [u8] {
322 fn to_c_str(&self) -> CString {
323 let mut cs = unsafe { self.to_c_str_unchecked() };
324 cs.with_mut_ref(|buf| check_for_null(*self, buf));
325 cs
326 }
327
328 unsafe fn to_c_str_unchecked(&self) -> CString {
329 let self_len = self.len();
330 let buf = malloc_raw(self_len + 1);
331
332 ptr::copy_memory(buf, self.as_ptr(), self_len);
333 *buf.offset(self_len as int) = 0;
334
335 CString::new(buf as *libc::c_char, true)
336 }
337
338 fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
339 unsafe { with_c_str(*self, true, f) }
340 }
341
342 unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
343 with_c_str(*self, false, f)
344 }
345 }
346
347 // Unsafe function that handles possibly copying the &[u8] into a stack array.
348 unsafe fn with_c_str<T>(v: &[u8], checked: bool, f: |*libc::c_char| -> T) -> T {
349 if v.len() < BUF_LEN {
350 let mut buf: [u8, .. BUF_LEN] = mem::uninit();
351 slice::bytes::copy_memory(buf, v);
352 buf[v.len()] = 0;
353
354 let buf = buf.as_mut_ptr();
355 if checked {
356 check_for_null(v, buf as *mut libc::c_char);
357 }
358
359 f(buf as *libc::c_char)
360 } else if checked {
361 v.to_c_str().with_ref(f)
362 } else {
363 v.to_c_str_unchecked().with_ref(f)
364 }
365 }
366
367 #[inline]
368 fn check_for_null(v: &[u8], buf: *mut libc::c_char) {
369 for i in range(0, v.len()) {
370 unsafe {
371 let p = buf.offset(i as int);
372 assert!(*p != 0);
373 }
374 }
375 }
376
377 /// External iterator for a CString's bytes.
378 ///
379 /// Use with the `std::iter` module.
380 pub struct CChars<'a> {
381 ptr: *libc::c_char,
382 marker: marker::ContravariantLifetime<'a>,
383 }
384
385 impl<'a> Iterator<libc::c_char> for CChars<'a> {
386 fn next(&mut self) -> Option<libc::c_char> {
387 let ch = unsafe { *self.ptr };
388 if ch == 0 {
389 None
390 } else {
391 self.ptr = unsafe { self.ptr.offset(1) };
392 Some(ch)
393 }
394 }
395 }
396
397 /// Parses a C "multistring", eg windows env values or
398 /// the req->ptr result in a uv_fs_readdir() call.
399 ///
400 /// Optionally, a `count` can be passed in, limiting the
401 /// parsing to only being done `count`-times.
402 ///
403 /// The specified closure is invoked with each string that
404 /// is found, and the number of strings found is returned.
405 pub unsafe fn from_c_multistring(buf: *libc::c_char,
406 count: Option<uint>,
407 f: |&CString|) -> uint {
408
409 let mut curr_ptr: uint = buf as uint;
410 let mut ctr = 0;
411 let (limited_count, limit) = match count {
412 Some(limit) => (true, limit),
413 None => (false, 0)
414 };
415 while ((limited_count && ctr < limit) || !limited_count)
416 && *(curr_ptr as *libc::c_char) != 0 as libc::c_char {
417 let cstr = CString::new(curr_ptr as *libc::c_char, false);
418 f(&cstr);
419 curr_ptr += cstr.len() + 1;
420 ctr += 1;
421 }
422 return ctr;
423 }
424
425 #[cfg(test)]
426 mod tests {
427 use prelude::*;
428 use super::*;
429 use libc;
430 use ptr;
431 use str::StrSlice;
432
433 #[test]
434 fn test_str_multistring_parsing() {
435 unsafe {
436 let input = bytes!("zero", "\x00", "one", "\x00", "\x00");
437 let ptr = input.as_ptr();
438 let expected = ["zero", "one"];
439 let mut it = expected.iter();
440 let result = from_c_multistring(ptr as *libc::c_char, None, |c| {
441 let cbytes = c.as_bytes_no_nul();
442 assert_eq!(cbytes, it.next().unwrap().as_bytes());
443 });
444 assert_eq!(result, 2);
445 assert!(it.next().is_none());
446 }
447 }
448
449 #[test]
450 fn test_str_to_c_str() {
451 "".to_c_str().with_ref(|buf| {
452 unsafe {
453 assert_eq!(*buf.offset(0), 0);
454 }
455 });
456
457 "hello".to_c_str().with_ref(|buf| {
458 unsafe {
459 assert_eq!(*buf.offset(0), 'h' as libc::c_char);
460 assert_eq!(*buf.offset(1), 'e' as libc::c_char);
461 assert_eq!(*buf.offset(2), 'l' as libc::c_char);
462 assert_eq!(*buf.offset(3), 'l' as libc::c_char);
463 assert_eq!(*buf.offset(4), 'o' as libc::c_char);
464 assert_eq!(*buf.offset(5), 0);
465 }
466 })
467 }
468
469 #[test]
470 fn test_vec_to_c_str() {
471 let b: &[u8] = [];
472 b.to_c_str().with_ref(|buf| {
473 unsafe {
474 assert_eq!(*buf.offset(0), 0);
475 }
476 });
477
478 let _ = bytes!("hello").to_c_str().with_ref(|buf| {
479 unsafe {
480 assert_eq!(*buf.offset(0), 'h' as libc::c_char);
481 assert_eq!(*buf.offset(1), 'e' as libc::c_char);
482 assert_eq!(*buf.offset(2), 'l' as libc::c_char);
483 assert_eq!(*buf.offset(3), 'l' as libc::c_char);
484 assert_eq!(*buf.offset(4), 'o' as libc::c_char);
485 assert_eq!(*buf.offset(5), 0);
486 }
487 });
488
489 let _ = bytes!("foo", 0xff).to_c_str().with_ref(|buf| {
490 unsafe {
491 assert_eq!(*buf.offset(0), 'f' as libc::c_char);
492 assert_eq!(*buf.offset(1), 'o' as libc::c_char);
493 assert_eq!(*buf.offset(2), 'o' as libc::c_char);
494 assert_eq!(*buf.offset(3), 0xff as i8);
495 assert_eq!(*buf.offset(4), 0);
496 }
497 });
498 }
499
500 #[test]
501 fn test_is_null() {
502 let c_str = unsafe { CString::new(ptr::null(), false) };
503 assert!(c_str.is_null());
504 assert!(!c_str.is_not_null());
505 }
506
507 #[test]
508 fn test_unwrap() {
509 let c_str = "hello".to_c_str();
510 unsafe { libc::free(c_str.unwrap() as *mut libc::c_void) }
511 }
512
513 #[test]
514 fn test_with_ref() {
515 let c_str = "hello".to_c_str();
516 let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
517 assert!(!c_str.is_null());
518 assert!(c_str.is_not_null());
519 assert_eq!(len, 5);
520 }
521
522 #[test]
523 #[should_fail]
524 fn test_with_ref_empty_fail() {
525 let c_str = unsafe { CString::new(ptr::null(), false) };
526 c_str.with_ref(|_| ());
527 }
528
529 #[test]
530 fn test_iterator() {
531 let c_str = "".to_c_str();
532 let mut iter = c_str.iter();
533 assert_eq!(iter.next(), None);
534
535 let c_str = "hello".to_c_str();
536 let mut iter = c_str.iter();
537 assert_eq!(iter.next(), Some('h' as libc::c_char));
538 assert_eq!(iter.next(), Some('e' as libc::c_char));
539 assert_eq!(iter.next(), Some('l' as libc::c_char));
540 assert_eq!(iter.next(), Some('l' as libc::c_char));
541 assert_eq!(iter.next(), Some('o' as libc::c_char));
542 assert_eq!(iter.next(), None);
543 }
544
545 #[test]
546 fn test_to_c_str_fail() {
547 use task;
548 assert!(task::try(proc() { "he\x00llo".to_c_str() }).is_err());
549 }
550
551 #[test]
552 fn test_to_c_str_unchecked() {
553 unsafe {
554 "he\x00llo".to_c_str_unchecked().with_ref(|buf| {
555 assert_eq!(*buf.offset(0), 'h' as libc::c_char);
556 assert_eq!(*buf.offset(1), 'e' as libc::c_char);
557 assert_eq!(*buf.offset(2), 0);
558 assert_eq!(*buf.offset(3), 'l' as libc::c_char);
559 assert_eq!(*buf.offset(4), 'l' as libc::c_char);
560 assert_eq!(*buf.offset(5), 'o' as libc::c_char);
561 assert_eq!(*buf.offset(6), 0);
562 })
563 }
564 }
565
566 #[test]
567 fn test_as_bytes() {
568 let c_str = "hello".to_c_str();
569 assert_eq!(c_str.as_bytes(), bytes!("hello", 0));
570 let c_str = "".to_c_str();
571 assert_eq!(c_str.as_bytes(), bytes!(0));
572 let c_str = bytes!("foo", 0xff).to_c_str();
573 assert_eq!(c_str.as_bytes(), bytes!("foo", 0xff, 0));
574 }
575
576 #[test]
577 fn test_as_bytes_no_nul() {
578 let c_str = "hello".to_c_str();
579 assert_eq!(c_str.as_bytes_no_nul(), bytes!("hello"));
580 let c_str = "".to_c_str();
581 let exp: &[u8] = [];
582 assert_eq!(c_str.as_bytes_no_nul(), exp);
583 let c_str = bytes!("foo", 0xff).to_c_str();
584 assert_eq!(c_str.as_bytes_no_nul(), bytes!("foo", 0xff));
585 }
586
587 #[test]
588 #[should_fail]
589 fn test_as_bytes_fail() {
590 let c_str = unsafe { CString::new(ptr::null(), false) };
591 c_str.as_bytes();
592 }
593
594 #[test]
595 #[should_fail]
596 fn test_as_bytes_no_nul_fail() {
597 let c_str = unsafe { CString::new(ptr::null(), false) };
598 c_str.as_bytes_no_nul();
599 }
600
601 #[test]
602 fn test_as_str() {
603 let c_str = "hello".to_c_str();
604 assert_eq!(c_str.as_str(), Some("hello"));
605 let c_str = "".to_c_str();
606 assert_eq!(c_str.as_str(), Some(""));
607 let c_str = bytes!("foo", 0xff).to_c_str();
608 assert_eq!(c_str.as_str(), None);
609 }
610
611 #[test]
612 #[should_fail]
613 fn test_as_str_fail() {
614 let c_str = unsafe { CString::new(ptr::null(), false) };
615 c_str.as_str();
616 }
617
618 #[test]
619 #[should_fail]
620 fn test_len_fail() {
621 let c_str = unsafe { CString::new(ptr::null(), false) };
622 c_str.len();
623 }
624
625 #[test]
626 #[should_fail]
627 fn test_iter_fail() {
628 let c_str = unsafe { CString::new(ptr::null(), false) };
629 c_str.iter();
630 }
631
632 #[test]
633 fn test_clone() {
634 let a = "hello".to_c_str();
635 let b = a.clone();
636 assert!(a == b);
637 }
638
639 #[test]
640 fn test_clone_noleak() {
641 fn foo(f: |c: &CString|) {
642 let s = "test".to_owned();
643 let c = s.to_c_str();
644 // give the closure a non-owned CString
645 let mut c_ = c.with_ref(|c| unsafe { CString::new(c, false) } );
646 f(&c_);
647 // muck with the buffer for later printing
648 c_.with_mut_ref(|c| unsafe { *c = 'X' as libc::c_char } );
649 }
650
651 let mut c_: Option<CString> = None;
652 foo(|c| {
653 c_ = Some(c.clone());
654 c.clone();
655 // force a copy, reading the memory
656 c.as_bytes().to_owned();
657 });
658 let c_ = c_.unwrap();
659 // force a copy, reading the memory
660 c_.as_bytes().to_owned();
661 }
662
663 #[test]
664 fn test_clone_eq_null() {
665 let x = unsafe { CString::new(ptr::null(), false) };
666 let y = x.clone();
667 assert!(x == y);
668 }
669 }
670
671 #[cfg(test)]
672 mod bench {
673 extern crate test;
674 use self::test::Bencher;
675 use libc;
676 use prelude::*;
677
678 #[inline]
679 fn check(s: &str, c_str: *libc::c_char) {
680 let s_buf = s.as_ptr();
681 for i in range(0, s.len()) {
682 unsafe {
683 assert_eq!(
684 *s_buf.offset(i as int) as libc::c_char,
685 *c_str.offset(i as int));
686 }
687 }
688 }
689
690 static s_short: &'static str = "Mary";
691 static s_medium: &'static str = "Mary had a little lamb";
692 static s_long: &'static str = "\
693 Mary had a little lamb, Little lamb
694 Mary had a little lamb, Little lamb
695 Mary had a little lamb, Little lamb
696 Mary had a little lamb, Little lamb
697 Mary had a little lamb, Little lamb
698 Mary had a little lamb, Little lamb";
699
700 fn bench_to_str(b: &mut Bencher, s: &str) {
701 b.iter(|| {
702 let c_str = s.to_c_str();
703 c_str.with_ref(|c_str_buf| check(s, c_str_buf))
704 })
705 }
706
707 #[bench]
708 fn bench_to_c_str_short(b: &mut Bencher) {
709 bench_to_str(b, s_short)
710 }
711
712 #[bench]
713 fn bench_to_c_str_medium(b: &mut Bencher) {
714 bench_to_str(b, s_medium)
715 }
716
717 #[bench]
718 fn bench_to_c_str_long(b: &mut Bencher) {
719 bench_to_str(b, s_long)
720 }
721
722 fn bench_to_c_str_unchecked(b: &mut Bencher, s: &str) {
723 b.iter(|| {
724 let c_str = unsafe { s.to_c_str_unchecked() };
725 c_str.with_ref(|c_str_buf| check(s, c_str_buf))
726 })
727 }
728
729 #[bench]
730 fn bench_to_c_str_unchecked_short(b: &mut Bencher) {
731 bench_to_c_str_unchecked(b, s_short)
732 }
733
734 #[bench]
735 fn bench_to_c_str_unchecked_medium(b: &mut Bencher) {
736 bench_to_c_str_unchecked(b, s_medium)
737 }
738
739 #[bench]
740 fn bench_to_c_str_unchecked_long(b: &mut Bencher) {
741 bench_to_c_str_unchecked(b, s_long)
742 }
743
744 fn bench_with_c_str(b: &mut Bencher, s: &str) {
745 b.iter(|| {
746 s.with_c_str(|c_str_buf| check(s, c_str_buf))
747 })
748 }
749
750 #[bench]
751 fn bench_with_c_str_short(b: &mut Bencher) {
752 bench_with_c_str(b, s_short)
753 }
754
755 #[bench]
756 fn bench_with_c_str_medium(b: &mut Bencher) {
757 bench_with_c_str(b, s_medium)
758 }
759
760 #[bench]
761 fn bench_with_c_str_long(b: &mut Bencher) {
762 bench_with_c_str(b, s_long)
763 }
764
765 fn bench_with_c_str_unchecked(b: &mut Bencher, s: &str) {
766 b.iter(|| {
767 unsafe {
768 s.with_c_str_unchecked(|c_str_buf| check(s, c_str_buf))
769 }
770 })
771 }
772
773 #[bench]
774 fn bench_with_c_str_unchecked_short(b: &mut Bencher) {
775 bench_with_c_str_unchecked(b, s_short)
776 }
777
778 #[bench]
779 fn bench_with_c_str_unchecked_medium(b: &mut Bencher) {
780 bench_with_c_str_unchecked(b, s_medium)
781 }
782
783 #[bench]
784 fn bench_with_c_str_unchecked_long(b: &mut Bencher) {
785 bench_with_c_str_unchecked(b, s_long)
786 }
787 }
libstd/c_str.rs:254:57-254:57 -trait- definition:
/// A generic trait for converting a value to a CString.
pub trait ToCStr {
/// Copy the receiver into a CString.
references:- 7321: impl<'a> ToCStr for &'a [u8] {
322: fn to_c_str(&self) -> CString {
libstd/io/net/unix.rs:
69: #[experimental = "the timeout argument is likely to change types"]
70: pub fn connect_timeout<P: ToCStr>(path: &P,
71: timeout_ms: u64) -> IoResult<UnixStream> {
--
164: /// ```
165: pub fn bind<P: ToCStr>(path: &P) -> IoResult<UnixListener> {
166: LocalIo::maybe_raise(|io| {
libstd/path/posix.rs:
82: impl ToCStr for Path {
83: #[inline]
libstd/path/windows.rs:
106: impl ToCStr for Path {
107: #[inline]
libstd/io/net/unix.rs:
57: /// ```
58: pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
59: LocalIo::maybe_raise(|io| {
libstd/c_str.rs:367:10-367:10 -fn- definition:
fn check_for_null(v: &[u8], buf: *mut libc::c_char) {
for i in range(0, v.len()) {
unsafe {
references:- 2323: let mut cs = unsafe { self.to_c_str_unchecked() };
324: cs.with_mut_ref(|buf| check_for_null(*self, buf));
325: cs
--
355: if checked {
356: check_for_null(v, buf as *mut libc::c_char);
357: }
libstd/c_str.rs:379:37-379:37 -struct- definition:
/// Use with the `std::iter` module.
pub struct CChars<'a> {
ptr: *libc::c_char,
references:- 3385: impl<'a> Iterator<libc::c_char> for CChars<'a> {
386: fn next(&mut self) -> Option<libc::c_char> {
libstd/c_str.rs:347:79-347:79 -fn- definition:
// Unsafe function that handles possibly copying the &[u8] into a stack array.
unsafe fn with_c_str<T>(v: &[u8], checked: bool, f: |*libc::c_char| -> T) -> T {
if v.len() < BUF_LEN {
references:- 2338: fn with_c_str<T>(&self, f: |*libc::c_char| -> T) -> T {
339: unsafe { with_c_str(*self, true, f) }
340: }
--
342: unsafe fn with_c_str_unchecked<T>(&self, f: |*libc::c_char| -> T) -> T {
343: with_c_str(*self, false, f)
344: }
libstd/c_str.rs:90:56-90:56 -struct- definition:
/// memory it is pointing to when it goes out of scope.
pub struct CString {
buf: *libc::c_char,
references:- 43libstd/path/mod.rs:
libstd/path/posix.rs:
libstd/path/windows.rs:
libstd/rt/rtio.rs:
libstd/rt/backtrace.rs:
libstd/rt/rtio.rs: