about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorErick Tryzelaar <erick.tryzelaar@gmail.com>2013-08-09 18:48:01 -0700
committerErick Tryzelaar <erick.tryzelaar@gmail.com>2013-08-09 18:48:01 -0700
commitee59aacac490edd619db1c4e2fcd848f793bc3b9 (patch)
treed4f01cefe67f55b80cfaca641a03b581823eb200 /src/libstd/rt
parentcab6d46e58ea6f7535d8e454f0345eccfae183c4 (diff)
parent6f6dce7bbcfb104a8a1e23b0b93d83cbb770f338 (diff)
downloadrust-ee59aacac490edd619db1c4e2fcd848f793bc3b9.tar.gz
rust-ee59aacac490edd619db1c4e2fcd848f793bc3b9.zip
Merge remote-tracking branch 'remotes/origin/master' into remove-str-trailing-nulls
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/comm.rs4
-rw-r--r--src/libstd/rt/io/net/ip.rs374
-rw-r--r--src/libstd/rt/local_heap.rs22
-rw-r--r--src/libstd/rt/mod.rs51
-rw-r--r--src/libstd/rt/uv/net.rs72
5 files changed, 424 insertions, 99 deletions
diff --git a/src/libstd/rt/comm.rs b/src/libstd/rt/comm.rs
index 936a6526508..793e244bec7 100644
--- a/src/libstd/rt/comm.rs
+++ b/src/libstd/rt/comm.rs
@@ -15,6 +15,7 @@ use cast;
 use ops::Drop;
 use rt::kill::BlockedTask;
 use kinds::Send;
+use rt;
 use rt::sched::Scheduler;
 use rt::local::Local;
 use rt::select::{Select, SelectPort};
@@ -24,7 +25,6 @@ use util::Void;
 use comm::{GenericChan, GenericSmartChan, GenericPort, Peekable};
 use cell::Cell;
 use clone::Clone;
-use rt::{context, SchedulerContext};
 use tuple::ImmutableTuple;
 
 /// A combined refcount / BlockedTask-as-uint pointer.
@@ -113,7 +113,7 @@ impl<T> ChanOne<T> {
     // 'do_resched' configures whether the scheduler immediately switches to
     // the receiving task, or leaves the sending task still running.
     fn try_send_inner(self, val: T, do_resched: bool) -> bool {
-        rtassert!(context() != SchedulerContext);
+        rtassert!(!rt::in_sched_context());
 
         let mut this = self;
         let mut recvr_active = true;
diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs
index 815ec9b5c61..77176088801 100644
--- a/src/libstd/rt/io/net/ip.rs
+++ b/src/libstd/rt/io/net/ip.rs
@@ -9,7 +9,11 @@
 // except according to those terms.
 
 use num::FromStrRadix;
+use vec::MutableCloneableVector;
 use to_str::ToStr;
+use from_str::FromStr;
+use option::{Option, None, Some};
+
 
 type Port = u16;
 
@@ -39,7 +43,7 @@ impl ToStr for IpAddr {
             }
 
             // Ipv4-Mapped address
-            Ipv6Addr(0, 0, 0, 0, 0, 1, g, h) => {
+            Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, g, h) => {
                 let a = fmt!("%04x", g as uint);
                 let b = FromStrRadix::from_str_radix(a.slice(2, 4), 16).unwrap();
                 let a = FromStrRadix::from_str_radix(a.slice(0, 2), 16).unwrap();
@@ -73,3 +77,371 @@ impl ToStr for SocketAddr {
         }
     }
 }
+
+struct Parser<'self> {
+    // parsing as ASCII, so can use byte array
+    s: &'self [u8],
+    pos: uint,
+}
+
+impl<'self> Parser<'self> {
+    fn new(s: &'self str) -> Parser<'self> {
+        Parser {
+            s: s.as_bytes(),
+            pos: 0,
+        }
+    }
+
+    fn is_eof(&self) -> bool {
+        self.pos == self.s.len()
+    }
+
+    // Commit only if parser returns Some
+    fn read_atomically<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> {
+        let pos = self.pos;
+        let r = cb(self);
+        if r.is_none() {
+            self.pos = pos;
+        }
+        r
+    }
+
+    // Commit only if parser read till EOF
+    fn read_till_eof<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> {
+        do self.read_atomically |p| {
+            cb(p).filtered(|_| p.is_eof())
+        }
+    }
+
+    // Return result of first successful parser
+    fn read_or<T>(&mut self, parsers: &[&fn(&mut Parser) -> Option<T>]) -> Option<T> {
+        for pf in parsers.iter() {
+            match self.read_atomically(|p: &mut Parser| (*pf)(p)) {
+                Some(r) => return Some(r),
+                None => {}
+            }
+        }
+        None
+    }
+
+    // Apply 3 parsers sequentially
+    fn read_seq_3<A, B, C>(&mut self,
+            pa: &fn(&mut Parser) -> Option<A>,
+            pb: &fn(&mut Parser) -> Option<B>,
+            pc: &fn(&mut Parser) -> Option<C>
+        ) -> Option<(A, B, C)>
+    {
+        do self.read_atomically |p| {
+            let a = pa(p);
+            let b = if a.is_some() { pb(p) } else { None };
+            let c = if b.is_some() { pc(p) } else { None };
+            match (a, b, c) {
+                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
+                _ => None
+            }
+        }
+    }
+
+    // Read next char
+    fn read_char(&mut self) -> Option<char> {
+        if self.is_eof() {
+            None
+        } else {
+            let r = self.s[self.pos] as char;
+            self.pos += 1;
+            Some(r)
+        }
+    }
+
+    // Return char and advance iff next char is equal to requested
+    fn read_given_char(&mut self, c: char) -> Option<char> {
+        do self.read_atomically |p| {
+            p.read_char().filtered(|&next| next == c)
+        }
+    }
+
+    // Read digit
+    fn read_digit(&mut self, radix: u8) -> Option<u8> {
+        fn parse_digit(c: char, radix: u8) -> Option<u8> {
+            // assuming radix is either 10 or 16
+            if c >= '0' && c <= '9' {
+                Some((c - '0') as u8)
+            } else if radix > 10 && c >= 'a' && c < 'a' + (radix - 10) as char {
+                Some((c - 'a' + (10 as char)) as u8)
+            } else if radix > 10 && c >= 'A' && c < 'A' + (radix - 10) as char {
+                Some((c - 'A' + (10 as char)) as u8)
+            } else {
+                None
+            }
+        }
+
+        do self.read_atomically |p| {
+            p.read_char().chain(|c| parse_digit(c, radix))
+        }
+    }
+
+    fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+        let mut r = 0u32;
+        let mut digit_count = 0;
+        loop {
+            match self.read_digit(radix) {
+                Some(d) => {
+                    r = r * (radix as u32) + (d as u32);
+                    digit_count += 1;
+                    if digit_count > max_digits || r >= upto {
+                        return None
+                    }
+                }
+                None => {
+                    if digit_count == 0 {
+                        return None
+                    } else {
+                        return Some(r)
+                    }
+                }
+            };
+        }
+    }
+
+    // Read number, failing if max_digits of number value exceeded
+    fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+        do self.read_atomically |p| {
+            p.read_number_impl(radix, max_digits, upto)
+        }
+    }
+
+    fn read_ipv4_addr_impl(&mut self) -> Option<IpAddr> {
+        let mut bs = [0u8, ..4];
+        let mut i = 0;
+        while i < 4 {
+            if i != 0 && self.read_given_char('.').is_none() {
+                return None;
+            }
+
+            let octet = self.read_number(10, 3, 0x100).map(|&n| n as u8);
+            match octet {
+                Some(d) => bs[i] = d,
+                None => return None,
+            };
+            i += 1;
+        }
+        Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3]))
+    }
+
+    // Read IPv4 address
+    fn read_ipv4_addr(&mut self) -> Option<IpAddr> {
+        do self.read_atomically |p| {
+            p.read_ipv4_addr_impl()
+        }
+    }
+
+    fn read_ipv6_addr_impl(&mut self) -> Option<IpAddr> {
+        fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr {
+            assert!(head.len() + tail.len() <= 8);
+            let mut gs = [0u16, ..8];
+            gs.copy_from(head);
+            gs.mut_slice(8 - tail.len(), 8).copy_from(tail);
+            Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
+        }
+
+        fn read_groups(p: &mut Parser, groups: &mut [u16, ..8], limit: uint) -> (uint, bool) {
+            let mut i = 0;
+            while i < limit {
+                if i < limit - 1 {
+                    let ipv4 = do p.read_atomically |p| {
+                        if i == 0 || p.read_given_char(':').is_some() {
+                            p.read_ipv4_addr()
+                        } else {
+                            None
+                        }
+                    };
+                    match ipv4 {
+                        Some(Ipv4Addr(a, b, c, d)) => {
+                            groups[i + 0] = (a as u16 << 8) | (b as u16);
+                            groups[i + 1] = (c as u16 << 8) | (d as u16);
+                            return (i + 2, true);
+                        }
+                        _ => {}
+                    }
+                }
+
+                let group = do p.read_atomically |p| {
+                    if i == 0 || p.read_given_char(':').is_some() {
+                        p.read_number(16, 4, 0x10000).map(|&n| n as u16)
+                    } else {
+                        None
+                    }
+                };
+                match group {
+                    Some(g) => groups[i] = g,
+                    None => return (i, false)
+                }
+                i += 1;
+            }
+            (i, false)
+        }
+
+        let mut head = [0u16, ..8];
+        let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
+
+        if head_size == 8 {
+            return Some(Ipv6Addr(
+                head[0], head[1], head[2], head[3],
+                head[4], head[5], head[6], head[7]))
+        }
+
+        // IPv4 part is not allowed before `::`
+        if head_ipv4 {
+            return None
+        }
+
+        // read `::` if previous code parsed less than 8 groups
+        if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
+            return None;
+        }
+
+        let mut tail = [0u16, ..8];
+        let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
+        Some(ipv6_addr_from_head_tail(head.slice(0, head_size), tail.slice(0, tail_size)))
+    }
+
+    fn read_ipv6_addr(&mut self) -> Option<IpAddr> {
+        do self.read_atomically |p| {
+            p.read_ipv6_addr_impl()
+        }
+    }
+
+    fn read_ip_addr(&mut self) -> Option<IpAddr> {
+        let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr();
+        let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr();
+        self.read_or([ipv4_addr, ipv6_addr])
+    }
+
+    fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+        let ip_addr = |p: &mut Parser| {
+            let ipv4_p = |p: &mut Parser| p.read_ip_addr();
+            let ipv6_p = |p: &mut Parser| {
+                let open_br = |p: &mut Parser| p.read_given_char('[');
+                let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
+                let clos_br = |p: &mut Parser| p.read_given_char(']');
+                p.read_seq_3::<char, IpAddr, char>(open_br, ip_addr, clos_br)
+                        .map(|&t| match t { (_, ip, _) => ip })
+            };
+            p.read_or([ipv4_p, ipv6_p])
+        };
+        let colon = |p: &mut Parser| p.read_given_char(':');
+        let port  = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|&n| n as u16);
+
+        // host, colon, port
+        self.read_seq_3::<IpAddr, char, u16>(ip_addr, colon, port)
+                .map(|&t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } })
+    }
+}
+
+impl FromStr for IpAddr {
+    fn from_str(s: &str) -> Option<IpAddr> {
+        do Parser::new(s).read_till_eof |p| {
+            p.read_ip_addr()
+        }
+    }
+}
+
+impl FromStr for SocketAddr {
+    fn from_str(s: &str) -> Option<SocketAddr> {
+        do Parser::new(s).read_till_eof |p| {
+            p.read_socket_addr()
+        }
+    }
+}
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use from_str::FromStr;
+    use option::{Some, None};
+
+    #[test]
+    fn test_from_str_ipv4() {
+        assert_eq!(Some(Ipv4Addr(127, 0, 0, 1)), FromStr::from_str("127.0.0.1"));
+        assert_eq!(Some(Ipv4Addr(255, 255, 255, 255)), FromStr::from_str("255.255.255.255"));
+        assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0"));
+
+        // out of range
+        assert_eq!(None, FromStr::from_str::<IpAddr>("256.0.0.1"));
+        // too short
+        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0"));
+        // too long
+        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2"));
+        // no number between dots
+        assert_eq!(None, FromStr::from_str::<IpAddr>("255.0..1"));
+    }
+
+    #[test]
+    fn test_from_str_ipv6() {
+        assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("0:0:0:0:0:0:0:0"));
+        assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("0:0:0:0:0:0:0:1"));
+
+        assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("::1"));
+        assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("::"));
+
+        assert_eq!(Some(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
+                FromStr::from_str("2a02:6b8::11:11"));
+
+        // too long group
+        assert_eq!(None, FromStr::from_str::<IpAddr>("::00000"));
+        // too short
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7"));
+        // too long
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9"));
+        // triple colon
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8"));
+        // two double colons
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1:2::6::8"));
+    }
+
+    #[test]
+    fn test_from_str_ipv4_in_ipv6() {
+        assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)),
+                FromStr::from_str("::192.0.2.33"));
+        assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
+                FromStr::from_str("::FFFF:192.0.2.33"));
+        assert_eq!(Some(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+                FromStr::from_str("64:ff9b::192.0.2.33"));
+        assert_eq!(Some(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+                FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33"));
+
+        // colon after v4
+        assert_eq!(None, FromStr::from_str::<IpAddr>("::127.0.0.1:"));
+        // not enought groups
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1"));
+        // too many groups
+        assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:6:7:127.0.0.1"));
+    }
+
+    #[test]
+    fn test_from_str_socket_addr() {
+        assert_eq!(Some(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }),
+                FromStr::from_str("77.88.21.11:80"));
+        assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }),
+                FromStr::from_str("[2a02:6b8:0:1::1]:53"));
+        assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }),
+                FromStr::from_str("[::127.0.0.1]:22"));
+
+        // without port
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1"));
+        // without port
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:"));
+        // wrong brackets around v4
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22"));
+        // port out of range
+        assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456"));
+    }
+
+    #[test]
+    fn ipv6_addr_to_str() {
+        let a1 = Ipv6Addr(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+        assert!(a1.to_str() == ~"::ffff:192.0.2.128" || a1.to_str() == ~"::FFFF:192.0.2.128");
+    }
+
+}
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
index e1e7ceacc38..8832597f40c 100644
--- a/src/libstd/rt/local_heap.rs
+++ b/src/libstd/rt/local_heap.rs
@@ -13,6 +13,7 @@
 use libc;
 use libc::{c_void, uintptr_t, size_t};
 use ops::Drop;
