(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_bufferbool) -> 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                                   countOption<uint>,
 407                                   f: |&CString|) -> uint {
 408  
 409      let mut curr_ptruint = 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:- 7
321: 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:- 2
323:         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:- 3
385: 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:- 2
338:     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:- 43
libstd/path/mod.rs:
libstd/path/posix.rs:
libstd/path/windows.rs:
libstd/rt/rtio.rs:
libstd/rt/backtrace.rs:
libstd/rt/rtio.rs: