// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use option::*;
-use result::*;
-use ops::Drop;
-use cell::Cell;
-use cast;
+use c_str::ToCStr;
use cast::transmute;
+use cast;
+use cell::Cell;
use clone::Clone;
use libc::{c_int, c_uint, c_void};
+use ops::Drop;
+use option::*;
use ptr;
+use result::*;
use rt::io::IoError;
- use rt::io::net::ip::{IpAddr, Ipv4, Ipv6};
+ use rt::io::net::ip::{SocketAddr, IpAddr};
-use rt::uv::*;
-use rt::uv::idle::IdleWatcher;
-use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
+use rt::io::{standard_error, OtherIoError};
+use rt::local::Local;
use rt::rtio::*;
use rt::sched::Scheduler;
-use rt::io::{standard_error, OtherIoError};
use rt::tube::Tube;
-use rt::local::Local;
-use str::StrSlice;
+use rt::uv::*;
+use rt::uv::idle::IdleWatcher;
- use rt::uv::net::{UvIpv4, UvIpv6};
++use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
use unstable::sync::Exclusive;
#[cfg(test)] use container::Container;
}
fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
- let ip_str = match multi {
- Ipv4(x1, x2, x3, x4, _) =>
- fmt!("%u.%u.%u.%u", x1 as uint, x2 as uint, x3 as uint, x4 as uint),
- Ipv6(x1, x2, x3, x4, x5, x6, x7, x8, _) =>
- fmt!("%x:%x:%x:%x:%x:%x:%x:%x",
- x1 as uint, x2 as uint, x3 as uint, x4 as uint,
- x5 as uint, x6 as uint, x7 as uint, x8 as uint),
- };
-
let r = unsafe {
- do ip_str.to_c_str().with_ref |m_addr| {
- do multi.to_str().as_c_str |m_addr| {
++ do multi.to_str().to_c_str().with_ref |m_addr| {
uvll::udp_set_membership(self.native_handle(), m_addr,
ptr::null(), uvll::UV_JOIN_GROUP)
}
}
fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
- let ip_str = match multi {
- Ipv4(x1, x2, x3, x4, _) =>
- fmt!("%u.%u.%u.%u", x1 as uint, x2 as uint, x3 as uint, x4 as uint),
- Ipv6(x1, x2, x3, x4, x5, x6, x7, x8, _) =>
- fmt!("%x:%x:%x:%x:%x:%x:%x:%x",
- x1 as uint, x2 as uint, x3 as uint, x4 as uint,
- x5 as uint, x6 as uint, x7 as uint, x8 as uint),
- };
-
let r = unsafe {
- do ip_str.to_c_str().with_ref |m_addr| {
- do multi.to_str().as_c_str |m_addr| {
++ do multi.to_str().to_c_str().with_ref |m_addr| {
uvll::udp_set_membership(self.native_handle(), m_addr,
ptr::null(), uvll::UV_LEAVE_GROUP)
}
}
#[cfg(unix)]
-fn with_argv<T>(prog: &str, args: &[~str],
- cb: &fn(**libc::c_char) -> T) -> T {
- let mut argptrs = ~[prog.as_c_str(|b| b)];
- let mut tmps = ~[];
+fn with_argv<T>(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T {
+ // We can't directly convert `str`s into `*char`s, as someone needs to hold
+ // a reference to the intermediary byte buffers. So first build an array to
+ // hold all the ~[u8] byte strings.
+ let mut tmps = vec::with_capacity(args.len() + 1);
+
+ tmps.push(prog.to_c_str());
+
- foreach arg in args.iter() {
+ for arg in args.iter() {
- let t = @(*arg).clone();
- tmps.push(t);
- argptrs.push(t.as_c_str(|b| b));
+ tmps.push(arg.to_c_str());
}
- argptrs.push(ptr::null());
- argptrs.as_imm_buf(|buf, _len| cb(buf))
+
+ // Next, convert each of the byte strings into a pointer. This is
+ // technically unsafe as the caller could leak these pointers out of our
+ // scope.
+ let mut ptrs = do tmps.map |tmp| {
+ tmp.with_ref(|buf| buf)
+ };
+
+ // Finally, make sure we add a null pointer.
+ ptrs.push(ptr::null());
+
+ ptrs.as_imm_buf(|buf, _| cb(buf))
}
#[cfg(unix)]
fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*c_void) -> T) -> T {
- // On posixy systems we can pass a char** for envp, which is
- // a null-terminated array of "k=v\n" strings.
+ // On posixy systems we can pass a char** for envp, which is a
+ // null-terminated array of "k=v\n" strings. Like `with_argv`, we have to
+ // have a temporary buffer to hold the intermediary `~[u8]` byte strings.
match env {
- Some(es) => {
- let mut tmps = ~[];
- let mut ptrs = ~[];
-
- for pair in es.iter() {
- // Use of match here is just to workaround limitations
- // in the stage0 irrefutable pattern impl.
- match pair {
- &(ref k, ref v) => {
- let kv = @fmt!("%s=%s", *k, *v);
- tmps.push(kv);
- ptrs.push(kv.as_c_str(|b| b));
- }
+ Some(env) => {
+ let mut tmps = vec::with_capacity(env.len());
+
- foreach pair in env.iter() {
++ for pair in env.iter() {
+ // Use of match here is just to workaround limitations
+ // in the stage0 irrefutable pattern impl.
+ let kv = fmt!("%s=%s", pair.first(), pair.second());
+ tmps.push(kv.to_c_str());
}
- }
- ptrs.push(ptr::null());
- ptrs.as_imm_buf(|p, _len|
- unsafe { cb(::cast::transmute(p)) }
- )
- }
- _ => cb(ptr::null())
+ // Once again, this is unsafe.
+ let mut ptrs = do tmps.map |tmp| {
+ tmp.with_ref(|buf| buf)
+ };
+ ptrs.push(ptr::null());
+
+ do ptrs.as_imm_buf |buf, _| {
+ unsafe { cb(cast::transmute(buf)) }
+ }
+ }
+ _ => cb(ptr::null())
}
}
// rather a concatenation of null-terminated k=v\0 sequences, with a final
// \0 to terminate.
match env {
- Some(es) => {
- let mut blk = ~[];
- for pair in es.iter() {
- let kv = fmt!("%s=%s", pair.first(), pair.second());
- blk.push_all(kv.to_bytes_with_null());
- }
- blk.push(0);
- blk.as_imm_buf(|p, _len|
- unsafe { cb(::cast::transmute(p)) }
- )
- }
- _ => cb(ptr::mut_null())
+ Some(env) => {
+ let mut blk = ~[];
+
- foreach pair in env.iter() {
++ for pair in env.iter() {
+ let kv = fmt!("%s=%s", pair.first(), pair.second());
+ blk.push_all(kv.as_bytes());
+ blk.push(0);
+ }
+
+ blk.push(0);
+
+ do blk.as_imm_buf |p, _len| {
+ unsafe { cb(cast::transmute(p)) }
+ }
+ }
+ _ => cb(ptr::mut_null())
}
}
s
}
- foreach ss in self.iter() {
+ /// Concatenate a vector of strings.
+ #[cfg(not(stage0))]
+ pub fn concat(&self) -> ~str {
+ if self.is_empty() { return ~""; }
+
+ let len = self.iter().transform(|s| s.as_slice().len()).sum();
+
+ let mut s = with_capacity(len);
+
+ unsafe {
+ do s.as_mut_buf |buf, _| {
+ let mut buf = buf;
++ for ss in self.iter() {
+ do ss.as_slice().as_imm_buf |ssbuf, sslen| {
+ ptr::copy_memory(buf, ssbuf, sslen);
+ buf = buf.offset(sslen as int);
+ }
+ }
+ }
+ raw::set_len(&mut s, len);
+ }
+ s
+ }
+
/// Concatenate a vector of strings, placing a given separator between each.
+ #[cfg(stage0)]
pub fn connect(&self, sep: &str) -> ~str {
if self.is_empty() { return ~""; }
}
s
}
- foreach ss in self.iter() {
+
+ /// Concatenate a vector of strings, placing a given separator between each.
+ #[cfg(not(stage0))]
+ pub fn connect(&self, sep: &str) -> ~str {
+ if self.is_empty() { return ~""; }
+
+ // concat is faster
+ if sep.is_empty() { return self.concat(); }
+
+ // this is wrong without the guarantee that `self` is non-empty
+ let len = sep.len() * (self.len() - 1)
+ + self.iter().transform(|s| s.as_slice().len()).sum();
+ let mut s = ~"";
+ let mut first = true;
+
+ s.reserve(len);
+
+ unsafe {
+ do s.as_mut_buf |buf, _| {
+ do sep.as_imm_buf |sepbuf, seplen| {
+ let mut buf = buf;
++ for ss in self.iter() {
+ do ss.as_slice().as_imm_buf |ssbuf, sslen| {
+ if first {
+ first = false;
+ } else {
+ ptr::copy_memory(buf, sepbuf, seplen);
+ buf = buf.offset(seplen as int);
+ }
+ ptr::copy_memory(buf, ssbuf, sslen);
+ buf = buf.offset(sslen as int);
+ }
+ }
+ }
+ }
+ raw::set_len(&mut s, len);
+ }
+ s
+ }
}
/// Something that can be used to compare against a character