+use option::{Some, None};
 use rt;
 use rt::OldTaskContext;
 use rt::local::Local;
@@ -86,8 +87,12 @@ impl Drop for LocalHeap {
 
 // A little compatibility function
 pub unsafe fn local_free(ptr: *libc::c_char) {
-    match rt::context() {
-        OldTaskContext => {
+    // XXX: Unsafe borrow for speed. Lame.
+    match Local::try_unsafe_borrow::<Task>() {
+        Some(task) => {
+            (*task).heap.free(ptr as *libc::c_void);
+        }
+        None => {
             rust_upcall_free_noswitch(ptr);
 
             extern {
@@ -95,11 +100,6 @@ pub unsafe fn local_free(ptr: *libc::c_char) {
                 fn rust_upcall_free_noswitch(ptr: *libc::c_char);
             }
         }
-        _ => {
-            do Local::borrow::<Task,()> |task| {
-                task.heap.free(ptr as *libc::c_void);
-            }
-        }
     }
 }
 
@@ -119,20 +119,28 @@ pub fn live_allocs() -> *raw::Box<()> {
 }
 
 extern {
+    #[fast_ffi]
     fn rust_new_memory_region(synchronized: uintptr_t,
                                detailed_leaks: uintptr_t,
                                poison_on_free: uintptr_t) -> *MemoryRegion;
+    #[fast_ffi]
     fn rust_delete_memory_region(region: *MemoryRegion);
+    #[fast_ffi]
     fn rust_new_boxed_region(region: *MemoryRegion,
                              poison_on_free: uintptr_t) -> *BoxedRegion;
+    #[fast_ffi]
     fn rust_delete_boxed_region(region: *BoxedRegion);
+    #[fast_ffi]
     fn rust_boxed_region_malloc(region: *BoxedRegion,
                                 td: *TypeDesc,
                                 size: size_t) -> *OpaqueBox;
+    #[fast_ffi]
     fn rust_boxed_region_realloc(region: *BoxedRegion,
                                  ptr: *OpaqueBox,
                                  size: size_t) -> *OpaqueBox;
+    #[fast_ffi]
     fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox);
+    #[fast_ffi]
     fn rust_current_boxed_region() -> *BoxedRegion;
 }
 
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 01a52892f63..be71bc651df 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -407,14 +407,10 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
 /// or the old scheduler.
 #[deriving(Eq)]
 pub enum RuntimeContext {
-    // Only the exchange heap is available
-    GlobalContext,
-    // The scheduler may be accessed
-    SchedulerContext,
-    // Full task services, e.g. local heap, unwinding
-    TaskContext,
     // Running in an old-style task
-    OldTaskContext
+    OldTaskContext,
+    // Not old task context
+    NewRtContext
 }
 
 /// Determine the current RuntimeContext
@@ -424,19 +420,8 @@ pub fn context() -> RuntimeContext {
 
     if unsafe { rust_try_get_task().is_not_null() } {
         return OldTaskContext;
-    } else if Local::exists::<Task>() {
-        // In this case we know it is a new runtime context, but we
-        // need to check which one. Going to try borrowing task to
-        // check. Task should always be in TLS, so hopefully this
-        // doesn't conflict with other ops that borrow.
-        return do Local::borrow::<Task,RuntimeContext> |task| {
-            match task.task_type {
-                SchedTask => SchedulerContext,
-                GreenTask(_) => TaskContext
-            }
-        };
     } else {
-        return GlobalContext;
+        return NewRtContext;
     }
 
     extern {
@@ -444,3 +429,31 @@ pub fn context() -> RuntimeContext {
         pub fn rust_try_get_task() -> *rust_task;
     }
 }
+
+pub fn in_sched_context() -> bool {
+    unsafe {
+        match Local::try_unsafe_borrow::<Task>() {
+            Some(task) => {
+                match (*task).task_type {
+                    SchedTask => true,
+                    _ => false
+                }
+            }
+            None => false
+        }
+    }
+}
+
+pub fn in_green_task_context() -> bool {
+    unsafe {
+        match Local::try_unsafe_borrow::<Task>() {
+            Some(task) => {
+                match (*task).task_type {
+                    GreenTask(_) => true,
+                    _ => false
+                }
+            }
+            None => false
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs
index fd3042899f6..c8b3d41a78d 100644
--- a/src/libstd/rt/uv/net.rs
+++ b/src/libstd/rt/uv/net.rs
@@ -20,7 +20,6 @@ use rt::uv::last_uv_error;
 use vec;
 use str;
 use from_str::{FromStr};
-use num;
 
 pub enum UvSocketAddr {
     UvIpv4SocketAddr(*sockaddr_in),
@@ -85,77 +84,10 @@ fn uv_socket_addr_as_socket_addr<T>(addr: UvSocketAddr, f: &fn(SocketAddr) -> T)
         port as u16
     };
     let ip_str = str::from_bytes_slice(ip_name).trim_right_chars(&'\x00');
-    let ip = match addr {
-        UvIpv4SocketAddr(*) => {
-            let ip: ~[u8] =
-                ip_str.split_iter('.')
-                      .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() })
-                      .collect();
-            assert_eq!(ip.len(), 4);
-            SocketAddr {
-                ip: Ipv4Addr(ip[0], ip[1], ip[2], ip[3]),
-                port: ip_port
-            }
-        },
-        UvIpv6SocketAddr(*) => {
-            let ip: ~[u16] = {
-                let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] {
-                    let convert_each_segment = |s: &str| -> ~[u16] {
-                        let read_hex_segment = |s: &str| -> u16 {
-                            num::FromStrRadix::from_str_radix(s, 16u).unwrap()
-                        };
-                        match s {
-                            "" => ~[],
-                            // IPv4-Mapped/Compatible IPv6 Address?
-                            s if s.find('.').is_some() => {
-                                let i = s.rfind(':').unwrap_or_default(-1);
-
-                                let b = s.slice(i + 1, s.len()); // the ipv4 part
-
-                                let h = b.split_iter('.')
-                                   .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() })
-                                   .transform(|s: u8| -> ~str { fmt!("%02x", s as uint) })
-                                   .collect::<~[~str]>();
-
-                                if i == -1 {
-                                    // Ipv4 Compatible Address (::x.x.x.x)
-                                    // first 96 bits are zero leaving 32 bits
-                                    // for the ipv4 part
-                                    // (i.e ::127.0.0.1 == ::7F00:1)
-                                    ~[num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(),
-                                      num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()]
-                                } else {
-                                    // Ipv4-Mapped Address (::FFFF:x.x.x.x)
-                                    // first 80 bits are zero, followed by all ones
-                                    // for the next 16 bits, leaving 32 bits for
-                                    // the ipv4 part
-                                    // (i.e ::FFFF:127.0.0.1 == ::FFFF:7F00:1)
-                                    ~[1,
-                                      num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(),
-                                      num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()]
-                                }
-                            },
-                            s => s.split_iter(':').transform(read_hex_segment).collect()
-                        }
-                    };
-                    s.split_str_iter("::").transform(convert_each_segment).collect()
-                };
-                match expand_shorthand_and_convert(ip_str) {
-                    [x] => x, // no shorthand found
-                    [l, r] => l + vec::from_elem(8 - l.len() - r.len(), 0u16) + r, // fill the gap
-                    _ => fail!(), // impossible. only one shorthand allowed.
-                }
-            };
-            assert_eq!(ip.len(), 8);
-            SocketAddr {
-                ip: Ipv6Addr(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
-                port: ip_port
-            }
-        },
-    };
+    let ip_addr = FromStr::from_str(ip_str).unwrap();
 
     // finally run the closure
-    f(ip)
+    f(SocketAddr { ip: ip_addr, port: ip_port })
 }
 
 pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {