# code, make sure that these common warnings are denied by default. These can
# be overridden during development temporarily. For stage0, we allow all these
# to suppress warnings which may be bugs in stage0 (should be fixed in stage1+)
-# NOTE: add "-A warnings" after snapshot to WFLAGS_ST0
-WFLAGS_ST0 = -A unrecognized-lint
+WFLAGS_ST0 = -A warnings
WFLAGS_ST1 = -D warnings
WFLAGS_ST2 = -D warnings
let mut tests = ~[];
let dirs = os::list_dir_path(&config.src_base);
for dirs.iter().advance |file| {
- let file = (*file).clone();
+ let file = file.clone();
debug!("inspecting file %s", file.to_str());
- if is_test(config, file) {
- let t = do make_test(config, file) {
+ if is_test(config, &file) {
+ let t = do make_test(config, &file) {
match config.mode {
- mode_codegen => make_metrics_test_closure(config, file),
- _ => make_test_closure(config, file)
+ mode_codegen => make_metrics_test_closure(config, &file),
+ _ => make_test_closure(config, &file)
}
};
tests.push(t)
*
* Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested.
*/
-#[mutable] // XXX remove after snap
#[no_freeze]
struct RWARC<T> {
priv x: UnsafeAtomicRcBox<RWARCInner<T>>,
use std::uint;
use std::vec;
use std::unstable::intrinsics;
-use std::unstable::intrinsics::{TyDesc};
-
-#[cfg(not(stage0))]
-use std::unstable::intrinsics::{get_tydesc};
-
-#[cfg(stage0)]
-unsafe fn get_tydesc<T>() -> *TyDesc {
- intrinsics::get_tydesc::<T>() as *TyDesc
-}
+use std::unstable::intrinsics::{TyDesc, get_tydesc};
// The way arena uses arrays is really deeply awful. The arrays are
// allocated, and have capacities reserved, but the fill for the array
is_pod: bool,
}
-#[mutable] // XXX remove after snap
#[no_freeze]
pub struct Arena {
// The head is separated out from the list as a unbenchmarked
(base + (align - 1)) & !(align - 1)
}
-#[inline]
-#[cfg(not(stage0))]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- // This function should be inlined when stage0 is gone
- ((*tydesc).drop_glue)(data);
-}
-
-#[inline]
-#[cfg(stage0)]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- ((*tydesc).drop_glue)(0 as **TyDesc, data);
-}
-
// Walk down a chunk, running the destructors for any objects stored
// in it.
unsafe fn destroy_chunk(chunk: &Chunk) {
//debug!("freeing object: idx = %u, size = %u, align = %u, done = %b",
// start, size, align, is_done);
if is_done {
- call_drop_glue(tydesc, ptr::offset(buf, start) as *i8);
+ ((*tydesc).drop_glue)(ptr::offset(buf, start) as *i8);
}
// Find where the next tydesc lives
use std::uint;
use std::vec;
+#[deriving(Clone)]
struct SmallBitv {
/// only the lowest nbits of this value are used. the rest is undefined.
bits: uint
pub fn negate(&mut self) { self.bits = !self.bits; }
}
+#[deriving(Clone)]
struct BigBitv {
storage: ~[uint]
}
}
}
-enum BitvVariant { Big(~BigBitv), Small(~SmallBitv) }
+#[deriving(Clone)]
+enum BitvVariant { Big(BigBitv), Small(SmallBitv) }
enum Op {Union, Intersect, Assign, Difference}
/// The bitvector type
+#[deriving(Clone)]
pub struct Bitv {
/// Internal representation of the bit vector (small or large)
rep: BitvVariant,
match self.rep {
Small(ref mut s) => match other.rep {
Small(ref s1) => match op {
- Union => s.union(*s1, self.nbits),
- Intersect => s.intersect(*s1, self.nbits),
- Assign => s.become(*s1, self.nbits),
- Difference => s.difference(*s1, self.nbits)
+ Union => s.union(s1, self.nbits),
+ Intersect => s.intersect(s1, self.nbits),
+ Assign => s.become(s1, self.nbits),
+ Difference => s.difference(s1, self.nbits)
},
Big(_) => die()
},
Big(ref mut s) => match other.rep {
Small(_) => die(),
Big(ref s1) => match op {
- Union => s.union(*s1, self.nbits),
- Intersect => s.intersect(*s1, self.nbits),
- Assign => s.become(*s1, self.nbits),
- Difference => s.difference(*s1, self.nbits)
+ Union => s.union(s1, self.nbits),
+ Intersect => s.intersect(s1, self.nbits),
+ Assign => s.become(s1, self.nbits),
+ Difference => s.difference(s1, self.nbits)
}
}
}
impl Bitv {
pub fn new(nbits: uint, init: bool) -> Bitv {
let rep = if nbits <= uint::bits {
- Small(~SmallBitv::new(if init {!0} else {0}))
+ Small(SmallBitv::new(if init {!0} else {0}))
}
else {
let nelems = nbits/uint::bits +
if nbits % uint::bits == 0 {0} else {1};
let elem = if init {!0u} else {0u};
let s = vec::from_elem(nelems, elem);
- Big(~BigBitv::new(s))
+ Big(BigBitv::new(s))
};
Bitv {rep: rep, nbits: nbits}
}
if self.nbits != v1.nbits { return false; }
match self.rep {
Small(ref b) => match v1.rep {
- Small(ref b1) => b.equals(*b1, self.nbits),
+ Small(ref b1) => b.equals(b1, self.nbits),
_ => false
},
Big(ref s) => match v1.rep {
- Big(ref s1) => s.equals(*s1, self.nbits),
+ Big(ref s1) => s.equals(s1, self.nbits),
Small(_) => return false
}
}
match self.rep {
Small(ref b) => b.is_true(self.nbits),
_ => {
- for self.each() |i| { if !i { return false; } }
+ for self.iter().advance |i| { if !i { return false; } }
true
}
}
}
#[inline]
- pub fn each(&self, f: &fn(bool) -> bool) -> bool {
- let mut i = 0;
- while i < self.nbits {
- if !f(self.get(i)) { return false; }
- i += 1;
- }
- return true;
+ pub fn iter<'a>(&'a self) -> BitvIterator<'a> {
+ BitvIterator {bitv: self, next_idx: 0}
}
/// Returns true if all bits are 0
match self.rep {
Small(ref b) => b.is_false(self.nbits),
Big(_) => {
- for self.each() |i| { if i { return false; } }
+ for self.iter().advance |i| { if i { return false; } }
true
}
}
*/
pub fn to_str(&self) -> ~str {
let mut rs = ~"";
- for self.each() |i| {
+ for self.iter().advance |i| {
if i {
rs.push_char('1');
} else {
}
-impl Clone for Bitv {
- /// Makes a copy of a bitvector
- #[inline]
- fn clone(&self) -> Bitv {
- match self.rep {
- Small(ref b) => {
- Bitv{nbits: self.nbits, rep: Small(~SmallBitv{bits: b.bits})}
- }
- Big(ref b) => {
- let mut st = vec::from_elem(self.nbits / uint::bits + 1, 0u);
- let len = st.len();
- for uint::range(0, len) |i| { st[i] = b.storage[i]; };
- Bitv{nbits: self.nbits, rep: Big(~BigBitv{storage: st})}
- }
- }
- }
-}
-
/**
* Transform a byte-vector into a bitv. Each byte becomes 8 bits,
* with the most significant bits of each byte coming first. Each
return true;
}
+/// An iterator for Bitv
+pub struct BitvIterator<'self> {
+ priv bitv: &'self Bitv,
+ priv next_idx: uint
+}
+
+impl<'self> Iterator<bool> for BitvIterator<'self> {
+ #[inline]
+ fn next(&mut self) -> Option<bool> {
+ if self.next_idx < self.bitv.nbits {
+ let idx = self.next_idx;
+ self.next_idx += 1;
+ Some(self.bitv.get(idx))
+ } else {
+ None
+ }
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ let rem = self.bitv.nbits - self.next_idx;
+ (rem, Some(rem))
+ }
+}
+
/// An implementation of a set using a bit vector as an underlying
/// representation for holding numerical elements.
///
/// It should also be noted that the amount of storage necessary for holding a
/// set of objects is proportional to the maximum of the objects when viewed
/// as a uint.
+#[deriving(Clone)]
pub struct BitvSet {
priv size: uint,
}
let Bitv{rep, _} = bitv;
match rep {
- Big(~b) => BitvSet{ size: size, bitv: b },
- Small(~SmallBitv{bits}) =>
+ Big(b) => BitvSet{ size: size, bitv: b },
+ Small(SmallBitv{bits}) =>
BitvSet{ size: size, bitv: BigBitv{ storage: ~[bits] } },
}
}
pub fn unwrap(self) -> Bitv {
let cap = self.capacity();
let BitvSet{bitv, _} = self;
- return Bitv{ nbits:cap, rep: Big(~bitv) };
+ return Bitv{ nbits:cap, rep: Big(bitv) };
}
#[inline]
self.other_op(other, |w1, w2| w1 ^ w2);
}
- pub fn each(&self, blk: &fn(v: &uint) -> bool) -> bool {
- for self.bitv.storage.iter().enumerate().advance |(i, &w)| {
- if !iterate_bits(i * uint::bits, w, |b| blk(&b)) {
- return false;
- }
- }
- return true;
+ pub fn iter<'a>(&'a self) -> BitvSetIterator<'a> {
+ BitvSetIterator {set: self, next_idx: 0}
}
}
}
}
+pub struct BitvSetIterator<'self> {
+ priv set: &'self BitvSet,
+ priv next_idx: uint
+}
+
+impl<'self> Iterator<uint> for BitvSetIterator<'self> {
+ #[inline]
+ fn next(&mut self) -> Option<uint> {
+ while self.next_idx < self.set.capacity() {
+ let idx = self.next_idx;
+ self.next_idx += 1;
+
+ if self.set.contains(&idx) {
+ return Some(idx);
+ }
+ }
+
+ return None;
+ }
+
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ (0, Some(self.set.capacity() - self.next_idx))
+ }
+}
+
#[cfg(test)]
mod tests {
use extra::test::BenchHarness;
assert_eq!(from_bytes([0b00100110]).to_bools(), bools);
}
+ #[test]
+ fn test_bitv_iterator() {
+ let bools = [true, false, true, true];
+ let bitv = from_bools(bools);
+
+ for bitv.iter().zip(bools.iter()).advance |(act, &ex)| {
+ assert_eq!(ex, act);
+ }
+ }
+
+ #[test]
+ fn test_bitv_set_iterator() {
+ let bools = [true, false, true, true];
+ let bitv = BitvSet::from_bitv(from_bools(bools));
+
+ let idxs: ~[uint] = bitv.iter().collect();
+ assert_eq!(idxs, ~[0, 2, 3]);
+ }
+
#[test]
fn test_small_difference() {
let mut b1 = Bitv::new(3, false);
assert_eq!(a.capacity(), uint::bits);
}
+ #[test]
+ fn test_bitv_clone() {
+ let mut a = BitvSet::new();
+
+ assert!(a.insert(1));
+ assert!(a.insert(100));
+ assert!(a.insert(1000));
+
+ let mut b = a.clone();
+
+ assert_eq!(&a, &b);
+
+ assert!(b.remove(&1));
+ assert!(a.contains(&1));
+
+ assert!(a.remove(&1000));
+ assert!(b.contains(&1000));
+ }
+
fn rng() -> rand::IsaacRng {
let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
rand::IsaacRng::new_seeded(seed)
b1.union(&b2);
}
}
+
+ #[bench]
+ fn bench_btv_small_iter(b: &mut BenchHarness) {
+ let bitv = Bitv::new(uint::bits, false);
+ do b.iter {
+ let mut sum = 0;
+ for bitv.iter().advance |pres| {
+ sum += pres as uint;
+ }
+ }
+ }
+
+ #[bench]
+ fn bench_bitv_big_iter(b: &mut BenchHarness) {
+ let bitv = Bitv::new(BENCH_BITS, false);
+ do b.iter {
+ let mut sum = 0;
+ for bitv.iter().advance |pres| {
+ sum += pres as uint;
+ }
+ }
+ }
+
+ #[bench]
+ fn bench_bitvset_iter(b: &mut BenchHarness) {
+ let bitv = BitvSet::from_bitv(from_fn(BENCH_BITS,
+ |idx| {idx % 3 == 0}));
+ do b.iter {
+ let mut sum = 0;
+ for bitv.iter().advance |idx| {
+ sum += idx;
+ }
+ }
+ }
}
#[allow(missing_doc)];
use std::cast::transmute;
-#[cfg(stage0)]
-use intrinsic::{get_tydesc};
-#[cfg(not(stage0))]
use std::unstable::intrinsics::{get_tydesc};
pub mod rustrt {
- #[cfg(stage0)]
- use intrinsic::{TyDesc};
- #[cfg(not(stage0))]
use std::unstable::intrinsics::{TyDesc};
#[abi = "cdecl"]
pub use std::os;
-pub mod uv_ll;
-
-// General io and system-services modules
-
-#[path = "net/mod.rs"]
-pub mod net;
-
-// libuv modules
-pub mod uv;
-pub mod uv_iotask;
-pub mod uv_global_loop;
-
-
// Utility modules
pub mod c_vec;
-pub mod timer;
pub mod io_util;
pub mod rc;
// And ... other stuff
+pub mod url;
pub mod ebml;
pub mod dbg;
pub mod getopts;
use flatpipes::serial;
use io_util::BufReader;
use flatpipes::{BytePort, FlatChan, FlatPort};
- use net::tcp::TcpSocketBuf;
use std::comm;
use std::int;
}
// FIXME #2064: Networking doesn't work on x86
- #[test]
+ // XXX Broken until networking support is added back
+ /*#[test]
#[cfg(target_arch = "x86_64")]
fn test_pod_tcp_stream() {
fn reader_port(buf: TcpSocketBuf
#[test]
#[cfg(target_arch = "x86_64")]
fn test_serializing_tcp_stream() {
+ // XXX Broken until networking support is added back
fn reader_port(buf: TcpSocketBuf
) -> serial::ReaderPort<int, TcpSocketBuf> {
serial::reader_port(buf)
}
finish_port.recv();
- }
+ }*/
// Tests that the different backends behave the same when the
// binary streaming protocol is broken
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Types/fns concerning Internet Protocol (IP), versions 4 & 6
-
-#[allow(missing_doc)];
-
-
-use std::libc;
-use std::comm::{stream, SharedChan};
-use std::ptr;
-use std::result;
-use std::str;
-
-use iotask = uv::iotask::IoTask;
-use interact = uv::iotask::interact;
-
-use sockaddr_in = uv_ll::sockaddr_in;
-use sockaddr_in6 = uv_ll::sockaddr_in6;
-use addrinfo = uv_ll::addrinfo;
-use uv_getaddrinfo_t = uv_ll::uv_getaddrinfo_t;
-use uv_ip4_name = uv_ll::ip4_name;
-use uv_ip4_port = uv_ll::ip4_port;
-use uv_ip6_name = uv_ll::ip6_name;
-use uv_ip6_port = uv_ll::ip6_port;
-use uv_getaddrinfo = uv_ll::getaddrinfo;
-use uv_freeaddrinfo = uv_ll::freeaddrinfo;
-use create_uv_getaddrinfo_t = uv_ll::getaddrinfo_t;
-use set_data_for_req = uv_ll::set_data_for_req;
-use get_data_for_req = uv_ll::get_data_for_req;
-use ll = uv_ll;
-
-/// An IP address
-#[deriving(Clone)]
-pub enum IpAddr {
- /// An IPv4 address
- Ipv4(sockaddr_in),
- Ipv6(sockaddr_in6)
-}
-
-/// Human-friendly feedback on why a parse_addr attempt failed
-pub struct ParseAddrErr {
- err_msg: ~str,
-}
-
-/**
- * Convert a `IpAddr` to a str
- *
- * # Arguments
- *
- * * ip - a `extra::net::ip::IpAddr`
- */
-pub fn format_addr(ip: &IpAddr) -> ~str {
- match *ip {
- Ipv4(ref addr) => unsafe {
- let result = uv_ip4_name(addr);
- if result == ~"" {
- fail!("failed to convert inner sockaddr_in address to str")
- }
- result
- },
- Ipv6(ref addr) => unsafe {
- let result = uv_ip6_name(addr);
- if result == ~"" {
- fail!("failed to convert inner sockaddr_in address to str")
- }
- result
- }
- }
-}
-
-/**
- * Get the associated port
- *
- * # Arguments
- * * ip - a `extra::net::ip::IpAddr`
- */
-pub fn get_port(ip: &IpAddr) -> uint {
- match *ip {
- Ipv4(ref addr) => unsafe {
- uv_ip4_port(addr)
- },
- Ipv6(ref addr) => unsafe {
- uv_ip6_port(addr)
- }
- }
-}
-
-/// Represents errors returned from `net::ip::get_addr()`
-enum IpGetAddrErr {
- GetAddrUnknownError
-}
-
-/**
- * Attempts name resolution on the provided `node` string
- *
- * # Arguments
- *
- * * `node` - a string representing some host address
- * * `iotask` - a `uv::iotask` used to interact with the underlying event loop
- *
- * # Returns
- *
- * A `result<~[ip_addr], ip_get_addr_err>` instance that will contain
- * a vector of `ip_addr` results, in the case of success, or an error
- * object in the case of failure
-*/
-pub fn get_addr(node: &str, iotask: &iotask)
- -> result::Result<~[IpAddr], IpGetAddrErr> {
- let (output_po, output_ch) = stream();
- let mut output_ch = Some(SharedChan::new(output_ch));
- do str::as_buf(node) |node_ptr, len| {
- let output_ch = output_ch.take_unwrap();
- debug!("slice len %?", len);
- let handle = create_uv_getaddrinfo_t();
- let handle_ptr: *uv_getaddrinfo_t = &handle;
- let handle_data = GetAddrData {
- output_ch: output_ch.clone()
- };
- let handle_data_ptr: *GetAddrData = &handle_data;
- do interact(iotask) |loop_ptr| {
- unsafe {
- let result = uv_getaddrinfo(
- loop_ptr,
- handle_ptr,
- get_addr_cb,
- node_ptr,
- ptr::null(),
- ptr::null());
- match result {
- 0i32 => {
- set_data_for_req(handle_ptr, handle_data_ptr);
- }
- _ => {
- output_ch.send(result::Err(GetAddrUnknownError));
- }
- }
- }
- };
- output_po.recv()
- }
-}
-
-pub mod v4 {
-
- use net::ip::{IpAddr, Ipv4, ParseAddrErr};
- use uv::ll;
- use uv_ip4_addr = uv::ll::ip4_addr;
- use uv_ip4_name = uv::ll::ip4_name;
-
- use std::cast::transmute;
- use std::result;
- use std::uint;
-
- /**
- * Convert a str to `ip_addr`
- *
- * # Failure
- *
- * Fails if the string is not a valid IPv4 address
- *
- * # Arguments
- *
- * * ip - a string of the format `x.x.x.x`
- *
- * # Returns
- *
- * * an `ip_addr` of the `ipv4` variant
- */
- pub fn parse_addr(ip: &str) -> IpAddr {
- match try_parse_addr(ip) {
- result::Ok(addr) => addr,
- result::Err(ref err_data) => fail!(err_data.err_msg.clone())
- }
- }
-
- // the simple, old style numberic representation of
- // ipv4
- #[deriving(Clone)]
- pub struct Ipv4Rep {
- a: u8,
- b: u8,
- c: u8,
- d: u8,
- }
-
- pub trait AsUnsafeU32 {
- unsafe fn as_u32(&self) -> u32;
- }
-
- impl AsUnsafeU32 for Ipv4Rep {
- // this is pretty dastardly, i know
- unsafe fn as_u32(&self) -> u32 {
- let this: &mut u32 = transmute(self);
- *this
- }
- }
- pub fn parse_to_ipv4_rep(ip: &str) -> result::Result<Ipv4Rep, ~str> {
- let parts: ~[uint] = ip.split_iter('.').transform(|s| {
- match uint::from_str(s) {
- Some(n) if n <= 255 => n,
- _ => 256
- }
- }).collect();
- if parts.len() != 4 {
- Err(fmt!("'%s' doesn't have 4 parts", ip))
- } else if parts.iter().any(|x| *x == 256u) {
- Err(fmt!("invalid octal in addr '%s'", ip))
- } else {
- Ok(Ipv4Rep {
- a: parts[0] as u8, b: parts[1] as u8,
- c: parts[2] as u8, d: parts[3] as u8,
- })
- }
- }
- pub fn try_parse_addr(ip: &str) -> result::Result<IpAddr,ParseAddrErr> {
- unsafe {
- let INADDR_NONE = ll::get_INADDR_NONE();
- let ip_rep_result = parse_to_ipv4_rep(ip);
- if result::is_err(&ip_rep_result) {
- let err_str = result::get_err(&ip_rep_result);
- return result::Err(ParseAddrErr { err_msg: err_str })
- }
- // ipv4_rep.as_u32 is unsafe :/
- let input_is_inaddr_none =
- result::get(&ip_rep_result).as_u32() == INADDR_NONE;
-
- let new_addr = uv_ip4_addr(ip, 22);
- let reformatted_name = uv_ip4_name(&new_addr);
- debug!("try_parse_addr: input ip: %s reparsed ip: %s",
- ip, reformatted_name);
- let ref_ip_rep_result = parse_to_ipv4_rep(reformatted_name);
- if result::is_err(&ref_ip_rep_result) {
- let err_str = result::get_err(&ref_ip_rep_result);
- return Err(ParseAddrErr { err_msg: err_str })
- }
-
- if result::get(&ref_ip_rep_result).as_u32() == INADDR_NONE &&
- !input_is_inaddr_none {
- Err(ParseAddrErr {
- err_msg: ~"uv_ip4_name produced invalid result.",
- })
- } else {
- Ok(Ipv4(new_addr))
- }
- }
- }
-}
-pub mod v6 {
-
- use net::ip::{IpAddr, Ipv6, ParseAddrErr};
- use uv_ip6_addr = uv::ll::ip6_addr;
- use uv_ip6_name = uv::ll::ip6_name;
-
- use std::result;
-
- /**
- * Convert a str to `ip_addr`
- *
- * # Failure
- *
- * Fails if the string is not a valid IPv6 address
- *
- * # Arguments
- *
- * * ip - an ipv6 string. See RFC2460 for spec.
- *
- * # Returns
- *
- * * an `ip_addr` of the `ipv6` variant
- */
- pub fn parse_addr(ip: &str) -> IpAddr {
- match try_parse_addr(ip) {
- result::Ok(addr) => addr,
- result::Err(err_data) => fail!(err_data.err_msg.clone())
- }
- }
- pub fn try_parse_addr(ip: &str) -> result::Result<IpAddr,ParseAddrErr> {
- unsafe {
- // need to figure out how to establish a parse failure..
- let new_addr = uv_ip6_addr(ip, 22);
- let reparsed_name = uv_ip6_name(&new_addr);
- debug!("v6::try_parse_addr ip: '%s' reparsed '%s'",
- ip, reparsed_name);
- // '::' appears to be uv_ip6_name() returns for bogus
- // parses..
- if ip != &"::" && reparsed_name == ~"::" {
- Err(ParseAddrErr { err_msg:fmt!("failed to parse '%s'", ip) })
- }
- else {
- Ok(Ipv6(new_addr))
- }
- }
- }
-}
-
-struct GetAddrData {
- output_ch: SharedChan<result::Result<~[IpAddr],IpGetAddrErr>>
-}
-
-extern fn get_addr_cb(handle: *uv_getaddrinfo_t,
- status: libc::c_int,
- res: *addrinfo) {
- unsafe {
- debug!("in get_addr_cb");
- let handle_data = get_data_for_req(handle) as
- *GetAddrData;
- let output_ch = (*handle_data).output_ch.clone();
- if status == 0i32 {
- if res != (ptr::null::<addrinfo>()) {
- let mut out_vec = ~[];
- debug!("initial addrinfo: %?", res);
- let mut curr_addr = res;
- loop {
- let new_ip_addr = if ll::is_ipv4_addrinfo(curr_addr) {
- Ipv4(*ll::addrinfo_as_sockaddr_in(curr_addr))
- }
- else if ll::is_ipv6_addrinfo(curr_addr) {
- Ipv6(*ll::addrinfo_as_sockaddr_in6(curr_addr))
- }
- else {
- debug!("curr_addr is not of family AF_INET or \
- AF_INET6. Error.");
- output_ch.send(
- result::Err(GetAddrUnknownError));
- break;
- };
- out_vec.push(new_ip_addr);
-
- let next_addr = ll::get_next_addrinfo(curr_addr);
- if next_addr == ptr::null::<addrinfo>() as *addrinfo {
- debug!("null next_addr encountered. no mas");
- break;
- }
- else {
- curr_addr = next_addr;
- debug!("next_addr addrinfo: %?", curr_addr);
- }
- }
- debug!("successful process addrinfo result, len: %?",
- out_vec.len());
- output_ch.send(result::Ok(out_vec));
- }
- else {
- debug!("addrinfo pointer is NULL");
- output_ch.send(
- result::Err(GetAddrUnknownError));
- }
- }
- else {
- debug!("status != 0 error in get_addr_cb");
- output_ch.send(
- result::Err(GetAddrUnknownError));
- }
- if res != (ptr::null::<addrinfo>()) {
- uv_freeaddrinfo(res);
- }
- debug!("leaving get_addr_cb");
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use net::ip::*;
- use net::ip::v4;
- use net::ip::v6;
- use uv;
-
- use std::result;
-
- #[test]
- fn test_ip_ipv4_parse_and_format_ip() {
- let localhost_str = ~"127.0.0.1";
- assert!(format_addr(&v4::parse_addr(localhost_str))
- == localhost_str)
- }
- #[test]
- fn test_ip_ipv6_parse_and_format_ip() {
- let localhost_str = ~"::1";
- let format_result = format_addr(&v6::parse_addr(localhost_str));
- debug!("results: expected: '%s' actual: '%s'",
- localhost_str, format_result);
- assert_eq!(format_result, localhost_str);
- }
- #[test]
- fn test_ip_ipv4_bad_parse() {
- match v4::try_parse_addr("b4df00d") {
- result::Err(ref err_info) => {
- debug!("got error as expected %?", err_info);
- assert!(true);
- }
- result::Ok(ref addr) => {
- fail!("Expected failure, but got addr %?", addr);
- }
- }
- }
- #[test]
- #[ignore(target_os="win32")]
- fn test_ip_ipv6_bad_parse() {
- match v6::try_parse_addr("::,~2234k;") {
- result::Err(ref err_info) => {
- debug!("got error as expected %?", err_info);
- assert!(true);
- }
- result::Ok(ref addr) => {
- fail!("Expected failure, but got addr %?", addr);
- }
- }
- }
- #[test]
- #[ignore(reason = "valgrind says it's leaky")]
- fn test_ip_get_addr() {
- let localhost_name = ~"localhost";
- let iotask = &uv::global_loop::get();
- let ga_result = get_addr(localhost_name, iotask);
- if result::is_err(&ga_result) {
- fail!("got err result from net::ip::get_addr();")
- }
- // note really sure how to reliably test/assert
- // this.. mostly just wanting to see it work, atm.
- let results = result::unwrap(ga_result);
- debug!("test_get_addr: Number of results for %s: %?",
- localhost_name, results.len());
- for results.iter().advance |r| {
- let ipv_prefix = match *r {
- Ipv4(_) => ~"IPv4",
- Ipv6(_) => ~"IPv6"
- };
- debug!("test_get_addr: result %s: '%s'",
- ipv_prefix, format_addr(r));
- }
- // at least one result.. this is going to vary from system
- // to system, based on stuff like the contents of /etc/hosts
- assert!(!results.is_empty());
- }
- #[test]
- #[ignore(reason = "valgrind says it's leaky")]
- fn test_ip_get_addr_bad_input() {
- let localhost_name = ~"sjkl234m,./sdf";
- let iotask = &uv::global_loop::get();
- let ga_result = get_addr(localhost_name, iotask);
- assert!(result::is_err(&ga_result));
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Top-level module for network-related functionality.
-
-Basically, including this module gives you:
-
-* `tcp`
-* `ip`
-* `url`
-
-See each of those three modules for documentation on what they do.
-*/
-
-pub mod tcp;
-pub mod ip;
-pub mod url;
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! High-level interface to libuv's TCP functionality
-// FIXME #4425: Need FFI fixes
-
-#[allow(missing_doc)];
-
-
-use future;
-use future_spawn = future::spawn;
-use ip = net::ip;
-use uv;
-use uv::iotask;
-use uv::iotask::IoTask;
-
-use std::io;
-use std::libc::size_t;
-use std::libc;
-use std::comm::{stream, Port, SharedChan};
-use std::ptr;
-use std::result::{Result};
-use std::result;
-use std::num;
-use std::vec;
-
-pub mod rustrt {
- use std::libc;
-
- #[nolink]
- extern {
- pub unsafe fn rust_uv_current_kernel_malloc(size: libc::c_uint)
- -> *libc::c_void;
- pub unsafe fn rust_uv_current_kernel_free(mem: *libc::c_void);
- pub unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint;
- }
-}
-
-/**
- * Encapsulates an open TCP/IP connection through libuv
- *
- * `TcpSocket` is non-copyable/sendable and automagically handles closing the
- * underlying libuv data structures when it goes out of scope. This is the
- * data structure that is used for read/write operations over a TCP stream.
- */
-pub struct TcpSocket {
- socket_data: @TcpSocketData,
-}
-
-#[unsafe_destructor]
-impl Drop for TcpSocket {
- fn drop(&self) {
- tear_down_socket_data(self.socket_data)
- }
-}
-
-pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket {
- TcpSocket {
- socket_data: socket_data
- }
-}
-
-/**
- * A buffered wrapper for `net::tcp::TcpSocket`
- *
- * It is created with a call to `net::tcp::socket_buf()` and has impls that
- * satisfy both the `io::Reader` and `io::Writer` traits.
- */
-pub struct TcpSocketBuf {
- data: @mut TcpBufferedSocketData,
- end_of_stream: @mut bool
-}
-
-pub fn TcpSocketBuf(data: @mut TcpBufferedSocketData) -> TcpSocketBuf {
- TcpSocketBuf {
- data: data,
- end_of_stream: @mut false
- }
-}
-
-/// Contains raw, string-based, error information returned from libuv
-#[deriving(Clone)]
-pub struct TcpErrData {
- err_name: ~str,
- err_msg: ~str,
-}
-
-/// Details returned as part of a `Result::Err` result from `tcp::listen`
-#[deriving(Clone)]
-pub enum TcpListenErrData {
- /**
- * Some unplanned-for error. The first and second fields correspond
- * to libuv's `err_name` and `err_msg` fields, respectively.
- */
- GenericListenErr(~str, ~str),
- /**
- * Failed to bind to the requested IP/Port, because it is already in use.
- *
- * # Possible Causes
- *
- * * Attempting to bind to a port already bound to another listener
- */
- AddressInUse,
- /**
- * Request to bind to an IP/Port was denied by the system.
- *
- * # Possible Causes
- *
- * * Attemping to binding to an IP/Port as a non-Administrator
- * on Windows Vista+
- * * Attempting to bind, as a non-priv'd
- * user, to 'privileged' ports (< 1024) on *nix
- */
- AccessDenied
-}
-/// Details returned as part of a `Result::Err` result from `tcp::connect`
-#[deriving(Clone)]
-pub enum TcpConnectErrData {
- /**
- * Some unplanned-for error. The first and second fields correspond
- * to libuv's `err_name` and `err_msg` fields, respectively.
- */
- GenericConnectErr(~str, ~str),
- /// Invalid IP or invalid port
- ConnectionRefused
-}
-
-/**
- * Initiate a client connection over TCP/IP
- *
- * # Arguments
- *
- * * `input_ip` - The IP address (versions 4 or 6) of the remote host
- * * `port` - the unsigned integer of the desired remote host port
- * * `iotask` - a `uv::iotask` that the tcp request will run on
- *
- * # Returns
- *
- * A `result` that, if the operation succeeds, contains a
- * `net::net::TcpSocket` that can be used to send and receive data to/from
- * the remote host. In the event of failure, a
- * `net::tcp::TcpConnectErrData` instance will be returned
- */
-pub fn connect(input_ip: ip::IpAddr, port: uint,
- iotask: &IoTask)
- -> result::Result<TcpSocket, TcpConnectErrData> {
- unsafe {
- let (result_po, result_ch) = stream::<ConnAttempt>();
- let result_ch = SharedChan::new(result_ch);
- let (closed_signal_po, closed_signal_ch) = stream::<()>();
- let closed_signal_ch = SharedChan::new(closed_signal_ch);
- let conn_data = ConnectReqData {
- result_ch: result_ch,
- closed_signal_ch: closed_signal_ch
- };
- let conn_data_ptr: *ConnectReqData = &conn_data;
- let (reader_po, reader_ch) = stream::<Result<~[u8], TcpErrData>>();
- let reader_ch = SharedChan::new(reader_ch);
- let stream_handle_ptr = malloc_uv_tcp_t();
- *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) = uv::ll::tcp_t();
- let socket_data = @TcpSocketData {
- reader_po: @reader_po,
- reader_ch: reader_ch,
- stream_handle_ptr: stream_handle_ptr,
- connect_req: uv::ll::connect_t(),
- write_req: uv::ll::write_t(),
- ipv6: match input_ip {
- ip::Ipv4(_) => { false }
- ip::Ipv6(_) => { true }
- },
- iotask: iotask.clone()
- };
- let socket_data_ptr: *TcpSocketData = &*socket_data;
- // get an unsafe representation of our stream_handle_ptr that
- // we can send into the interact cb to be handled in libuv..
- debug!("stream_handle_ptr outside interact %?",
- stream_handle_ptr);
- do iotask::interact(iotask) |loop_ptr| {
- debug!("in interact cb for tcp client connect..");
- debug!("stream_handle_ptr in interact %?",
- stream_handle_ptr);
- match uv::ll::tcp_init( loop_ptr, stream_handle_ptr) {
- 0i32 => {
- debug!("tcp_init successful");
- debug!("dealing w/ ipv4 connection..");
- let connect_req_ptr: *uv::ll::uv_connect_t =
- &(*socket_data_ptr).connect_req;
- let addr_str = ip::format_addr(&input_ip);
- let connect_result = match input_ip {
- ip::Ipv4(ref addr) => {
- // have to "recreate" the
- // sockaddr_in/6 since the ip_addr
- // discards the port info.. should
- // probably add an additional rust
- // type that actually is closer to
- // what the libuv API expects (ip str
- // + port num)
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip4_addr(addr_str,
- port as int);
- uv::ll::tcp_connect(
- connect_req_ptr,
- stream_handle_ptr,
- &in_addr,
- tcp_connect_on_connect_cb)
- }
- ip::Ipv6(ref addr) => {
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip6_addr(addr_str,
- port as int);
- uv::ll::tcp_connect6(
- connect_req_ptr,
- stream_handle_ptr,
- &in_addr,
- tcp_connect_on_connect_cb)
- }
- };
- match connect_result {
- 0i32 => {
- debug!("tcp_connect successful: \
- stream %x,
- socket data %x",
- stream_handle_ptr as uint,
- socket_data_ptr as uint);
- // reusable data that we'll have for the
- // duration..
- uv::ll::set_data_for_uv_handle(
- stream_handle_ptr,
- socket_data_ptr as
- *libc::c_void);
- // just so the connect_cb can send the
- // outcome..
- uv::ll::set_data_for_req(connect_req_ptr,
- conn_data_ptr);
- debug!("leaving tcp_connect interact cb...");
- // let tcp_connect_on_connect_cb send on
- // the result_ch, now..
- }
- _ => {
- // immediate connect
- // failure.. probably a garbage ip or
- // somesuch
- let err_data =
- uv::ll::get_last_err_data(loop_ptr);
- let result_ch = (*conn_data_ptr)
- .result_ch.clone();
- result_ch.send(ConnFailure(err_data));
- uv::ll::set_data_for_uv_handle(
- stream_handle_ptr,
- conn_data_ptr);
- uv::ll::close(stream_handle_ptr,
- stream_error_close_cb);
- }
- }
- }
- _ => {
- // failure to create a tcp handle
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- let result_ch = (*conn_data_ptr).result_ch.clone();
- result_ch.send(ConnFailure(err_data));
- }
- }
- }
- match result_po.recv() {
- ConnSuccess => {
- debug!("tcp::connect - received success on result_po");
- result::Ok(TcpSocket(socket_data))
- }
- ConnFailure(ref err_data) => {
- closed_signal_po.recv();
- debug!("tcp::connect - received failure on result_po");
- // still have to free the malloc'd stream handle..
- rustrt::rust_uv_current_kernel_free(stream_handle_ptr
- as *libc::c_void);
- let tcp_conn_err = match err_data.err_name {
- ~"ECONNREFUSED" => ConnectionRefused,
- _ => GenericConnectErr(err_data.err_name.clone(),
- err_data.err_msg.clone())
- };
- result::Err(tcp_conn_err)
- }
- }
- }
-}
-
-/**
- * Write binary data to a tcp stream; Blocks until operation completes
- *
- * # Arguments
- *
- * * sock - a `TcpSocket` to write to
- * * raw_write_data - a vector of `~[u8]` that will be written to the stream.
- * This value must remain valid for the duration of the `write` call
- *
- * # Returns
- *
- * A `Result` object with a `()` value as the `Ok` variant, or a
- * `TcpErrData` value as the `Err` variant
- */
-pub fn write(sock: &TcpSocket, raw_write_data: ~[u8])
- -> result::Result<(), TcpErrData> {
- let socket_data_ptr: *TcpSocketData = &*sock.socket_data;
- write_common_impl(socket_data_ptr, raw_write_data)
-}
-
-/**
- * Write binary data to tcp stream; Returns a `future::Future` value
- * immediately
- *
- * # Safety
- *
- * This function can produce unsafe results if:
- *
- * 1. the call to `write_future` is made
- * 2. the `future::Future` value returned is never resolved via
- * `Future::get`
- * 3. and then the `TcpSocket` passed in to `write_future` leaves
- * scope and is destructed before the task that runs the libuv write
- * operation completes.
- *
- * As such: If using `write_future`, always be sure to resolve the returned
- * `Future` so as to ensure libuv doesn't try to access a released write
- * handle. Otherwise, use the blocking `tcp::write` function instead.
- *
- * # Arguments
- *
- * * sock - a `TcpSocket` to write to
- * * raw_write_data - a vector of `~[u8]` that will be written to the stream.
- * This value must remain valid for the duration of the `write` call
- *
- * # Returns
- *
- * A `Future` value that, once the `write` operation completes, resolves to a
- * `Result` object with a `nil` value as the `Ok` variant, or a `TcpErrData`
- * value as the `Err` variant
- */
-pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8])
- -> future::Future<result::Result<(), TcpErrData>>
-{
- let socket_data_ptr: *TcpSocketData = &*sock.socket_data;
- do future_spawn {
- let data_copy = raw_write_data.clone();
- write_common_impl(socket_data_ptr, data_copy)
- }
-}
-
-/**
- * Begin reading binary data from an open TCP connection; used with
- * `read_stop`
- *
- * # Arguments
- *
- * * sock -- a `net::tcp::TcpSocket` for the connection to read from
- *
- * # Returns
- *
- * * A `Result` instance that will either contain a
- * `std::comm::Port<Result<~[u8], TcpErrData>>` that the user can read
- * (and * optionally, loop on) from until `read_stop` is called, or a
- * `TcpErrData` record
- */
-pub fn read_start(sock: &TcpSocket)
- -> result::Result<@Port<result::Result<~[u8],
- TcpErrData>>,
- TcpErrData> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- read_start_common_impl(socket_data)
-}
-
-/**
- * Stop reading from an open TCP connection; used with `read_start`
- *
- * # Arguments
- *
- * * `sock` - a `net::tcp::TcpSocket` that you wish to stop reading on
- */
-pub fn read_stop(sock: &TcpSocket) -> result::Result<(), TcpErrData> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- read_stop_common_impl(socket_data)
-}
-
-/**
- * Reads a single chunk of data from `TcpSocket`; block until data/error
- * recv'd
- *
- * Does a blocking read operation for a single chunk of data from a
- * `TcpSocket` until a data arrives or an error is received. The provided
- * `timeout_msecs` value is used to raise an error if the timeout period
- * passes without any data received.
- *
- * # Arguments
- *
- * * `sock` - a `net::tcp::TcpSocket` that you wish to read from
- * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the
- * read attempt. Pass `0u` to wait indefinitely
- */
-pub fn read(sock: &TcpSocket, timeout_msecs: uint)
- -> result::Result<~[u8],TcpErrData> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- read_common_impl(socket_data, timeout_msecs)
-}
-
-/**
- * Reads a single chunk of data; returns a `future::Future<~[u8]>`
- * immediately
- *
- * Does a non-blocking read operation for a single chunk of data from a
- * `TcpSocket` and immediately returns a `Future` value representing the
- * result. When resolving the returned `Future`, it will block until data
- * arrives or an error is received. The provided `timeout_msecs`
- * value is used to raise an error if the timeout period passes without any
- * data received.
- *
- * # Safety
- *
- * This function can produce unsafe results if the call to `read_future` is
- * made, the `future::Future` value returned is never resolved via
- * `Future::get`, and then the `TcpSocket` passed in to `read_future` leaves
- * scope and is destructed before the task that runs the libuv read
- * operation completes.
- *
- * As such: If using `read_future`, always be sure to resolve the returned
- * `Future` so as to ensure libuv doesn't try to access a released read
- * handle. Otherwise, use the blocking `tcp::read` function instead.
- *
- * # Arguments
- *
- * * `sock` - a `net::tcp::TcpSocket` that you wish to read from
- * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the
- * read attempt. Pass `0u` to wait indefinitely
- */
-fn read_future(sock: &TcpSocket, timeout_msecs: uint)
- -> future::Future<result::Result<~[u8],TcpErrData>> {
- let socket_data: *TcpSocketData = &*sock.socket_data;
- do future_spawn {
- read_common_impl(socket_data, timeout_msecs)
- }
-}
-
-/**
- * Bind an incoming client connection to a `net::tcp::TcpSocket`
- *
- * # Notes
- *
- * It is safe to call `net::tcp::accept` _only_ within the context of the
- * `new_connect_cb` callback provided as the final argument to the
- * `net::tcp::listen` function.
- *
- * The `new_conn` opaque value is provided _only_ as the first argument to the
- * `new_connect_cb` provided as a part of `net::tcp::listen`.
- * It can be safely sent to another task but it _must_ be
- * used (via `net::tcp::accept`) before the `new_connect_cb` call it was
- * provided to returns.
- *
- * This implies that a port/chan pair must be used to make sure that the
- * `new_connect_cb` call blocks until an attempt to create a
- * `net::tcp::TcpSocket` is completed.
- *
- * # Example
- *
- * Here, the `new_conn` is used in conjunction with `accept` from within
- * a task spawned by the `new_connect_cb` passed into `listen`
- *
- * ~~~ {.rust}
- * do net::tcp::listen(remote_ip, remote_port, backlog, iotask,
- * // this callback is ran once after the connection is successfully
- * // set up
- * |kill_ch| {
- * // pass the kill_ch to your main loop or wherever you want
- * // to be able to externally kill the server from
- * })
- * // this callback is ran when a new connection arrives
- * |new_conn, kill_ch| {
- * let (cont_po, cont_ch) = comm::stream::<option::Option<TcpErrData>>();
- * do task::spawn {
- * let accept_result = net::tcp::accept(new_conn);
- * match accept_result {
- * Err(accept_error) => {
- * cont_ch.send(Some(accept_error));
- * // fail?
- * },
- * Ok(sock) => {
- * cont_ch.send(None);
- * // do work here
- * }
- * }
- * };
- * match cont_po.recv() {
- * // shut down listen()
- * Some(err_data) => kill_ch.send(Some(err_data)),
- * // wait for next connection
- * None => ()
- * }
- * };
- * ~~~
- *
- * # Arguments
- *
- * * `new_conn` - an opaque value used to create a new `TcpSocket`
- *
- * # Returns
- *
- * On success, this function will return a `net::tcp::TcpSocket` as the
- * `Ok` variant of a `Result`. The `net::tcp::TcpSocket` is anchored within
- * the task that `accept` was called within for its lifetime. On failure,
- * this function will return a `net::tcp::TcpErrData` record
- * as the `Err` variant of a `Result`.
- */
-pub fn accept(new_conn: TcpNewConnection)
- -> result::Result<TcpSocket, TcpErrData> {
- unsafe {
- match new_conn{
- NewTcpConn(server_handle_ptr) => {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(
- server_handle_ptr) as *TcpListenFcData;
- let (reader_po, reader_ch) = stream::<
- Result<~[u8], TcpErrData>>();
- let reader_ch = SharedChan::new(reader_ch);
- let iotask = &(*server_data_ptr).iotask;
- let stream_handle_ptr = malloc_uv_tcp_t();
- *(stream_handle_ptr as *mut uv::ll::uv_tcp_t) =
- uv::ll::tcp_t();
- let client_socket_data: @TcpSocketData = @TcpSocketData {
- reader_po: @reader_po,
- reader_ch: reader_ch,
- stream_handle_ptr : stream_handle_ptr,
- connect_req : uv::ll::connect_t(),
- write_req : uv::ll::write_t(),
- ipv6: (*server_data_ptr).ipv6,
- iotask : iotask.clone()
- };
- let client_socket_data_ptr: *TcpSocketData =
- &*client_socket_data;
- let client_stream_handle_ptr =
- (*client_socket_data_ptr).stream_handle_ptr;
-
- let (result_po, result_ch) = stream::<Option<TcpErrData>>();
- let result_ch = SharedChan::new(result_ch);
-
- // UNSAFE LIBUV INTERACTION BEGIN
- // .. normally this happens within the context of
- // a call to uv::hl::interact.. but we're breaking
- // the rules here because this always has to be
- // called within the context of a listen() new_connect_cb
- // callback (or it will likely fail and drown your cat)
- debug!("in interact cb for tcp::accept");
- let loop_ptr = uv::ll::get_loop_for_uv_handle(
- server_handle_ptr);
- match uv::ll::tcp_init(loop_ptr, client_stream_handle_ptr) {
- 0i32 => {
- debug!("uv_tcp_init successful for \
- client stream");
- match uv::ll::accept(
- server_handle_ptr as *libc::c_void,
- client_stream_handle_ptr as *libc::c_void) {
- 0i32 => {
- debug!("successfully accepted client \
- connection: \
- stream %x, \
- socket data %x",
- client_stream_handle_ptr as uint,
- client_socket_data_ptr as uint);
- uv::ll::set_data_for_uv_handle(
- client_stream_handle_ptr,
- client_socket_data_ptr
- as *libc::c_void);
- let ptr = uv::ll::get_data_for_uv_handle(
- client_stream_handle_ptr);
- debug!("ptrs: %x %x",
- client_socket_data_ptr as uint,
- ptr as uint);
- result_ch.send(None);
- }
- _ => {
- debug!("failed to accept client conn");
- result_ch.send(Some(
- uv::ll::get_last_err_data(
- loop_ptr).to_tcp_err()));
- }
- }
- }
- _ => {
- debug!("failed to accept client stream");
- result_ch.send(Some(
- uv::ll::get_last_err_data(
- loop_ptr).to_tcp_err()));
- }
- }
- // UNSAFE LIBUV INTERACTION END
- match result_po.recv() {
- Some(err_data) => result::Err(err_data),
- None => result::Ok(TcpSocket(client_socket_data))
- }
- }
- }
- }
-}
-
-/**
- * Bind to a given IP/port and listen for new connections
- *
- * # Arguments
- *
- * * `host_ip` - a `net::ip::IpAddr` representing a unique IP
- * (versions 4 or 6)
- * * `port` - a uint representing the port to listen on
- * * `backlog` - a uint representing the number of incoming connections
- * to cache in memory
- * * `hl_loop` - a `uv_iotask::IoTask` that the tcp request will run on
- * * `on_establish_cb` - a callback that is evaluated if/when the listener
- * is successfully established. it takes no parameters
- * * `new_connect_cb` - a callback to be evaluated, on the libuv thread,
- * whenever a client attempts to conect on the provided ip/port. the
- * callback's arguments are:
- * * `new_conn` - an opaque type that can be passed to
- * `net::tcp::accept` in order to be converted to a `TcpSocket`.
- * * `kill_ch` - channel of type `std::comm::Chan<Option<tcp_err_data>>`.
- * this channel can be used to send a message to cause `listen` to begin
- * closing the underlying libuv data structures.
- *
- * # returns
- *
- * a `Result` instance containing empty data of type `()` on a
- * successful/normal shutdown, and a `TcpListenErrData` enum in the event
- * of listen exiting because of an error
- */
-pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint,
- iotask: &IoTask,
- on_establish_cb: ~fn(SharedChan<Option<TcpErrData>>),
- new_connect_cb: ~fn(TcpNewConnection,
- SharedChan<Option<TcpErrData>>))
- -> result::Result<(), TcpListenErrData> {
- do listen_common(host_ip, port, backlog, iotask,
- on_establish_cb)
- // on_connect_cb
- |handle| {
- unsafe {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(handle)
- as *TcpListenFcData;
- let new_conn = NewTcpConn(handle);
- let kill_ch = (*server_data_ptr).kill_ch.clone();
- new_connect_cb(new_conn, kill_ch);
- }
- }
-}
-
-fn listen_common(host_ip: ip::IpAddr,
- port: uint,
- backlog: uint,
- iotask: &IoTask,
- on_establish_cb: ~fn(SharedChan<Option<TcpErrData>>),
- on_connect_cb: ~fn(*uv::ll::uv_tcp_t))
- -> result::Result<(), TcpListenErrData> {
- let (stream_closed_po, stream_closed_ch) = stream::<()>();
- let stream_closed_ch = SharedChan::new(stream_closed_ch);
- let (kill_po, kill_ch) = stream::<Option<TcpErrData>>();
- let kill_ch = SharedChan::new(kill_ch);
- let server_stream = uv::ll::tcp_t();
- let server_stream_ptr: *uv::ll::uv_tcp_t = &server_stream;
- let server_data: TcpListenFcData = TcpListenFcData {
- server_stream_ptr: server_stream_ptr,
- stream_closed_ch: stream_closed_ch,
- kill_ch: kill_ch.clone(),
- on_connect_cb: on_connect_cb,
- iotask: iotask.clone(),
- ipv6: match &host_ip {
- &ip::Ipv4(_) => { false }
- &ip::Ipv6(_) => { true }
- },
- active: @mut true
- };
- let server_data_ptr: *TcpListenFcData = &server_data;
-
- let (setup_po, setup_ch) = stream();
-
- // this is to address a compiler warning about
- // an implicit copy.. it seems that double nested
- // will defeat a move sigil, as is done to the host_ip
- // arg above.. this same pattern works w/o complaint in
- // tcp::connect (because the iotask::interact cb isn't
- // nested within a core::comm::listen block)
- let loc_ip = host_ip;
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- match uv::ll::tcp_init(loop_ptr, server_stream_ptr) {
- 0i32 => {
- uv::ll::set_data_for_uv_handle(
- server_stream_ptr,
- server_data_ptr);
- let addr_str = ip::format_addr(&loc_ip);
- let bind_result = match loc_ip {
- ip::Ipv4(ref addr) => {
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip4_addr(
- addr_str,
- port as int);
- uv::ll::tcp_bind(server_stream_ptr, &in_addr)
- }
- ip::Ipv6(ref addr) => {
- debug!("addr: %?", addr);
- let in_addr = uv::ll::ip6_addr(
- addr_str,
- port as int);
- uv::ll::tcp_bind6(server_stream_ptr, &in_addr)
- }
- };
- match bind_result {
- 0i32 => {
- match uv::ll::listen(
- server_stream_ptr,
- backlog as libc::c_int,
- tcp_lfc_on_connection_cb) {
- 0i32 => setup_ch.send(None),
- _ => {
- debug!(
- "failure to uv_tcp_init");
- let err_data =
- uv::ll::get_last_err_data(
- loop_ptr);
- setup_ch.send(Some(err_data));
- }
- }
- }
- _ => {
- debug!("failure to uv_tcp_bind");
- let err_data = uv::ll::get_last_err_data(
- loop_ptr);
- setup_ch.send(Some(err_data));
- }
- }
- }
- _ => {
- debug!("failure to uv_tcp_bind");
- let err_data = uv::ll::get_last_err_data(
- loop_ptr);
- setup_ch.send(Some(err_data));
- }
- }
- }
- }
-
- let setup_result = setup_po.recv();
-
- match setup_result {
- Some(ref err_data) => {
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- debug!(
- "tcp::listen post-kill recv hl interact %?",
- loop_ptr);
- *(*server_data_ptr).active = false;
- uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
- }
- };
- stream_closed_po.recv();
- match err_data.err_name {
- ~"EACCES" => {
- debug!("Got EACCES error");
- result::Err(AccessDenied)
- }
- ~"EADDRINUSE" => {
- debug!("Got EADDRINUSE error");
- result::Err(AddressInUse)
- }
- _ => {
- debug!("Got '%s' '%s' libuv error",
- err_data.err_name, err_data.err_msg);
- result::Err(
- GenericListenErr(err_data.err_name.clone(),
- err_data.err_msg.clone()))
- }
- }
- }
- None => {
- on_establish_cb(kill_ch.clone());
- let kill_result = kill_po.recv();
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- debug!(
- "tcp::listen post-kill recv hl interact %?",
- loop_ptr);
- *(*server_data_ptr).active = false;
- uv::ll::close(server_stream_ptr, tcp_lfc_close_cb);
- }
- };
- stream_closed_po.recv();
- match kill_result {
- // some failure post bind/listen
- Some(ref err_data) => result::Err(GenericListenErr(
- err_data.err_name.clone(),
- err_data.err_msg.clone())),
- // clean exit
- None => result::Ok(())
- }
- }
- }
-}
-
-
-/**
- * Convert a `net::tcp::TcpSocket` to a `net::tcp::TcpSocketBuf`.
- *
- * This function takes ownership of a `net::tcp::TcpSocket`, returning it
- * stored within a buffered wrapper, which can be converted to a `io::Reader`
- * or `io::Writer`
- *
- * # Arguments
- *
- * * `sock` -- a `net::tcp::TcpSocket` that you want to buffer
- *
- * # Returns
- *
- * A buffered wrapper that you can cast as an `io::Reader` or `io::Writer`
- */
-pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf {
- TcpSocketBuf(@mut TcpBufferedSocketData {
- sock: sock, buf: ~[], buf_off: 0
- })
-}
-
-/// Convenience methods extending `net::tcp::TcpSocket`
-impl TcpSocket {
- pub fn read_start(&self) -> result::Result<@Port<
- result::Result<~[u8], TcpErrData>>, TcpErrData> {
- read_start(self)
- }
- pub fn read_stop(&self) ->
- result::Result<(), TcpErrData> {
- read_stop(self)
- }
- pub fn read(&self, timeout_msecs: uint) ->
- result::Result<~[u8], TcpErrData> {
- read(self, timeout_msecs)
- }
- pub fn read_future(&self, timeout_msecs: uint) ->
- future::Future<result::Result<~[u8], TcpErrData>> {
- read_future(self, timeout_msecs)
- }
- pub fn write(&self, raw_write_data: ~[u8])
- -> result::Result<(), TcpErrData> {
- write(self, raw_write_data)
- }
- pub fn write_future(&self, raw_write_data: ~[u8])
- -> future::Future<result::Result<(), TcpErrData>> {
- write_future(self, raw_write_data)
- }
- pub fn get_peer_addr(&self) -> ip::IpAddr {
- unsafe {
- if self.socket_data.ipv6 {
- let addr = uv::ll::ip6_addr("", 0);
- uv::ll::tcp_getpeername6(self.socket_data.stream_handle_ptr,
- &addr);
- ip::Ipv6(addr)
- } else {
- let addr = uv::ll::ip4_addr("", 0);
- uv::ll::tcp_getpeername(self.socket_data.stream_handle_ptr,
- &addr);
- ip::Ipv4(addr)
- }
- }
- }
-}
-
-/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket`
-impl io::Reader for TcpSocketBuf {
- fn read(&self, buf: &mut [u8], len: uint) -> uint {
- if len == 0 { return 0 }
- let mut count: uint = 0;
-
- loop {
- assert!(count < len);
-
- // If possible, copy up to `len` bytes from the internal
- // `data.buf` into `buf`
- let nbuffered = self.data.buf.len() - self.data.buf_off;
- let needed = len - count;
- if nbuffered > 0 {
- unsafe {
- let ncopy = num::min(nbuffered, needed);
- let dst = ptr::mut_offset(
- vec::raw::to_mut_ptr(buf), count);
- let src = ptr::offset(
- vec::raw::to_ptr(self.data.buf),
- self.data.buf_off);
- ptr::copy_memory(dst, src, ncopy);
- self.data.buf_off += ncopy;
- count += ncopy;
- }
- }
-
- assert!(count <= len);
- if count == len {
- break;
- }
-
- // We copied all the bytes we had in the internal buffer into
- // the result buffer, but the caller wants more bytes, so we
- // need to read in data from the socket. Note that the internal
- // buffer is of no use anymore as we read all bytes from it,
- // so we can throw it away.
- let read_result = {
- let data = &*self.data;
- read(&data.sock, 0)
- };
- if read_result.is_err() {
- let err_data = read_result.get_err();
-
- if err_data.err_name == ~"EOF" {
- *self.end_of_stream = true;
- break;
- } else {
- debug!("ERROR sock_buf as io::reader.read err %? %?",
- err_data.err_name, err_data.err_msg);
- // As we have already copied data into result buffer,
- // we cannot simply return 0 here. Instead the error
- // should show up in a later call to read().
- break;
- }
- } else {
- self.data.buf = result::unwrap(read_result);
- self.data.buf_off = 0;
- }
- }
-
- count
- }
- fn read_byte(&self) -> int {
- loop {
- if self.data.buf.len() > self.data.buf_off {
- let c = self.data.buf[self.data.buf_off];
- self.data.buf_off += 1;
- return c as int
- }
-
- let read_result = {
- let data = &*self.data;
- read(&data.sock, 0)
- };
- if read_result.is_err() {
- let err_data = read_result.get_err();
-
- if err_data.err_name == ~"EOF" {
- *self.end_of_stream = true;
- return -1
- } else {
- debug!("ERROR sock_buf as io::reader.read err %? %?",
- err_data.err_name, err_data.err_msg);
- fail!()
- }
- } else {
- self.data.buf = result::unwrap(read_result);
- self.data.buf_off = 0;
- }
- }
- }
- fn eof(&self) -> bool {
- *self.end_of_stream
- }
- fn seek(&self, dist: int, seek: io::SeekStyle) {
- debug!("tcp_socket_buf seek stub %? %?", dist, seek);
- // noop
- }
- fn tell(&self) -> uint {
- 0u // noop
- }
-}
-
-/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket`
-impl io::Writer for TcpSocketBuf {
- pub fn write(&self, data: &[u8]) {
- let socket_data_ptr: *TcpSocketData =
- &(*((*(self.data)).sock).socket_data);
- let w_result = write_common_impl(socket_data_ptr,
- data.slice(0, data.len()).to_owned());
- if w_result.is_err() {
- let err_data = w_result.get_err();
- debug!(
- "ERROR sock_buf as io::writer.writer err: %? %?",
- err_data.err_name, err_data.err_msg);
- }
- }
- fn seek(&self, dist: int, seek: io::SeekStyle) {
- debug!("tcp_socket_buf seek stub %? %?", dist, seek);
- // noop
- }
- fn tell(&self) -> uint {
- 0u
- }
- fn flush(&self) -> int {
- 0
- }
- fn get_type(&self) -> io::WriterType {
- io::File
- }
-}
-
-// INTERNAL API
-
-fn tear_down_socket_data(socket_data: @TcpSocketData) {
- unsafe {
- let (closed_po, closed_ch) = stream::<()>();
- let closed_ch = SharedChan::new(closed_ch);
- let close_data = TcpSocketCloseData {
- closed_ch: closed_ch
- };
- let close_data_ptr: *TcpSocketCloseData = &close_data;
- let stream_handle_ptr = (*socket_data).stream_handle_ptr;
- do iotask::interact(&(*socket_data).iotask) |loop_ptr| {
- debug!(
- "interact dtor for tcp_socket stream %? loop %?",
- stream_handle_ptr, loop_ptr);
- uv::ll::set_data_for_uv_handle(stream_handle_ptr,
- close_data_ptr);
- uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb);
- };
- closed_po.recv();
- //the line below will most likely crash
- //log(debug, fmt!("about to free socket_data at %?", socket_data));
- rustrt::rust_uv_current_kernel_free(stream_handle_ptr
- as *libc::c_void);
- debug!("exiting dtor for tcp_socket");
- }
-}
-
-// shared implementation for tcp::read
-fn read_common_impl(socket_data: *TcpSocketData, timeout_msecs: uint)
- -> result::Result<~[u8],TcpErrData> {
- unsafe {
- use timer;
-
- debug!("starting tcp::read");
- let iotask = &(*socket_data).iotask;
- let rs_result = read_start_common_impl(socket_data);
- if result::is_err(&rs_result) {
- let err_data = result::get_err(&rs_result);
- result::Err(err_data)
- }
- else {
- debug!("tcp::read before recv_timeout");
- let read_result = if timeout_msecs > 0u {
- timer::recv_timeout(
- iotask, timeout_msecs, result::unwrap(rs_result))
- } else {
- Some(result::get(&rs_result).recv())
- };
- debug!("tcp::read after recv_timeout");
- match read_result {
- None => {
- debug!("tcp::read: timed out..");
- let err_data = TcpErrData {
- err_name: ~"TIMEOUT",
- err_msg: ~"req timed out"
- };
- read_stop_common_impl(socket_data);
- result::Err(err_data)
- }
- Some(data_result) => {
- debug!("tcp::read got data");
- read_stop_common_impl(socket_data);
- data_result
- }
- }
- }
- }
-}
-
-// shared impl for read_stop
-fn read_stop_common_impl(socket_data: *TcpSocketData) ->
- result::Result<(), TcpErrData> {
- unsafe {
- let stream_handle_ptr = (*socket_data).stream_handle_ptr;
- let (stop_po, stop_ch) = stream::<Option<TcpErrData>>();
- do iotask::interact(&(*socket_data).iotask) |loop_ptr| {
- debug!("in interact cb for tcp::read_stop");
- match uv::ll::read_stop(stream_handle_ptr
- as *uv::ll::uv_stream_t) {
- 0i32 => {
- debug!("successfully called uv_read_stop");
- stop_ch.send(None);
- }
- _ => {
- debug!("failure in calling uv_read_stop");
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- stop_ch.send(Some(err_data.to_tcp_err()));
- }
- }
- }
- match stop_po.recv() {
- Some(err_data) => Err(err_data),
- None => Ok(())
- }
- }
-}
-
-// shared impl for read_start
-fn read_start_common_impl(socket_data: *TcpSocketData)
- -> result::Result<@Port<
- result::Result<~[u8], TcpErrData>>, TcpErrData> {
- unsafe {
- let stream_handle_ptr = (*socket_data).stream_handle_ptr;
- let (start_po, start_ch) = stream::<Option<uv::ll::uv_err_data>>();
- debug!("in tcp::read_start before interact loop");
- do iotask::interact(&(*socket_data).iotask) |loop_ptr| {
- debug!("in tcp::read_start interact cb %?",
- loop_ptr);
- match uv::ll::read_start(stream_handle_ptr
- as *uv::ll::uv_stream_t,
- on_alloc_cb,
- on_tcp_read_cb) {
- 0i32 => {
- debug!("success doing uv_read_start");
- start_ch.send(None);
- }
- _ => {
- debug!("error attempting uv_read_start");
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- start_ch.send(Some(err_data));
- }
- }
- }
- match start_po.recv() {
- Some(ref err_data) => result::Err(
- err_data.to_tcp_err()),
- None => {
- result::Ok((*socket_data).reader_po)
- }
- }
- }
-}
-
-// helper to convert a "class" vector of [u8] to a *[uv::ll::uv_buf_t]
-
-// shared implementation used by write and write_future
-fn write_common_impl(socket_data_ptr: *TcpSocketData,
- raw_write_data: ~[u8])
- -> result::Result<(), TcpErrData> {
- unsafe {
- let write_req_ptr: *uv::ll::uv_write_t =
- &(*socket_data_ptr).write_req;
- let stream_handle_ptr =
- (*socket_data_ptr).stream_handle_ptr;
- let write_buf_vec = ~[
- uv::ll::buf_init(vec::raw::to_ptr(raw_write_data),
- raw_write_data.len())
- ];
- let write_buf_vec_ptr: *~[uv::ll::uv_buf_t] = &write_buf_vec;
- let (result_po, result_ch) = stream::<TcpWriteResult>();
- let result_ch = SharedChan::new(result_ch);
- let write_data = WriteReqData {
- result_ch: result_ch
- };
- let write_data_ptr: *WriteReqData = &write_data;
- do iotask::interact(&(*socket_data_ptr).iotask) |loop_ptr| {
- debug!("in interact cb for tcp::write %?",
- loop_ptr);
- match uv::ll::write(write_req_ptr,
- stream_handle_ptr,
- write_buf_vec_ptr,
- tcp_write_complete_cb) {
- 0i32 => {
- debug!("uv_write() invoked successfully");
- uv::ll::set_data_for_req(write_req_ptr,
- write_data_ptr);
- }
- _ => {
- debug!("error invoking uv_write()");
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- let result_ch = (*write_data_ptr).result_ch.clone();
- result_ch.send(TcpWriteError(err_data.to_tcp_err()));
- }
- }
- }
- // FIXME (#2656): Instead of passing unsafe pointers to local data,
- // and waiting here for the write to complete, we should transfer
- // ownership of everything to the I/O task and let it deal with the
- // aftermath, so we don't have to sit here blocking.
- match result_po.recv() {
- TcpWriteSuccess => Ok(()),
- TcpWriteError(err_data) => Err(err_data)
- }
- }
-}
-
-enum TcpNewConnection {
- NewTcpConn(*uv::ll::uv_tcp_t)
-}
-
-struct TcpListenFcData {
- server_stream_ptr: *uv::ll::uv_tcp_t,
- stream_closed_ch: SharedChan<()>,
- kill_ch: SharedChan<Option<TcpErrData>>,
- on_connect_cb: ~fn(*uv::ll::uv_tcp_t),
- iotask: IoTask,
- ipv6: bool,
- active: @mut bool,
-}
-
-extern fn tcp_lfc_close_cb(handle: *uv::ll::uv_tcp_t) {
- unsafe {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(
- handle) as *TcpListenFcData;
- let stream_closed_ch = (*server_data_ptr).stream_closed_ch.clone();
- stream_closed_ch.send(());
- }
-}
-
-extern fn tcp_lfc_on_connection_cb(handle: *uv::ll::uv_tcp_t,
- status: libc::c_int) {
- unsafe {
- let server_data_ptr = uv::ll::get_data_for_uv_handle(handle)
- as *TcpListenFcData;
- let kill_ch = (*server_data_ptr).kill_ch.clone();
- if *(*server_data_ptr).active {
- match status {
- 0i32 => ((*server_data_ptr).on_connect_cb)(handle),
- _ => {
- let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
- kill_ch.send(
- Some(uv::ll::get_last_err_data(loop_ptr)
- .to_tcp_err()));
- *(*server_data_ptr).active = false;
- }
- }
- }
- }
-}
-
-fn malloc_uv_tcp_t() -> *uv::ll::uv_tcp_t {
- unsafe {
- rustrt::rust_uv_current_kernel_malloc(
- rustrt::rust_uv_helper_uv_tcp_t_size()) as *uv::ll::uv_tcp_t
- }
-}
-
-enum TcpConnectResult {
- TcpConnected(TcpSocket),
- TcpConnectError(TcpErrData)
-}
-
-enum TcpWriteResult {
- TcpWriteSuccess,
- TcpWriteError(TcpErrData)
-}
-
-enum TcpReadStartResult {
- TcpReadStartSuccess(Port<TcpReadResult>),
- TcpReadStartError(TcpErrData)
-}
-
-enum TcpReadResult {
- TcpReadData(~[u8]),
- TcpReadDone,
- TcpReadErr(TcpErrData)
-}
-
-trait ToTcpErr {
- fn to_tcp_err(&self) -> TcpErrData;
-}
-
-impl ToTcpErr for uv::ll::uv_err_data {
- fn to_tcp_err(&self) -> TcpErrData {
- TcpErrData {
- err_name: self.err_name.clone(),
- err_msg: self.err_msg.clone(),
- }
- }
-}
-
-extern fn on_tcp_read_cb(stream: *uv::ll::uv_stream_t,
- nread: libc::ssize_t,
- buf: uv::ll::uv_buf_t) {
- unsafe {
- debug!("entering on_tcp_read_cb stream: %x nread: %?",
- stream as uint, nread);
- let loop_ptr = uv::ll::get_loop_for_uv_handle(stream);
- let socket_data_ptr = uv::ll::get_data_for_uv_handle(stream)
- as *TcpSocketData;
- debug!("socket data is %x", socket_data_ptr as uint);
- match nread as int {
- // incoming err.. probably eof
- -1 => {
- let err_data = uv::ll::get_last_err_data(loop_ptr).to_tcp_err();
- debug!("on_tcp_read_cb: incoming err.. name %? msg %?",
- err_data.err_name, err_data.err_msg);
- let reader_ch = &(*socket_data_ptr).reader_ch;
- reader_ch.send(result::Err(err_data));
- }
- // do nothing .. unneeded buf
- 0 => (),
- // have data
- _ => {
- // we have data
- debug!("tcp on_read_cb nread: %d", nread as int);
- let reader_ch = &(*socket_data_ptr).reader_ch;
- let buf_base = uv::ll::get_base_from_buf(buf);
- let new_bytes = vec::from_buf(buf_base, nread as uint);
- reader_ch.send(result::Ok(new_bytes));
- }
- }
- uv::ll::free_base_of_buf(buf);
- debug!("exiting on_tcp_read_cb");
- }
-}
-
-extern fn on_alloc_cb(handle: *libc::c_void,
- suggested_size: size_t)
- -> uv::ll::uv_buf_t {
- unsafe {
- debug!("tcp read on_alloc_cb!");
- let char_ptr = uv::ll::malloc_buf_base_of(suggested_size);
- debug!("tcp read on_alloc_cb h: %? char_ptr: %u sugsize: %u",
- handle,
- char_ptr as uint,
- suggested_size as uint);
- uv::ll::buf_init(char_ptr, suggested_size as uint)
- }
-}
-
-struct TcpSocketCloseData {
- closed_ch: SharedChan<()>,
-}
-
-extern fn tcp_socket_dtor_close_cb(handle: *uv::ll::uv_tcp_t) {
- unsafe {
- let data = uv::ll::get_data_for_uv_handle(handle)
- as *TcpSocketCloseData;
- let closed_ch = (*data).closed_ch.clone();
- closed_ch.send(());
- debug!("tcp_socket_dtor_close_cb exiting..");
- }
-}
-
-extern fn tcp_write_complete_cb(write_req: *uv::ll::uv_write_t,
- status: libc::c_int) {
- unsafe {
- let write_data_ptr = uv::ll::get_data_for_req(write_req)
- as *WriteReqData;
- if status == 0i32 {
- debug!("successful write complete");
- let result_ch = (*write_data_ptr).result_ch.clone();
- result_ch.send(TcpWriteSuccess);
- } else {
- let stream_handle_ptr = uv::ll::get_stream_handle_from_write_req(
- write_req);
- let loop_ptr = uv::ll::get_loop_for_uv_handle(stream_handle_ptr);
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- debug!("failure to write");
- let result_ch = (*write_data_ptr).result_ch.clone();
- result_ch.send(TcpWriteError(err_data.to_tcp_err()));
- }
- }
-}
-
-struct WriteReqData {
- result_ch: SharedChan<TcpWriteResult>,
-}
-
-struct ConnectReqData {
- result_ch: SharedChan<ConnAttempt>,
- closed_signal_ch: SharedChan<()>,
-}
-
-extern fn stream_error_close_cb(handle: *uv::ll::uv_tcp_t) {
- unsafe {
- let data = uv::ll::get_data_for_uv_handle(handle) as
- *ConnectReqData;
- let closed_signal_ch = (*data).closed_signal_ch.clone();
- closed_signal_ch.send(());
- debug!("exiting steam_error_close_cb for %?", handle);
- }
-}
-
-extern fn tcp_connect_close_cb(handle: *uv::ll::uv_tcp_t) {
- debug!("closed client tcp handle %?", handle);
-}
-
-extern fn tcp_connect_on_connect_cb(connect_req_ptr: *uv::ll::uv_connect_t,
- status: libc::c_int) {
- unsafe {
- let conn_data_ptr = (uv::ll::get_data_for_req(connect_req_ptr)
- as *ConnectReqData);
- let result_ch = (*conn_data_ptr).result_ch.clone();
- debug!("tcp_connect result_ch %?", result_ch);
- let tcp_stream_ptr =
- uv::ll::get_stream_handle_from_connect_req(connect_req_ptr);
- match status {
- 0i32 => {
- debug!("successful tcp connection!");
- result_ch.send(ConnSuccess);
- }
- _ => {
- debug!("error in tcp_connect_on_connect_cb");
- let loop_ptr = uv::ll::get_loop_for_uv_handle(tcp_stream_ptr);
- let err_data = uv::ll::get_last_err_data(loop_ptr);
- debug!("err_data %? %?", err_data.err_name,
- err_data.err_msg);
- result_ch.send(ConnFailure(err_data));
- uv::ll::set_data_for_uv_handle(tcp_stream_ptr,
- conn_data_ptr);
- uv::ll::close(tcp_stream_ptr, stream_error_close_cb);
- }
- }
- debug!("leaving tcp_connect_on_connect_cb");
- }
-}
-
-enum ConnAttempt {
- ConnSuccess,
- ConnFailure(uv::ll::uv_err_data)
-}
-
-struct TcpSocketData {
- reader_po: @Port<result::Result<~[u8], TcpErrData>>,
- reader_ch: SharedChan<result::Result<~[u8], TcpErrData>>,
- stream_handle_ptr: *uv::ll::uv_tcp_t,
- connect_req: uv::ll::uv_connect_t,
- write_req: uv::ll::uv_write_t,
- ipv6: bool,
- iotask: IoTask,
-}
-
-struct TcpBufferedSocketData {
- sock: TcpSocket,
- buf: ~[u8],
- buf_off: uint
-}
-
-#[cfg(test)]
-mod test {
-
- use net::ip;
- use net::tcp::{GenericListenErr, TcpConnectErrData, TcpListenErrData};
- use net::tcp::{connect, accept, read, listen, TcpSocket, socket_buf};
- use net;
- use uv::iotask::IoTask;
- use uv;
-
- use std::cell::Cell;
- use std::comm::{stream, SharedChan};
- use std::io;
- use std::result;
- use std::str;
- use std::task;
-
- // FIXME don't run on fbsd or linux 32 bit (#2064)
- #[cfg(target_os="win32")]
- #[cfg(target_os="darwin")]
- #[cfg(target_os="linux")]
- #[cfg(target_os="android")]
- mod tcp_ipv4_server_and_client_test {
- #[cfg(target_arch="x86_64")]
- mod impl64 {
- use net::tcp::test::*;
-
- #[test]
- fn test_gl_tcp_server_and_client_ipv4() {
- impl_gl_tcp_ipv4_server_and_client();
- }
- #[test]
- fn test_gl_tcp_get_peer_addr() {
- impl_gl_tcp_ipv4_get_peer_addr();
- }
- #[test]
- fn test_gl_tcp_ipv4_client_error_connection_refused() {
- impl_gl_tcp_ipv4_client_error_connection_refused();
- }
- #[test]
- fn test_gl_tcp_server_address_in_use() {
- impl_gl_tcp_ipv4_server_address_in_use();
- }
- #[test]
- fn test_gl_tcp_server_access_denied() {
- impl_gl_tcp_ipv4_server_access_denied();
- }
- // Strange failure on Windows. --pcwalton
- #[test]
- #[ignore(cfg(target_os = "win32"))]
- fn test_gl_tcp_ipv4_server_client_reader_writer() {
- impl_gl_tcp_ipv4_server_client_reader_writer();
- }
- #[test]
- fn test_tcp_socket_impl_reader_handles_eof() {
- impl_tcp_socket_impl_reader_handles_eof();
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- mod impl32 {
- use net::tcp::test::*;
-
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_server_and_client_ipv4() {
- unsafe {
- impl_gl_tcp_ipv4_server_and_client();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_get_peer_addr() {
- unsafe {
- impl_gl_tcp_ipv4_get_peer_addr();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_ipv4_client_error_connection_refused() {
- unsafe {
- impl_gl_tcp_ipv4_client_error_connection_refused();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_gl_tcp_server_address_in_use() {
- unsafe {
- impl_gl_tcp_ipv4_server_address_in_use();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- #[ignore(cfg(windows), reason = "deadlocking bots")]
- fn test_gl_tcp_server_access_denied() {
- unsafe {
- impl_gl_tcp_ipv4_server_access_denied();
- }
- }
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- #[ignore(cfg(target_os = "win32"))]
- fn test_gl_tcp_ipv4_server_client_reader_writer() {
- impl_gl_tcp_ipv4_server_client_reader_writer();
- }
- }
- }
- pub fn impl_gl_tcp_ipv4_server_and_client() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8888u;
- let expected_req = ~"ping";
- let expected_resp = "pong";
-
- let (server_result_po, server_result_ch) = stream::<~str>();
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- let actual_req = run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- server_result_ch.send(actual_req);
- };
- cont_po.recv();
- // client
- debug!("server started, firing up client..");
- let actual_resp_result = run_tcp_test_client(
- server_ip,
- server_port,
- expected_req,
- hl_loop);
- assert!(actual_resp_result.is_ok());
- let actual_resp = actual_resp_result.get();
- let actual_req = server_result_po.recv();
- debug!("REQ: expected: '%s' actual: '%s'",
- expected_req, actual_req);
- debug!("RESP: expected: '%s' actual: '%s'",
- expected_resp, actual_resp);
- assert!(actual_req.contains(expected_req));
- assert!(actual_resp.contains(expected_resp));
- }
- pub fn impl_gl_tcp_ipv4_get_peer_addr() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8887u;
- let expected_resp = "pong";
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- };
- cont_po.recv();
- // client
- debug!("server started, firing up client..");
- let server_ip_addr = ip::v4::parse_addr(server_ip);
- let iotask = uv::global_loop::get();
- let connect_result = connect(server_ip_addr, server_port,
- &iotask);
-
- let sock = result::unwrap(connect_result);
-
- debug!("testing peer address");
- // This is what we are actually testing!
- assert!(net::ip::format_addr(&sock.get_peer_addr()) ==
- ~"127.0.0.1");
- assert_eq!(net::ip::get_port(&sock.get_peer_addr()), 8887);
-
- // Fulfill the protocol the test server expects
- let resp_bytes = "ping".as_bytes().to_owned();
- tcp_write_single(&sock, resp_bytes);
- debug!("message sent");
- sock.read(0u);
- debug!("result read");
- }
- pub fn impl_gl_tcp_ipv4_client_error_connection_refused() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8889u;
- let expected_req = ~"ping";
- // client
- debug!("firing up client..");
- let actual_resp_result = run_tcp_test_client(
- server_ip,
- server_port,
- expected_req,
- hl_loop);
- match actual_resp_result.get_err() {
- ConnectionRefused => (),
- _ => fail!("unknown error.. expected connection_refused")
- }
- }
- pub fn impl_gl_tcp_ipv4_server_address_in_use() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8890u;
- let expected_req = ~"ping";
- let expected_resp = "pong";
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- }
- cont_po.recv();
- // this one should fail..
- let listen_err = run_tcp_test_server_fail(
- server_ip,
- server_port,
- hl_loop);
- // client.. just doing this so that the first server tears down
- debug!("server started, firing up client..");
- run_tcp_test_client(
- server_ip,
- server_port,
- expected_req,
- hl_loop);
- match listen_err {
- AddressInUse => {
- assert!(true);
- }
- _ => {
- fail!("expected address_in_use listen error, \
- but got a different error varient. check logs.");
- }
- }
- }
- pub fn impl_gl_tcp_ipv4_server_access_denied() {
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 80u;
- // this one should fail..
- let listen_err = run_tcp_test_server_fail(
- server_ip,
- server_port,
- hl_loop);
- match listen_err {
- AccessDenied => {
- assert!(true);
- }
- _ => {
- fail!("expected address_in_use listen error, \
- but got a different error varient. check logs.");
- }
- }
- }
- pub fn impl_gl_tcp_ipv4_server_client_reader_writer() {
-
- let iotask = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 8891u;
- let expected_req = ~"ping";
- let expected_resp = "pong";
-
- let (server_result_po, server_result_ch) = stream::<~str>();
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let iotask_clone = iotask.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- let actual_req = run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &iotask_clone);
- server_result_ch.send(actual_req);
- };
- cont_po.recv();
- // client
- let server_addr = ip::v4::parse_addr(server_ip);
- let conn_result = connect(server_addr, server_port, iotask);
- if result::is_err(&conn_result) {
- assert!(false);
- }
- let sock_buf = @socket_buf(result::unwrap(conn_result));
- buf_write(sock_buf, expected_req);
-
- // so contrived!
- let actual_resp = buf_read(sock_buf, expected_resp.as_bytes().len());
-
- let actual_req = server_result_po.recv();
- debug!("REQ: expected: '%s' actual: '%s'",
- expected_req, actual_req);
- debug!("RESP: expected: '%s' actual: '%s'",
- expected_resp, actual_resp);
- assert!(actual_req.contains(expected_req));
- assert!(actual_resp.contains(expected_resp));
- }
-
- pub fn impl_tcp_socket_impl_reader_handles_eof() {
- use std::io::{Reader,ReaderUtil};
-
- let hl_loop = &uv::global_loop::get();
- let server_ip = "127.0.0.1";
- let server_port = 10041u;
- let expected_req = ~"GET /";
- let expected_resp = "A string\nwith multiple lines\n";
-
- let (cont_po, cont_ch) = stream::<()>();
- let cont_ch = SharedChan::new(cont_ch);
- // server
- let hl_loop_clone = hl_loop.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- let cont_ch = cont_ch.clone();
- run_tcp_test_server(
- server_ip,
- server_port,
- expected_resp.to_str(),
- cont_ch.clone(),
- &hl_loop_clone);
- };
- cont_po.recv();
- // client
- debug!("server started, firing up client..");
- let server_addr = ip::v4::parse_addr(server_ip);
- let conn_result = connect(server_addr, server_port, hl_loop);
- if result::is_err(&conn_result) {
- assert!(false);
- }
- let sock_buf = @socket_buf(result::unwrap(conn_result));
- buf_write(sock_buf, expected_req);
-
- let buf_reader = sock_buf as @Reader;
- let actual_response = str::from_bytes(buf_reader.read_whole_stream());
- debug!("Actual response: %s", actual_response);
- assert!(expected_resp == actual_response);
- }
-
- fn buf_write<W:io::Writer>(w: &W, val: &str) {
- debug!("BUF_WRITE: val len %?", val.len());
- let b_slice = val.as_bytes();
- debug!("BUF_WRITE: b_slice len %?",
- b_slice.len());
- w.write(b_slice)
- }
-
- fn buf_read<R:io::Reader>(r: &R, len: uint) -> ~str {
- let new_bytes = (*r).read_bytes(len);
- debug!("in buf_read.. new_bytes len: %?",
- new_bytes.len());
- str::from_bytes(new_bytes)
- }
-
- fn run_tcp_test_server(server_ip: &str, server_port: uint, resp: ~str,
- cont_ch: SharedChan<()>,
- iotask: &IoTask) -> ~str {
- let (server_po, server_ch) = stream::<~str>();
- let server_ch = SharedChan::new(server_ch);
- let server_ip_addr = ip::v4::parse_addr(server_ip);
- let resp_cell = Cell::new(resp);
- let listen_result = listen(server_ip_addr, server_port, 128,
- iotask,
- // on_establish_cb -- called when listener is set up
- |kill_ch| {
- debug!("establish_cb %?",
- kill_ch);
- cont_ch.send(());
- },
- // risky to run this on the loop, but some users
- // will want the POWER
- |new_conn, kill_ch| {
- let resp_cell2 = Cell::new(resp_cell.take());
- debug!("SERVER: new connection!");
- let (cont_po, cont_ch) = stream();
- let server_ch = server_ch.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- debug!("SERVER: starting worker for new req");
-
- let accept_result = accept(new_conn);
- debug!("SERVER: after accept()");
- if result::is_err(&accept_result) {
- debug!("SERVER: error accept connection");
- let err_data = result::get_err(&accept_result);
- kill_ch.send(Some(err_data));
- debug!(
- "SERVER/WORKER: send on err cont ch");
- cont_ch.send(());
- }
- else {
- debug!("SERVER/WORKER: send on cont ch");
- cont_ch.send(());
- let sock = result::unwrap(accept_result);
- let peer_addr = sock.get_peer_addr();
- debug!("SERVER: successfully accepted \
- connection from %s:%u",
- ip::format_addr(&peer_addr),
- ip::get_port(&peer_addr));
- let received_req_bytes = read(&sock, 0u);
- match received_req_bytes {
- result::Ok(data) => {
- debug!("SERVER: got REQ str::from_bytes..");
- debug!("SERVER: REQ data len: %?",
- data.len());
- server_ch.send(
- str::from_bytes(data));
- debug!("SERVER: before write");
- let s = resp_cell2.take();
- tcp_write_single(&sock, s.as_bytes().to_owned());
- debug!("SERVER: after write.. die");
- kill_ch.send(None);
- }
- result::Err(err_data) => {
- debug!("SERVER: error recvd: %s %s",
- err_data.err_name, err_data.err_msg);
- kill_ch.send(Some(err_data));
- server_ch.send(~"");
- }
- }
- debug!("SERVER: worker spinning down");
- }
- }
- debug!("SERVER: waiting to recv on cont_ch");
- cont_po.recv();
- });
- // err check on listen_result
- if result::is_err(&listen_result) {
- match result::get_err(&listen_result) {
- GenericListenErr(ref name, ref msg) => {
- fail!("SERVER: exited abnormally name %s msg %s", *name, *msg);
- }
- AccessDenied => {
- fail!("SERVER: exited abnormally, got access denied..");
- }
- AddressInUse => {
- fail!("SERVER: exited abnormally, got address in use...");
- }
- }
- }
- let ret_val = server_po.recv();
- debug!("SERVER: exited and got return val: '%s'", ret_val);
- ret_val
- }
-
- fn run_tcp_test_server_fail(server_ip: &str, server_port: uint,
- iotask: &IoTask) -> TcpListenErrData {
- let server_ip_addr = ip::v4::parse_addr(server_ip);
- let listen_result = listen(server_ip_addr, server_port, 128,
- iotask,
- // on_establish_cb -- called when listener is set up
- |kill_ch| {
- debug!("establish_cb %?", kill_ch);
- },
- |new_conn, kill_ch| {
- fail!("SERVER: shouldn't be called.. %? %?", new_conn, kill_ch);
- });
- // err check on listen_result
- if result::is_err(&listen_result) {
- result::get_err(&listen_result)
- }
- else {
- fail!("SERVER: did not fail as expected")
- }
- }
-
- fn run_tcp_test_client(server_ip: &str, server_port: uint, resp: &str,
- iotask: &IoTask) -> result::Result<~str,
- TcpConnectErrData> {
- let server_ip_addr = ip::v4::parse_addr(server_ip);
-
- debug!("CLIENT: starting..");
- let connect_result = connect(server_ip_addr, server_port,
- iotask);
- if result::is_err(&connect_result) {
- debug!("CLIENT: failed to connect");
- let err_data = result::get_err(&connect_result);
- Err(err_data)
- }
- else {
- let sock = result::unwrap(connect_result);
- let resp_bytes = resp.as_bytes().to_owned();
- tcp_write_single(&sock, resp_bytes);
- let read_result = sock.read(0u);
- if read_result.is_err() {
- debug!("CLIENT: failure to read");
- Ok(~"")
- }
- else {
- let ret_val = str::from_bytes(read_result.get());
- debug!("CLIENT: after client_ch recv ret: '%s'",
- ret_val);
- Ok(ret_val)
- }
- }
- }
-
- fn tcp_write_single(sock: &TcpSocket, val: ~[u8]) {
- let mut write_result_future = sock.write_future(val);
- let write_result = write_result_future.get();
- if result::is_err(&write_result) {
- debug!("tcp_write_single: write failed!");
- let err_data = result::get_err(&write_result);
- debug!("tcp_write_single err name: %s msg: %s",
- err_data.err_name, err_data.err_msg);
- // meh. torn on what to do here.
- fail!("tcp_write_single failed");
- }
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Types/fns concerning URLs (see RFC 3986)
-
-#[allow(missing_doc)];
-
-
-use std::cmp::Eq;
-use std::io::{Reader, ReaderUtil};
-use std::io;
-use std::hashmap::HashMap;
-use std::to_bytes;
-use std::uint;
-
-#[deriving(Clone, Eq)]
-struct Url {
- scheme: ~str,
- user: Option<UserInfo>,
- host: ~str,
- port: Option<~str>,
- path: ~str,
- query: Query,
- fragment: Option<~str>
-}
-
-#[deriving(Clone, Eq)]
-struct UserInfo {
- user: ~str,
- pass: Option<~str>
-}
-
-pub type Query = ~[(~str, ~str)];
-
-impl Url {
- pub fn new(scheme: ~str,
- user: Option<UserInfo>,
- host: ~str,
- port: Option<~str>,
- path: ~str,
- query: Query,
- fragment: Option<~str>)
- -> Url {
- Url {
- scheme: scheme,
- user: user,
- host: host,
- port: port,
- path: path,
- query: query,
- fragment: fragment,
- }
- }
-}
-
-impl UserInfo {
- pub fn new(user: ~str, pass: Option<~str>) -> UserInfo {
- UserInfo { user: user, pass: pass }
- }
-}
-
-fn encode_inner(s: &str, full_url: bool) -> ~str {
- do io::with_str_reader(s) |rdr| {
- let mut out = ~"";
-
- while !rdr.eof() {
- let ch = rdr.read_byte() as char;
- match ch {
- // unreserved:
- 'A' .. 'Z' |
- 'a' .. 'z' |
- '0' .. '9' |
- '-' | '.' | '_' | '~' => {
- out.push_char(ch);
- }
- _ => {
- if full_url {
- match ch {
- // gen-delims:
- ':' | '/' | '?' | '#' | '[' | ']' | '@' |
-
- // sub-delims:
- '!' | '$' | '&' | '"' | '(' | ')' | '*' |
- '+' | ',' | ';' | '=' => {
- out.push_char(ch);
- }
-
- _ => out.push_str(fmt!("%%%X", ch as uint))
- }
- } else {
- out.push_str(fmt!("%%%X", ch as uint));
- }
- }
- }
- }
-
- out
- }
-}
-
-/**
- * Encodes a URI by replacing reserved characters with percent encoded
- * character sequences.
- *
- * This function is compliant with RFC 3986.
- */
-pub fn encode(s: &str) -> ~str {
- encode_inner(s, true)
-}
-
-/**
- * Encodes a URI component by replacing reserved characters with percent
- * encoded character sequences.
- *
- * This function is compliant with RFC 3986.
- */
-
-pub fn encode_component(s: &str) -> ~str {
- encode_inner(s, false)
-}
-
-fn decode_inner(s: &str, full_url: bool) -> ~str {
- do io::with_str_reader(s) |rdr| {
- let mut out = ~"";
-
- while !rdr.eof() {
- match rdr.read_char() {
- '%' => {
- let bytes = rdr.read_bytes(2u);
- let ch = uint::parse_bytes(bytes, 16u).get() as char;
-
- if full_url {
- // Only decode some characters:
- match ch {
- // gen-delims:
- ':' | '/' | '?' | '#' | '[' | ']' | '@' |
-
- // sub-delims:
- '!' | '$' | '&' | '"' | '(' | ')' | '*' |
- '+' | ',' | ';' | '=' => {
- out.push_char('%');
- out.push_char(bytes[0u] as char);
- out.push_char(bytes[1u] as char);
- }
-
- ch => out.push_char(ch)
- }
- } else {
- out.push_char(ch);
- }
- }
- ch => out.push_char(ch)
- }
- }
-
- out
- }
-}
-
-/**
- * Decode a string encoded with percent encoding.
- *
- * This will only decode escape sequences generated by encode.
- */
-pub fn decode(s: &str) -> ~str {
- decode_inner(s, true)
-}
-
-/**
- * Decode a string encoded with percent encoding.
- */
-pub fn decode_component(s: &str) -> ~str {
- decode_inner(s, false)
-}
-
-fn encode_plus(s: &str) -> ~str {
- do io::with_str_reader(s) |rdr| {
- let mut out = ~"";
-
- while !rdr.eof() {
- let ch = rdr.read_byte() as char;
- match ch {
- 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => {
- out.push_char(ch);
- }
- ' ' => out.push_char('+'),
- _ => out.push_str(fmt!("%%%X", ch as uint))
- }
- }
-
- out
- }
-}
-
-/**
- * Encode a hashmap to the 'application/x-www-form-urlencoded' media type.
- */
-pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str {
- let mut out = ~"";
- let mut first = true;
-
- for m.iter().advance |(key, values)| {
- let key = encode_plus(*key);
-
- for values.iter().advance |value| {
- if first {
- first = false;
- } else {
- out.push_char('&');
- first = false;
- }
-
- out.push_str(fmt!("%s=%s", key, encode_plus(*value)));
- }
- }
-
- out
-}
-
-/**
- * Decode a string encoded with the 'application/x-www-form-urlencoded' media
- * type into a hashmap.
- */
-pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
- do io::with_bytes_reader(s) |rdr| {
- let mut m = HashMap::new();
- let mut key = ~"";
- let mut value = ~"";
- let mut parsing_key = true;
-
- while !rdr.eof() {
- match rdr.read_char() {
- '&' | ';' => {
- if key != ~"" && value != ~"" {
- let mut values = match m.pop(&key) {
- Some(values) => values,
- None => ~[],
- };
-
- values.push(value);
- m.insert(key, values);
- }
-
- parsing_key = true;
- key = ~"";
- value = ~"";
- }
- '=' => parsing_key = false,
- ch => {
- let ch = match ch {
- '%' => {
- let bytes = rdr.read_bytes(2u);
- uint::parse_bytes(bytes, 16u).get() as char
- }
- '+' => ' ',
- ch => ch
- };
-
- if parsing_key {
- key.push_char(ch)
- } else {
- value.push_char(ch)
- }
- }
- }
- }
-
- if key != ~"" && value != ~"" {
- let mut values = match m.pop(&key) {
- Some(values) => values,
- None => ~[],
- };
-
- values.push(value);
- m.insert(key, values);
- }
-
- m
- }
-}
-
-
-fn split_char_first(s: &str, c: char) -> (~str, ~str) {
- let len = s.len();
- let mut index = len;
- let mut mat = 0;
- do io::with_str_reader(s) |rdr| {
- let mut ch;
- while !rdr.eof() {
- ch = rdr.read_byte() as char;
- if ch == c {
- // found a match, adjust markers
- index = rdr.tell()-1;
- mat = 1;
- break;
- }
- }
- }
- if index+mat == len {
- return (s.slice(0, index).to_owned(), ~"");
- } else {
- return (s.slice(0, index).to_owned(),
- s.slice(index + mat, s.len()).to_owned());
- }
-}
-
-fn userinfo_from_str(uinfo: &str) -> UserInfo {
- let (user, p) = split_char_first(uinfo, ':');
- let pass = if p.is_empty() {
- None
- } else {
- Some(p)
- };
- return UserInfo::new(user, pass);
-}
-
-fn userinfo_to_str(userinfo: &UserInfo) -> ~str {
- match userinfo.pass {
- Some(ref pass) => fmt!("%s:%s@", userinfo.user, *pass),
- None => fmt!("%s@", userinfo.user),
- }
-}
-
-fn query_from_str(rawquery: &str) -> Query {
- let mut query: Query = ~[];
- if !rawquery.is_empty() {
- for rawquery.split_iter('&').advance |p| {
- let (k, v) = split_char_first(p, '=');
- query.push((decode_component(k), decode_component(v)));
- };
- }
- return query;
-}
-
-pub fn query_to_str(query: &Query) -> ~str {
- let mut strvec = ~[];
- for query.iter().advance |kv| {
- match kv {
- &(ref k, ref v) => {
- strvec.push(fmt!("%s=%s",
- encode_component(*k),
- encode_component(*v))
- );
- }
- }
- }
- return strvec.connect("&");
-}
-
-// returns the scheme and the rest of the url, or a parsing error
-pub fn get_scheme(rawurl: &str) -> Result<(~str, ~str), ~str> {
- for rawurl.iter().enumerate().advance |(i,c)| {
- match c {
- 'A' .. 'Z' | 'a' .. 'z' => loop,
- '0' .. '9' | '+' | '-' | '.' => {
- if i == 0 {
- return Err(~"url: Scheme must begin with a letter.");
- }
- loop;
- }
- ':' => {
- if i == 0 {
- return Err(~"url: Scheme cannot be empty.");
- } else {
- return Ok((rawurl.slice(0,i).to_owned(),
- rawurl.slice(i+1,rawurl.len()).to_owned()));
- }
- }
- _ => {
- return Err(~"url: Invalid character in scheme.");
- }
- }
- };
- return Err(~"url: Scheme must be terminated with a colon.");
-}
-
-#[deriving(Clone, Eq)]
-enum Input {
- Digit, // all digits
- Hex, // digits and letters a-f
- Unreserved // all other legal characters
-}
-
-// returns userinfo, host, port, and unparsed part, or an error
-fn get_authority(rawurl: &str) ->
- Result<(Option<UserInfo>, ~str, Option<~str>, ~str), ~str> {
- if !rawurl.starts_with("//") {
- // there is no authority.
- return Ok((None, ~"", None, rawurl.to_str()));
- }
-
- enum State {
- Start, // starting state
- PassHostPort, // could be in user or port
- Ip6Port, // either in ipv6 host or port
- Ip6Host, // are in an ipv6 host
- InHost, // are in a host - may be ipv6, but don't know yet
- InPort // are in port
- }
-
- let len = rawurl.len();
- let mut st = Start;
- let mut in = Digit; // most restricted, start here.
-
- let mut userinfo = None;
- let mut host = ~"";
- let mut port = None;
-
- let mut colon_count = 0;
- let mut pos = 0;
- let mut begin = 2;
- let mut end = len;
-
- for rawurl.iter().enumerate().advance |(i,c)| {
- if i < 2 { loop; } // ignore the leading //
-
- // deal with input class first
- match c {
- '0' .. '9' => (),
- 'A' .. 'F' | 'a' .. 'f' => {
- if in == Digit {
- in = Hex;
- }
- }
- 'G' .. 'Z' | 'g' .. 'z' | '-' | '.' | '_' | '~' | '%' |
- '&' |'\'' | '(' | ')' | '+' | '!' | '*' | ',' | ';' | '=' => {
- in = Unreserved;
- }
- ':' | '@' | '?' | '#' | '/' => {
- // separators, don't change anything
- }
- _ => {
- return Err(~"Illegal character in authority");
- }
- }
-
- // now process states
- match c {
- ':' => {
- colon_count += 1;
- match st {
- Start => {
- pos = i;
- st = PassHostPort;
- }
- PassHostPort => {
- // multiple colons means ipv6 address.
- if in == Unreserved {
- return Err(
- ~"Illegal characters in IPv6 address.");
- }
- st = Ip6Host;
- }
- InHost => {
- pos = i;
- // can't be sure whether this is an ipv6 address or a port
- if in == Unreserved {
- return Err(~"Illegal characters in authority.");
- }
- st = Ip6Port;
- }
- Ip6Port => {
- if in == Unreserved {
- return Err(~"Illegal characters in authority.");
- }
- st = Ip6Host;
- }
- Ip6Host => {
- if colon_count > 7 {
- host = rawurl.slice(begin, i).to_owned();
- pos = i;
- st = InPort;
- }
- }
- _ => {
- return Err(~"Invalid ':' in authority.");
- }
- }
- in = Digit; // reset input class
- }
-
- '@' => {
- in = Digit; // reset input class
- colon_count = 0; // reset count
- match st {
- Start => {
- let user = rawurl.slice(begin, i).to_owned();
- userinfo = Some(UserInfo::new(user, None));
- st = InHost;
- }
- PassHostPort => {
- let user = rawurl.slice(begin, pos).to_owned();
- let pass = rawurl.slice(pos+1, i).to_owned();
- userinfo = Some(UserInfo::new(user, Some(pass)));
- st = InHost;
- }
- _ => {
- return Err(~"Invalid '@' in authority.");
- }
- }
- begin = i+1;
- }
-
- '?' | '#' | '/' => {
- end = i;
- break;
- }
- _ => ()
- }
- end = i;
- }
-
- let end = end; // make end immutable so it can be captured
-
- let host_is_end_plus_one: &fn() -> bool = || {
- let xs = ['?', '#', '/'];
- end+1 == len
- && !xs.iter().any(|x| *x == (rawurl[end] as char))
- };
-
- // finish up
- match st {
- Start => {
- if host_is_end_plus_one() {
- host = rawurl.slice(begin, end+1).to_owned();
- } else {
- host = rawurl.slice(begin, end).to_owned();
- }
- }
- PassHostPort | Ip6Port => {
- if in != Digit {
- return Err(~"Non-digit characters in port.");
- }
- host = rawurl.slice(begin, pos).to_owned();
- port = Some(rawurl.slice(pos+1, end).to_owned());
- }
- Ip6Host | InHost => {
- host = rawurl.slice(begin, end).to_owned();
- }
- InPort => {
- if in != Digit {
- return Err(~"Non-digit characters in port.");
- }
- port = Some(rawurl.slice(pos+1, end).to_owned());
- }
- }
-
- let rest = if host_is_end_plus_one() { ~"" }
- else { rawurl.slice(end, len).to_owned() };
- return Ok((userinfo, host, port, rest));
-}
-
-
-// returns the path and unparsed part of url, or an error
-fn get_path(rawurl: &str, authority: bool) ->
- Result<(~str, ~str), ~str> {
- let len = rawurl.len();
- let mut end = len;
- for rawurl.iter().enumerate().advance |(i,c)| {
- match c {
- 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '&' |'\'' | '(' | ')' | '.'
- | '@' | ':' | '%' | '/' | '+' | '!' | '*' | ',' | ';' | '='
- | '_' | '-' => {
- loop;
- }
- '?' | '#' => {
- end = i;
- break;
- }
- _ => return Err(~"Invalid character in path.")
- }
- }
-
- if authority {
- if end != 0 && !rawurl.starts_with("/") {
- return Err(~"Non-empty path must begin with\
- '/' in presence of authority.");
- }
- }
-
- return Ok((decode_component(rawurl.slice(0, end)),
- rawurl.slice(end, len).to_owned()));
-}
-
-// returns the parsed query and the fragment, if present
-fn get_query_fragment(rawurl: &str) ->
- Result<(Query, Option<~str>), ~str> {
- if !rawurl.starts_with("?") {
- if rawurl.starts_with("#") {
- let f = decode_component(rawurl.slice(
- 1,
- rawurl.len()));
- return Ok((~[], Some(f)));
- } else {
- return Ok((~[], None));
- }
- }
- let (q, r) = split_char_first(rawurl.slice(1, rawurl.len()), '#');
- let f = if r.len() != 0 {
- Some(decode_component(r)) } else { None };
- return Ok((query_from_str(q), f));
-}
-
-/**
- * Parse a `str` to a `url`
- *
- * # Arguments
- *
- * `rawurl` - a string representing a full url, including scheme.
- *
- * # Returns
- *
- * a `url` that contains the parsed representation of the url.
- *
- */
-
-pub fn from_str(rawurl: &str) -> Result<Url, ~str> {
- // scheme
- let (scheme, rest) = match get_scheme(rawurl) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- // authority
- let (userinfo, host, port, rest) = match get_authority(rest) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- // path
- let has_authority = if host == ~"" { false } else { true };
- let (path, rest) = match get_path(rest, has_authority) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- // query and fragment
- let (query, fragment) = match get_query_fragment(rest) {
- Ok(val) => val,
- Err(e) => return Err(e),
- };
-
- Ok(Url::new(scheme, userinfo, host, port, path, query, fragment))
-}
-
-impl FromStr for Url {
- fn from_str(s: &str) -> Option<Url> {
- match from_str(s) {
- Ok(url) => Some(url),
- Err(_) => None
- }
- }
-}
-
-/**
- * Format a `url` as a string
- *
- * # Arguments
- *
- * `url` - a url.
- *
- * # Returns
- *
- * a `str` that contains the formatted url. Note that this will usually
- * be an inverse of `from_str` but might strip out unneeded separators.
- * for example, "http://somehost.com?", when parsed and formatted, will
- * result in just "http://somehost.com".
- *
- */
-pub fn to_str(url: &Url) -> ~str {
- let user = match url.user {
- Some(ref user) => userinfo_to_str(user),
- None => ~"",
- };
-
- let authority = if url.host.is_empty() {
- ~""
- } else {
- fmt!("//%s%s", user, url.host)
- };
-
- let query = if url.query.is_empty() {
- ~""
- } else {
- fmt!("?%s", query_to_str(&url.query))
- };
-
- let fragment = match url.fragment {
- Some(ref fragment) => fmt!("#%s", encode_component(*fragment)),
- None => ~"",
- };
-
- fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment)
-}
-
-impl ToStr for Url {
- pub fn to_str(&self) -> ~str {
- to_str(self)
- }
-}
-
-impl IterBytes for Url {
- fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
- self.to_str().iter_bytes(lsb0, f)
- }
-}
-
-// Put a few tests outside of the 'test' module so they can test the internal
-// functions and those functions don't need 'pub'
-
-#[test]
-fn test_split_char_first() {
- let (u,v) = split_char_first("hello, sweet world", ',');
- assert_eq!(u, ~"hello");
- assert_eq!(v, ~" sweet world");
-
- let (u,v) = split_char_first("hello sweet world", ',');
- assert_eq!(u, ~"hello sweet world");
- assert_eq!(v, ~"");
-}
-
-#[test]
-fn test_get_authority() {
- let (u, h, p, r) = get_authority(
- "//user:pass@rust-lang.org/something").unwrap();
- assert_eq!(u, Some(UserInfo::new(~"user", Some(~"pass"))));
- assert_eq!(h, ~"rust-lang.org");
- assert!(p.is_none());
- assert_eq!(r, ~"/something");
-
- let (u, h, p, r) = get_authority(
- "//rust-lang.org:8000?something").unwrap();
- assert!(u.is_none());
- assert_eq!(h, ~"rust-lang.org");
- assert_eq!(p, Some(~"8000"));
- assert_eq!(r, ~"?something");
-
- let (u, h, p, r) = get_authority(
- "//rust-lang.org#blah").unwrap();
- assert!(u.is_none());
- assert_eq!(h, ~"rust-lang.org");
- assert!(p.is_none());
- assert_eq!(r, ~"#blah");
-
- // ipv6 tests
- let (_, h, _, _) = get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334#blah").unwrap();
- assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
-
- let (_, h, p, _) = get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah").unwrap();
- assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
- assert_eq!(p, Some(~"8000"));
-
- let (u, h, p, _) = get_authority(
- "//us:p@2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah"
- ).unwrap();
- assert_eq!(u, Some(UserInfo::new(~"us", Some(~"p"))));
- assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
- assert_eq!(p, Some(~"8000"));
-
- // invalid authorities;
- assert!(get_authority("//user:pass@rust-lang:something").is_err());
- assert!(get_authority("//user@rust-lang:something:/path").is_err());
- assert!(get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:800a").is_err());
- assert!(get_authority(
- "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000:00").is_err());
-
- // these parse as empty, because they don't start with '//'
- let (_, h, _, _) = get_authority("user:pass@rust-lang").unwrap();
- assert_eq!(h, ~"");
- let (_, h, _, _) = get_authority("rust-lang.org").unwrap();
- assert_eq!(h, ~"");
-}
-
-#[test]
-fn test_get_path() {
- let (p, r) = get_path("/something+%20orother", true).unwrap();
- assert_eq!(p, ~"/something+ orother");
- assert_eq!(r, ~"");
- let (p, r) = get_path("test@email.com#fragment", false).unwrap();
- assert_eq!(p, ~"test@email.com");
- assert_eq!(r, ~"#fragment");
- let (p, r) = get_path("/gen/:addr=?q=v", false).unwrap();
- assert_eq!(p, ~"/gen/:addr=");
- assert_eq!(r, ~"?q=v");
-
- //failure cases
- assert!(get_path("something?q", true).is_err());
-}
-
-#[cfg(test)]
-mod tests {
-
- use net::url::*;
-
- use std::hashmap::HashMap;
-
- #[test]
- fn test_url_parse() {
- let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
-
- let up = from_str(url);
- let u = up.unwrap();
- assert!(u.scheme == ~"http");
- let userinfo = u.user.get_ref();
- assert!(userinfo.user == ~"user");
- assert!(userinfo.pass.get_ref() == &~"pass");
- assert!(u.host == ~"rust-lang.org");
- assert!(u.path == ~"/doc");
- assert!(u.query == ~[(~"s", ~"v")]);
- assert!(u.fragment.get_ref() == &~"something");
- }
-
- #[test]
- fn test_url_parse_host_slash() {
- let urlstr = ~"http://0.42.42.42/";
- let url = from_str(urlstr).unwrap();
- assert!(url.host == ~"0.42.42.42");
- assert!(url.path == ~"/");
- }
-
- #[test]
- fn test_url_with_underscores() {
- let urlstr = ~"http://dotcom.com/file_name.html";
- let url = from_str(urlstr).unwrap();
- assert!(url.path == ~"/file_name.html");
- }
-
- #[test]
- fn test_url_with_dashes() {
- let urlstr = ~"http://dotcom.com/file-name.html";
- let url = from_str(urlstr).unwrap();
- assert!(url.path == ~"/file-name.html");
- }
-
- #[test]
- fn test_no_scheme() {
- assert!(get_scheme("noschemehere.html").is_err());
- }
-
- #[test]
- fn test_invalid_scheme_errors() {
- assert!(from_str("99://something").is_err());
- assert!(from_str("://something").is_err());
- }
-
- #[test]
- fn test_full_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_userless_url_parse_and_format() {
- let url = ~"http://rust-lang.org/doc?s=v#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_queryless_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_empty_query_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc?#something";
- let should_be = ~"http://user:pass@rust-lang.org/doc#something";
- assert_eq!(from_str(url).unwrap().to_str(), should_be);
- }
-
- #[test]
- fn test_fragmentless_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org/doc?q=v";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_minimal_url_parse_and_format() {
- let url = ~"http://rust-lang.org/doc";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_scheme_host_only_url_parse_and_format() {
- let url = ~"http://rust-lang.org";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_pathless_url_parse_and_format() {
- let url = ~"http://user:pass@rust-lang.org?q=v#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_scheme_host_fragment_only_url_parse_and_format() {
- let url = ~"http://rust-lang.org#something";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_url_component_encoding() {
- let url = ~"http://rust-lang.org/doc%20uments?ba%25d%20=%23%26%2B";
- let u = from_str(url).unwrap();
- assert!(u.path == ~"/doc uments");
- assert!(u.query == ~[(~"ba%d ", ~"#&+")]);
- }
-
- #[test]
- fn test_url_without_authority() {
- let url = ~"mailto:test@email.com";
- assert_eq!(from_str(url).unwrap().to_str(), url);
- }
-
- #[test]
- fn test_encode() {
- assert_eq!(encode(""), ~"");
- assert_eq!(encode("http://example.com"), ~"http://example.com");
- assert_eq!(encode("foo bar% baz"), ~"foo%20bar%25%20baz");
- assert_eq!(encode(" "), ~"%20");
- assert_eq!(encode("!"), ~"!");
- assert_eq!(encode("\""), ~"\"");
- assert_eq!(encode("#"), ~"#");
- assert_eq!(encode("$"), ~"$");
- assert_eq!(encode("%"), ~"%25");
- assert_eq!(encode("&"), ~"&");
- assert_eq!(encode("'"), ~"%27");
- assert_eq!(encode("("), ~"(");
- assert_eq!(encode(")"), ~")");
- assert_eq!(encode("*"), ~"*");
- assert_eq!(encode("+"), ~"+");
- assert_eq!(encode(","), ~",");
- assert_eq!(encode("/"), ~"/");
- assert_eq!(encode(":"), ~":");
- assert_eq!(encode(";"), ~";");
- assert_eq!(encode("="), ~"=");
- assert_eq!(encode("?"), ~"?");
- assert_eq!(encode("@"), ~"@");
- assert_eq!(encode("["), ~"[");
- assert_eq!(encode("]"), ~"]");
- }
-
- #[test]
- fn test_encode_component() {
- assert_eq!(encode_component(""), ~"");
- assert!(encode_component("http://example.com") ==
- ~"http%3A%2F%2Fexample.com");
- assert!(encode_component("foo bar% baz") ==
- ~"foo%20bar%25%20baz");
- assert_eq!(encode_component(" "), ~"%20");
- assert_eq!(encode_component("!"), ~"%21");
- assert_eq!(encode_component("#"), ~"%23");
- assert_eq!(encode_component("$"), ~"%24");
- assert_eq!(encode_component("%"), ~"%25");
- assert_eq!(encode_component("&"), ~"%26");
- assert_eq!(encode_component("'"), ~"%27");
- assert_eq!(encode_component("("), ~"%28");
- assert_eq!(encode_component(")"), ~"%29");
- assert_eq!(encode_component("*"), ~"%2A");
- assert_eq!(encode_component("+"), ~"%2B");
- assert_eq!(encode_component(","), ~"%2C");
- assert_eq!(encode_component("/"), ~"%2F");
- assert_eq!(encode_component(":"), ~"%3A");
- assert_eq!(encode_component(";"), ~"%3B");
- assert_eq!(encode_component("="), ~"%3D");
- assert_eq!(encode_component("?"), ~"%3F");
- assert_eq!(encode_component("@"), ~"%40");
- assert_eq!(encode_component("["), ~"%5B");
- assert_eq!(encode_component("]"), ~"%5D");
- }
-
- #[test]
- fn test_decode() {
- assert_eq!(decode(""), ~"");
- assert_eq!(decode("abc/def 123"), ~"abc/def 123");
- assert_eq!(decode("abc%2Fdef%20123"), ~"abc%2Fdef 123");
- assert_eq!(decode("%20"), ~" ");
- assert_eq!(decode("%21"), ~"%21");
- assert_eq!(decode("%22"), ~"%22");
- assert_eq!(decode("%23"), ~"%23");
- assert_eq!(decode("%24"), ~"%24");
- assert_eq!(decode("%25"), ~"%");
- assert_eq!(decode("%26"), ~"%26");
- assert_eq!(decode("%27"), ~"'");
- assert_eq!(decode("%28"), ~"%28");
- assert_eq!(decode("%29"), ~"%29");
- assert_eq!(decode("%2A"), ~"%2A");
- assert_eq!(decode("%2B"), ~"%2B");
- assert_eq!(decode("%2C"), ~"%2C");
- assert_eq!(decode("%2F"), ~"%2F");
- assert_eq!(decode("%3A"), ~"%3A");
- assert_eq!(decode("%3B"), ~"%3B");
- assert_eq!(decode("%3D"), ~"%3D");
- assert_eq!(decode("%3F"), ~"%3F");
- assert_eq!(decode("%40"), ~"%40");
- assert_eq!(decode("%5B"), ~"%5B");
- assert_eq!(decode("%5D"), ~"%5D");
- }
-
- #[test]
- fn test_decode_component() {
- assert_eq!(decode_component(""), ~"");
- assert_eq!(decode_component("abc/def 123"), ~"abc/def 123");
- assert_eq!(decode_component("abc%2Fdef%20123"), ~"abc/def 123");
- assert_eq!(decode_component("%20"), ~" ");
- assert_eq!(decode_component("%21"), ~"!");
- assert_eq!(decode_component("%22"), ~"\"");
- assert_eq!(decode_component("%23"), ~"#");
- assert_eq!(decode_component("%24"), ~"$");
- assert_eq!(decode_component("%25"), ~"%");
- assert_eq!(decode_component("%26"), ~"&");
- assert_eq!(decode_component("%27"), ~"'");
- assert_eq!(decode_component("%28"), ~"(");
- assert_eq!(decode_component("%29"), ~")");
- assert_eq!(decode_component("%2A"), ~"*");
- assert_eq!(decode_component("%2B"), ~"+");
- assert_eq!(decode_component("%2C"), ~",");
- assert_eq!(decode_component("%2F"), ~"/");
- assert_eq!(decode_component("%3A"), ~":");
- assert_eq!(decode_component("%3B"), ~";");
- assert_eq!(decode_component("%3D"), ~"=");
- assert_eq!(decode_component("%3F"), ~"?");
- assert_eq!(decode_component("%40"), ~"@");
- assert_eq!(decode_component("%5B"), ~"[");
- assert_eq!(decode_component("%5D"), ~"]");
- }
-
- #[test]
- fn test_encode_form_urlencoded() {
- let mut m = HashMap::new();
- assert_eq!(encode_form_urlencoded(&m), ~"");
-
- m.insert(~"", ~[]);
- m.insert(~"foo", ~[]);
- assert_eq!(encode_form_urlencoded(&m), ~"");
-
- let mut m = HashMap::new();
- m.insert(~"foo", ~[~"bar", ~"123"]);
- assert_eq!(encode_form_urlencoded(&m), ~"foo=bar&foo=123");
-
- let mut m = HashMap::new();
- m.insert(~"foo bar", ~[~"abc", ~"12 = 34"]);
- assert!(encode_form_urlencoded(&m) ==
- ~"foo+bar=abc&foo+bar=12+%3D+34");
- }
-
- #[test]
- fn test_decode_form_urlencoded() {
- // FIXME #4449: Commented out because this causes an ICE, but only
- // on FreeBSD
- /*
- assert_eq!(decode_form_urlencoded([]).len(), 0);
-
- let s = "a=1&foo+bar=abc&foo+bar=12+%3D+34".as_bytes();
- let form = decode_form_urlencoded(s);
- assert_eq!(form.len(), 2);
- assert_eq!(form.get_ref(&~"a"), &~[~"1"]);
- assert_eq!(form.get_ref(&~"foo bar"), &~[~"abc", ~"12 = 34"]);
- */
- }
-}
}
/// Mutable reference counted pointer type
-#[non_owned]
#[no_send]
-#[mutable] // XXX remove after snap
#[no_freeze]
#[unsafe_no_drop_flag]
pub struct RcMut<T> {
pub type CompletionCb = @fn(~str, @fn(~str));
-#[cfg(not(stage0))]
static complete_key: local_data::Key<@CompletionCb> = &local_data::Key;
-#[cfg(stage0)]
-fn complete_key(_: @CompletionCb) {}
/// Bind to the main completion callback
pub unsafe fn complete(cb: CompletionCb) {
fn recursive_mkdir_rel() {
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os;
+ use std::unstable::change_dir_locked;
let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel").
expect("recursive_mkdir_rel");
- assert!(do os::change_dir_locked(&root) {
+ assert!(do change_dir_locked(&root) {
let path = Path("frob");
debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(),
os::getcwd().to_str(),
fn recursive_mkdir_rel_2() {
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os;
+ use std::unstable::change_dir_locked;
let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2").
expect("recursive_mkdir_rel_2");
- assert!(do os::change_dir_locked(&root) {
+ assert!(do change_dir_locked(&root) {
let path = Path("./frob/baz");
debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(),
os::getcwd().to_str(), os::path_exists(&path));
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Utilities that leverage libuv's `uv_timer_*` API
-
-
-use uv;
-use uv::iotask;
-use uv::iotask::IoTask;
-
-use std::cast::transmute;
-use std::cast;
-use std::comm::{stream, Chan, SharedChan, Port, select2i};
-use std::either;
-use std::libc::c_void;
-use std::libc;
-
-/**
- * Wait for timeout period then send provided value over a channel
- *
- * This call returns immediately. Useful as the building block for a number
- * of higher-level timer functions.
- *
- * Is not guaranteed to wait for exactly the specified time, but will wait
- * for *at least* that period of time.
- *
- * # Arguments
- *
- * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on
- * * msecs - a timeout period, in milliseconds, to wait
- * * ch - a channel of type T to send a `val` on
- * * val - a value of type T to send over the provided `ch`
- */
-pub fn delayed_send<T:Send>(iotask: &IoTask,
- msecs: uint,
- ch: &Chan<T>,
- val: T) {
- let (timer_done_po, timer_done_ch) = stream::<()>();
- let timer_done_ch = SharedChan::new(timer_done_ch);
- let timer = uv::ll::timer_t();
- let timer_ptr: *uv::ll::uv_timer_t = &timer;
- do iotask::interact(iotask) |loop_ptr| {
- unsafe {
- let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
- if (init_result == 0i32) {
- let start_result = uv::ll::timer_start(
- timer_ptr, delayed_send_cb, msecs, 0u);
- if (start_result == 0i32) {
- // Note: putting the channel into a ~
- // to cast to *c_void
- let timer_done_ch_clone = ~timer_done_ch.clone();
- let timer_done_ch_ptr = transmute::<
- ~SharedChan<()>, *c_void>(
- timer_done_ch_clone);
- uv::ll::set_data_for_uv_handle(
- timer_ptr,
- timer_done_ch_ptr);
- } else {
- let error_msg = uv::ll::get_last_err_info(
- loop_ptr);
- fail!("timer::delayed_send() start failed: %s", error_msg);
- }
- } else {
- let error_msg = uv::ll::get_last_err_info(loop_ptr);
- fail!("timer::delayed_send() init failed: %s", error_msg);
- }
- }
- };
- // delayed_send_cb has been processed by libuv
- timer_done_po.recv();
- // notify the caller immediately
- ch.send(val);
- // uv_close for this timer has been processed
- timer_done_po.recv();
-}
-
-/**
- * Blocks the current task for (at least) the specified time period.
- *
- * Is not guaranteed to sleep for exactly the specified time, but will sleep
- * for *at least* that period of time.
- *
- * # Arguments
- *
- * * `iotask` - a `uv::iotask` that the tcp request will run on
- * * msecs - an amount of time, in milliseconds, for the current task to block
- */
-pub fn sleep(iotask: &IoTask, msecs: uint) {
- let (exit_po, exit_ch) = stream::<()>();
- delayed_send(iotask, msecs, &exit_ch, ());
- exit_po.recv();
-}
-
-/**
- * Receive on a port for (up to) a specified time, then return an `Option<T>`
- *
- * This call will block to receive on the provided port for up to the
- * specified timeout. Depending on whether the provided port receives in that
- * time period, `recv_timeout` will return an `Option<T>` representing the
- * result.
- *
- * # Arguments
- *
- * * `iotask' - `uv::iotask` that the tcp request will run on
- * * msecs - an mount of time, in milliseconds, to wait to receive
- * * wait_port - a `std::comm::port<T>` to receive on
- *
- * # Returns
- *
- * An `Option<T>` representing the outcome of the call. If the call `recv`'d
- * on the provided port in the allotted timeout period, then the result will
- * be a `Some(T)`. If not, then `None` will be returned.
- */
-pub fn recv_timeout<T:Send>(iotask: &IoTask, msecs: uint, wait_po: &Port<T>)
- -> Option<T> {
- let (timeout_po, timeout_ch) = stream::<()>();
- let mut timeout_po = timeout_po;
- delayed_send(iotask, msecs, &timeout_ch, ());
-
- // XXX: Workaround due to ports and channels not being &mut. They should
- // be.
- unsafe {
- let wait_po = cast::transmute_mut(wait_po);
-
- either::either(
- |_| {
- None
- }, |_| {
- Some(wait_po.recv())
- }, &select2i(&mut timeout_po, wait_po)
- )
- }
-}
-
-// INTERNAL API
-extern fn delayed_send_cb(handle: *uv::ll::uv_timer_t, status: libc::c_int) {
- unsafe {
- debug!(
- "delayed_send_cb handle %? status %?", handle, status);
- // Faking a borrowed pointer to our ~SharedChan
- let timer_done_ch_ptr: &*c_void = &uv::ll::get_data_for_uv_handle(
- handle);
- let timer_done_ch_ptr = transmute::<&*c_void, &~SharedChan<()>>(
- timer_done_ch_ptr);
- let stop_result = uv::ll::timer_stop(handle);
- if (stop_result == 0i32) {
- timer_done_ch_ptr.send(());
- uv::ll::close(handle, delayed_send_close_cb);
- } else {
- let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
- let error_msg = uv::ll::get_last_err_info(loop_ptr);
- fail!("timer::sleep() init failed: %s", error_msg);
- }
- }
-}
-
-extern fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) {
- unsafe {
- debug!("delayed_send_close_cb handle %?", handle);
- let timer_done_ch_ptr = uv::ll::get_data_for_uv_handle(handle);
- let timer_done_ch = transmute::<*c_void, ~SharedChan<()>>(
- timer_done_ch_ptr);
- timer_done_ch.send(());
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use timer::*;
- use uv;
-
- use std::cell::Cell;
- use std::pipes::{stream, SharedChan};
- use std::rand::RngUtil;
- use std::rand;
- use std::task;
-
- #[test]
- fn test_gl_timer_simple_sleep_test() {
- let hl_loop = &uv::global_loop::get();
- sleep(hl_loop, 1u);
- }
-
- #[test]
- fn test_gl_timer_sleep_stress1() {
- let hl_loop = &uv::global_loop::get();
- for 50u.times {
- sleep(hl_loop, 1u);
- }
- }
-
- #[test]
- fn test_gl_timer_sleep_stress2() {
- let (po, ch) = stream();
- let ch = SharedChan::new(ch);
- let hl_loop = &uv::global_loop::get();
-
- let repeat = 20u;
- let spec = {
-
- ~[(1u, 20u),
- (10u, 10u),
- (20u, 2u)]
-
- };
-
- for repeat.times {
- let ch = ch.clone();
- for spec.iter().advance |spec| {
- let (times, maxms) = *spec;
- let ch = ch.clone();
- let hl_loop_clone = hl_loop.clone();
- do task::spawn {
- use std::rand::*;
- let mut rng = rng();
- for times.times {
- sleep(&hl_loop_clone, rng.next() as uint % maxms);
- }
- ch.send(());
- }
- }
- }
-
- for (repeat * spec.len()).times {
- po.recv()
- }
- }
-
- // Because valgrind serializes multithreaded programs it can
- // make timing-sensitive tests fail in wierd ways. In these
- // next test we run them many times and expect them to pass
- // the majority of tries.
-
- #[test]
- #[cfg(ignore)]
- fn test_gl_timer_recv_timeout_before_time_passes() {
- let times = 100;
- let mut successes = 0;
- let mut failures = 0;
- let hl_loop = uv::global_loop::get();
-
- for (times as uint).times {
- task::yield();
-
- let expected = rand::rng().gen_str(16u);
- let (test_po, test_ch) = stream::<~str>();
-
- do task::spawn() {
- delayed_send(hl_loop, 1u, &test_ch, expected);
- };
-
- match recv_timeout(hl_loop, 10u, &test_po) {
- Some(val) => {
- assert_eq!(val, expected);
- successes += 1;
- }
- _ => failures += 1
- };
- }
-
- assert!(successes > times / 2);
- }
-
- #[test]
- fn test_gl_timer_recv_timeout_after_time_passes() {
- let times = 100;
- let mut successes = 0;
- let mut failures = 0;
- let hl_loop = uv::global_loop::get();
-
- for (times as uint).times {
- let mut rng = rand::rng();
- let expected = Cell::new(rng.gen_str(16u));
- let (test_po, test_ch) = stream::<~str>();
- let hl_loop_clone = hl_loop.clone();
- do task::spawn() {
- delayed_send(&hl_loop_clone, 50u, &test_ch, expected.take());
- };
-
- match recv_timeout(&hl_loop, 1u, &test_po) {
- None => successes += 1,
- _ => failures += 1
- };
- }
-
- assert!(successes > times / 2);
- }
-}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Types/fns concerning URLs (see RFC 3986)
+
+#[allow(missing_doc)];
+
+
+use std::cmp::Eq;
+use std::io::{Reader, ReaderUtil};
+use std::io;
+use std::hashmap::HashMap;
+use std::to_bytes;
+use std::uint;
+
+#[deriving(Clone, Eq)]
+struct Url {
+ scheme: ~str,
+ user: Option<UserInfo>,
+ host: ~str,
+ port: Option<~str>,
+ path: ~str,
+ query: Query,
+ fragment: Option<~str>
+}
+
+#[deriving(Clone, Eq)]
+struct UserInfo {
+ user: ~str,
+ pass: Option<~str>
+}
+
+pub type Query = ~[(~str, ~str)];
+
+impl Url {
+ pub fn new(scheme: ~str,
+ user: Option<UserInfo>,
+ host: ~str,
+ port: Option<~str>,
+ path: ~str,
+ query: Query,
+ fragment: Option<~str>)
+ -> Url {
+ Url {
+ scheme: scheme,
+ user: user,
+ host: host,
+ port: port,
+ path: path,
+ query: query,
+ fragment: fragment,
+ }
+ }
+}
+
+impl UserInfo {
+ pub fn new(user: ~str, pass: Option<~str>) -> UserInfo {
+ UserInfo { user: user, pass: pass }
+ }
+}
+
+fn encode_inner(s: &str, full_url: bool) -> ~str {
+ do io::with_str_reader(s) |rdr| {
+ let mut out = ~"";
+
+ while !rdr.eof() {
+ let ch = rdr.read_byte() as char;
+ match ch {
+ // unreserved:
+ 'A' .. 'Z' |
+ 'a' .. 'z' |
+ '0' .. '9' |
+ '-' | '.' | '_' | '~' => {
+ out.push_char(ch);
+ }
+ _ => {
+ if full_url {
+ match ch {
+ // gen-delims:
+ ':' | '/' | '?' | '#' | '[' | ']' | '@' |
+
+ // sub-delims:
+ '!' | '$' | '&' | '"' | '(' | ')' | '*' |
+ '+' | ',' | ';' | '=' => {
+ out.push_char(ch);
+ }
+
+ _ => out.push_str(fmt!("%%%X", ch as uint))
+ }
+ } else {
+ out.push_str(fmt!("%%%X", ch as uint));
+ }
+ }
+ }
+ }
+
+ out
+ }
+}
+
+/**
+ * Encodes a URI by replacing reserved characters with percent encoded
+ * character sequences.
+ *
+ * This function is compliant with RFC 3986.
+ */
+pub fn encode(s: &str) -> ~str {
+ encode_inner(s, true)
+}
+
+/**
+ * Encodes a URI component by replacing reserved characters with percent
+ * encoded character sequences.
+ *
+ * This function is compliant with RFC 3986.
+ */
+
+pub fn encode_component(s: &str) -> ~str {
+ encode_inner(s, false)
+}
+
+fn decode_inner(s: &str, full_url: bool) -> ~str {
+ do io::with_str_reader(s) |rdr| {
+ let mut out = ~"";
+
+ while !rdr.eof() {
+ match rdr.read_char() {
+ '%' => {
+ let bytes = rdr.read_bytes(2u);
+ let ch = uint::parse_bytes(bytes, 16u).get() as char;
+
+ if full_url {
+ // Only decode some characters:
+ match ch {
+ // gen-delims:
+ ':' | '/' | '?' | '#' | '[' | ']' | '@' |
+
+ // sub-delims:
+ '!' | '$' | '&' | '"' | '(' | ')' | '*' |
+ '+' | ',' | ';' | '=' => {
+ out.push_char('%');
+ out.push_char(bytes[0u] as char);
+ out.push_char(bytes[1u] as char);
+ }
+
+ ch => out.push_char(ch)
+ }
+ } else {
+ out.push_char(ch);
+ }
+ }
+ ch => out.push_char(ch)
+ }
+ }
+
+ out
+ }
+}
+
+/**
+ * Decode a string encoded with percent encoding.
+ *
+ * This will only decode escape sequences generated by encode.
+ */
+pub fn decode(s: &str) -> ~str {
+ decode_inner(s, true)
+}
+
+/**
+ * Decode a string encoded with percent encoding.
+ */
+pub fn decode_component(s: &str) -> ~str {
+ decode_inner(s, false)
+}
+
+fn encode_plus(s: &str) -> ~str {
+ do io::with_str_reader(s) |rdr| {
+ let mut out = ~"";
+
+ while !rdr.eof() {
+ let ch = rdr.read_byte() as char;
+ match ch {
+ 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => {
+ out.push_char(ch);
+ }
+ ' ' => out.push_char('+'),
+ _ => out.push_str(fmt!("%%%X", ch as uint))
+ }
+ }
+
+ out
+ }
+}
+
+/**
+ * Encode a hashmap to the 'application/x-www-form-urlencoded' media type.
+ */
+pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str {
+ let mut out = ~"";
+ let mut first = true;
+
+ for m.iter().advance |(key, values)| {
+ let key = encode_plus(*key);
+
+ for values.iter().advance |value| {
+ if first {
+ first = false;
+ } else {
+ out.push_char('&');
+ first = false;
+ }
+
+ out.push_str(fmt!("%s=%s", key, encode_plus(*value)));
+ }
+ }
+
+ out
+}
+
+/**
+ * Decode a string encoded with the 'application/x-www-form-urlencoded' media
+ * type into a hashmap.
+ */
+pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
+ do io::with_bytes_reader(s) |rdr| {
+ let mut m = HashMap::new();
+ let mut key = ~"";
+ let mut value = ~"";
+ let mut parsing_key = true;
+
+ while !rdr.eof() {
+ match rdr.read_char() {
+ '&' | ';' => {
+ if key != ~"" && value != ~"" {
+ let mut values = match m.pop(&key) {
+ Some(values) => values,
+ None => ~[],
+ };
+
+ values.push(value);
+ m.insert(key, values);
+ }
+
+ parsing_key = true;
+ key = ~"";
+ value = ~"";
+ }
+ '=' => parsing_key = false,
+ ch => {
+ let ch = match ch {
+ '%' => {
+ let bytes = rdr.read_bytes(2u);
+ uint::parse_bytes(bytes, 16u).get() as char
+ }
+ '+' => ' ',
+ ch => ch
+ };
+
+ if parsing_key {
+ key.push_char(ch)
+ } else {
+ value.push_char(ch)
+ }
+ }
+ }
+ }
+
+ if key != ~"" && value != ~"" {
+ let mut values = match m.pop(&key) {
+ Some(values) => values,
+ None => ~[],
+ };
+
+ values.push(value);
+ m.insert(key, values);
+ }
+
+ m
+ }
+}
+
+
+fn split_char_first(s: &str, c: char) -> (~str, ~str) {
+ let len = s.len();
+ let mut index = len;
+ let mut mat = 0;
+ do io::with_str_reader(s) |rdr| {
+ let mut ch;
+ while !rdr.eof() {
+ ch = rdr.read_byte() as char;
+ if ch == c {
+ // found a match, adjust markers
+ index = rdr.tell()-1;
+ mat = 1;
+ break;
+ }
+ }
+ }
+ if index+mat == len {
+ return (s.slice(0, index).to_owned(), ~"");
+ } else {
+ return (s.slice(0, index).to_owned(),
+ s.slice(index + mat, s.len()).to_owned());
+ }
+}
+
+fn userinfo_from_str(uinfo: &str) -> UserInfo {
+ let (user, p) = split_char_first(uinfo, ':');
+ let pass = if p.is_empty() {
+ None
+ } else {
+ Some(p)
+ };
+ return UserInfo::new(user, pass);
+}
+
+fn userinfo_to_str(userinfo: &UserInfo) -> ~str {
+ match userinfo.pass {
+ Some(ref pass) => fmt!("%s:%s@", userinfo.user, *pass),
+ None => fmt!("%s@", userinfo.user),
+ }
+}
+
+fn query_from_str(rawquery: &str) -> Query {
+ let mut query: Query = ~[];
+ if !rawquery.is_empty() {
+ for rawquery.split_iter('&').advance |p| {
+ let (k, v) = split_char_first(p, '=');
+ query.push((decode_component(k), decode_component(v)));
+ };
+ }
+ return query;
+}
+
+pub fn query_to_str(query: &Query) -> ~str {
+ let mut strvec = ~[];
+ for query.iter().advance |kv| {
+ match kv {
+ &(ref k, ref v) => {
+ strvec.push(fmt!("%s=%s",
+ encode_component(*k),
+ encode_component(*v))
+ );
+ }
+ }
+ }
+ return strvec.connect("&");
+}
+
+// returns the scheme and the rest of the url, or a parsing error
+pub fn get_scheme(rawurl: &str) -> Result<(~str, ~str), ~str> {
+ for rawurl.iter().enumerate().advance |(i,c)| {
+ match c {
+ 'A' .. 'Z' | 'a' .. 'z' => loop,
+ '0' .. '9' | '+' | '-' | '.' => {
+ if i == 0 {
+ return Err(~"url: Scheme must begin with a letter.");
+ }
+ loop;
+ }
+ ':' => {
+ if i == 0 {
+ return Err(~"url: Scheme cannot be empty.");
+ } else {
+ return Ok((rawurl.slice(0,i).to_owned(),
+ rawurl.slice(i+1,rawurl.len()).to_owned()));
+ }
+ }
+ _ => {
+ return Err(~"url: Invalid character in scheme.");
+ }
+ }
+ };
+ return Err(~"url: Scheme must be terminated with a colon.");
+}
+
+#[deriving(Clone, Eq)]
+enum Input {
+ Digit, // all digits
+ Hex, // digits and letters a-f
+ Unreserved // all other legal characters
+}
+
+// returns userinfo, host, port, and unparsed part, or an error
+fn get_authority(rawurl: &str) ->
+ Result<(Option<UserInfo>, ~str, Option<~str>, ~str), ~str> {
+ if !rawurl.starts_with("//") {
+ // there is no authority.
+ return Ok((None, ~"", None, rawurl.to_str()));
+ }
+
+ enum State {
+ Start, // starting state
+ PassHostPort, // could be in user or port
+ Ip6Port, // either in ipv6 host or port
+ Ip6Host, // are in an ipv6 host
+ InHost, // are in a host - may be ipv6, but don't know yet
+ InPort // are in port
+ }
+
+ let len = rawurl.len();
+ let mut st = Start;
+ let mut in = Digit; // most restricted, start here.
+
+ let mut userinfo = None;
+ let mut host = ~"";
+ let mut port = None;
+
+ let mut colon_count = 0;
+ let mut pos = 0;
+ let mut begin = 2;
+ let mut end = len;
+
+ for rawurl.iter().enumerate().advance |(i,c)| {
+ if i < 2 { loop; } // ignore the leading //
+
+ // deal with input class first
+ match c {
+ '0' .. '9' => (),
+ 'A' .. 'F' | 'a' .. 'f' => {
+ if in == Digit {
+ in = Hex;
+ }
+ }
+ 'G' .. 'Z' | 'g' .. 'z' | '-' | '.' | '_' | '~' | '%' |
+ '&' |'\'' | '(' | ')' | '+' | '!' | '*' | ',' | ';' | '=' => {
+ in = Unreserved;
+ }
+ ':' | '@' | '?' | '#' | '/' => {
+ // separators, don't change anything
+ }
+ _ => {
+ return Err(~"Illegal character in authority");
+ }
+ }
+
+ // now process states
+ match c {
+ ':' => {
+ colon_count += 1;
+ match st {
+ Start => {
+ pos = i;
+ st = PassHostPort;
+ }
+ PassHostPort => {
+ // multiple colons means ipv6 address.
+ if in == Unreserved {
+ return Err(
+ ~"Illegal characters in IPv6 address.");
+ }
+ st = Ip6Host;
+ }
+ InHost => {
+ pos = i;
+ // can't be sure whether this is an ipv6 address or a port
+ if in == Unreserved {
+ return Err(~"Illegal characters in authority.");
+ }
+ st = Ip6Port;
+ }
+ Ip6Port => {
+ if in == Unreserved {
+ return Err(~"Illegal characters in authority.");
+ }
+ st = Ip6Host;
+ }
+ Ip6Host => {
+ if colon_count > 7 {
+ host = rawurl.slice(begin, i).to_owned();
+ pos = i;
+ st = InPort;
+ }
+ }
+ _ => {
+ return Err(~"Invalid ':' in authority.");
+ }
+ }
+ in = Digit; // reset input class
+ }
+
+ '@' => {
+ in = Digit; // reset input class
+ colon_count = 0; // reset count
+ match st {
+ Start => {
+ let user = rawurl.slice(begin, i).to_owned();
+ userinfo = Some(UserInfo::new(user, None));
+ st = InHost;
+ }
+ PassHostPort => {
+ let user = rawurl.slice(begin, pos).to_owned();
+ let pass = rawurl.slice(pos+1, i).to_owned();
+ userinfo = Some(UserInfo::new(user, Some(pass)));
+ st = InHost;
+ }
+ _ => {
+ return Err(~"Invalid '@' in authority.");
+ }
+ }
+ begin = i+1;
+ }
+
+ '?' | '#' | '/' => {
+ end = i;
+ break;
+ }
+ _ => ()
+ }
+ end = i;
+ }
+
+ let end = end; // make end immutable so it can be captured
+
+ let host_is_end_plus_one: &fn() -> bool = || {
+ let xs = ['?', '#', '/'];
+ end+1 == len
+ && !xs.iter().any(|x| *x == (rawurl[end] as char))
+ };
+
+ // finish up
+ match st {
+ Start => {
+ if host_is_end_plus_one() {
+ host = rawurl.slice(begin, end+1).to_owned();
+ } else {
+ host = rawurl.slice(begin, end).to_owned();
+ }
+ }
+ PassHostPort | Ip6Port => {
+ if in != Digit {
+ return Err(~"Non-digit characters in port.");
+ }
+ host = rawurl.slice(begin, pos).to_owned();
+ port = Some(rawurl.slice(pos+1, end).to_owned());
+ }
+ Ip6Host | InHost => {
+ host = rawurl.slice(begin, end).to_owned();
+ }
+ InPort => {
+ if in != Digit {
+ return Err(~"Non-digit characters in port.");
+ }
+ port = Some(rawurl.slice(pos+1, end).to_owned());
+ }
+ }
+
+ let rest = if host_is_end_plus_one() { ~"" }
+ else { rawurl.slice(end, len).to_owned() };
+ return Ok((userinfo, host, port, rest));
+}
+
+
+// returns the path and unparsed part of url, or an error
+fn get_path(rawurl: &str, authority: bool) ->
+ Result<(~str, ~str), ~str> {
+ let len = rawurl.len();
+ let mut end = len;
+ for rawurl.iter().enumerate().advance |(i,c)| {
+ match c {
+ 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '&' |'\'' | '(' | ')' | '.'
+ | '@' | ':' | '%' | '/' | '+' | '!' | '*' | ',' | ';' | '='
+ | '_' | '-' => {
+ loop;
+ }
+ '?' | '#' => {
+ end = i;
+ break;
+ }
+ _ => return Err(~"Invalid character in path.")
+ }
+ }
+
+ if authority {
+ if end != 0 && !rawurl.starts_with("/") {
+ return Err(~"Non-empty path must begin with\
+ '/' in presence of authority.");
+ }
+ }
+
+ return Ok((decode_component(rawurl.slice(0, end)),
+ rawurl.slice(end, len).to_owned()));
+}
+
+// returns the parsed query and the fragment, if present
+fn get_query_fragment(rawurl: &str) ->
+ Result<(Query, Option<~str>), ~str> {
+ if !rawurl.starts_with("?") {
+ if rawurl.starts_with("#") {
+ let f = decode_component(rawurl.slice(
+ 1,
+ rawurl.len()));
+ return Ok((~[], Some(f)));
+ } else {
+ return Ok((~[], None));
+ }
+ }
+ let (q, r) = split_char_first(rawurl.slice(1, rawurl.len()), '#');
+ let f = if r.len() != 0 {
+ Some(decode_component(r)) } else { None };
+ return Ok((query_from_str(q), f));
+}
+
+/**
+ * Parse a `str` to a `url`
+ *
+ * # Arguments
+ *
+ * `rawurl` - a string representing a full url, including scheme.
+ *
+ * # Returns
+ *
+ * a `url` that contains the parsed representation of the url.
+ *
+ */
+
+pub fn from_str(rawurl: &str) -> Result<Url, ~str> {
+ // scheme
+ let (scheme, rest) = match get_scheme(rawurl) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ // authority
+ let (userinfo, host, port, rest) = match get_authority(rest) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ // path
+ let has_authority = if host == ~"" { false } else { true };
+ let (path, rest) = match get_path(rest, has_authority) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ // query and fragment
+ let (query, fragment) = match get_query_fragment(rest) {
+ Ok(val) => val,
+ Err(e) => return Err(e),
+ };
+
+ Ok(Url::new(scheme, userinfo, host, port, path, query, fragment))
+}
+
+impl FromStr for Url {
+ fn from_str(s: &str) -> Option<Url> {
+ match from_str(s) {
+ Ok(url) => Some(url),
+ Err(_) => None
+ }
+ }
+}
+
+/**
+ * Format a `url` as a string
+ *
+ * # Arguments
+ *
+ * `url` - a url.
+ *
+ * # Returns
+ *
+ * a `str` that contains the formatted url. Note that this will usually
+ * be an inverse of `from_str` but might strip out unneeded separators.
+ * for example, "http://somehost.com?", when parsed and formatted, will
+ * result in just "http://somehost.com".
+ *
+ */
+pub fn to_str(url: &Url) -> ~str {
+ let user = match url.user {
+ Some(ref user) => userinfo_to_str(user),
+ None => ~"",
+ };
+
+ let authority = if url.host.is_empty() {
+ ~""
+ } else {
+ fmt!("//%s%s", user, url.host)
+ };
+
+ let query = if url.query.is_empty() {
+ ~""
+ } else {
+ fmt!("?%s", query_to_str(&url.query))
+ };
+
+ let fragment = match url.fragment {
+ Some(ref fragment) => fmt!("#%s", encode_component(*fragment)),
+ None => ~"",
+ };
+
+ fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment)
+}
+
+impl ToStr for Url {
+ pub fn to_str(&self) -> ~str {
+ to_str(self)
+ }
+}
+
+impl IterBytes for Url {
+ fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
+ self.to_str().iter_bytes(lsb0, f)
+ }
+}
+
+// Put a few tests outside of the 'test' module so they can test the internal
+// functions and those functions don't need 'pub'
+
+#[test]
+fn test_split_char_first() {
+ let (u,v) = split_char_first("hello, sweet world", ',');
+ assert_eq!(u, ~"hello");
+ assert_eq!(v, ~" sweet world");
+
+ let (u,v) = split_char_first("hello sweet world", ',');
+ assert_eq!(u, ~"hello sweet world");
+ assert_eq!(v, ~"");
+}
+
+#[test]
+fn test_get_authority() {
+ let (u, h, p, r) = get_authority(
+ "//user:pass@rust-lang.org/something").unwrap();
+ assert_eq!(u, Some(UserInfo::new(~"user", Some(~"pass"))));
+ assert_eq!(h, ~"rust-lang.org");
+ assert!(p.is_none());
+ assert_eq!(r, ~"/something");
+
+ let (u, h, p, r) = get_authority(
+ "//rust-lang.org:8000?something").unwrap();
+ assert!(u.is_none());
+ assert_eq!(h, ~"rust-lang.org");
+ assert_eq!(p, Some(~"8000"));
+ assert_eq!(r, ~"?something");
+
+ let (u, h, p, r) = get_authority(
+ "//rust-lang.org#blah").unwrap();
+ assert!(u.is_none());
+ assert_eq!(h, ~"rust-lang.org");
+ assert!(p.is_none());
+ assert_eq!(r, ~"#blah");
+
+ // ipv6 tests
+ let (_, h, _, _) = get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334#blah").unwrap();
+ assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
+
+ let (_, h, p, _) = get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah").unwrap();
+ assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
+ assert_eq!(p, Some(~"8000"));
+
+ let (u, h, p, _) = get_authority(
+ "//us:p@2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000#blah"
+ ).unwrap();
+ assert_eq!(u, Some(UserInfo::new(~"us", Some(~"p"))));
+ assert_eq!(h, ~"2001:0db8:85a3:0042:0000:8a2e:0370:7334");
+ assert_eq!(p, Some(~"8000"));
+
+ // invalid authorities;
+ assert!(get_authority("//user:pass@rust-lang:something").is_err());
+ assert!(get_authority("//user@rust-lang:something:/path").is_err());
+ assert!(get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:800a").is_err());
+ assert!(get_authority(
+ "//2001:0db8:85a3:0042:0000:8a2e:0370:7334:8000:00").is_err());
+
+ // these parse as empty, because they don't start with '//'
+ let (_, h, _, _) = get_authority("user:pass@rust-lang").unwrap();
+ assert_eq!(h, ~"");
+ let (_, h, _, _) = get_authority("rust-lang.org").unwrap();
+ assert_eq!(h, ~"");
+}
+
+#[test]
+fn test_get_path() {
+ let (p, r) = get_path("/something+%20orother", true).unwrap();
+ assert_eq!(p, ~"/something+ orother");
+ assert_eq!(r, ~"");
+ let (p, r) = get_path("test@email.com#fragment", false).unwrap();
+ assert_eq!(p, ~"test@email.com");
+ assert_eq!(r, ~"#fragment");
+ let (p, r) = get_path("/gen/:addr=?q=v", false).unwrap();
+ assert_eq!(p, ~"/gen/:addr=");
+ assert_eq!(r, ~"?q=v");
+
+ //failure cases
+ assert!(get_path("something?q", true).is_err());
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+
+ use std::hashmap::HashMap;
+
+ #[test]
+ fn test_url_parse() {
+ let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
+
+ let up = from_str(url);
+ let u = up.unwrap();
+ assert!(u.scheme == ~"http");
+ let userinfo = u.user.get_ref();
+ assert!(userinfo.user == ~"user");
+ assert!(userinfo.pass.get_ref() == &~"pass");
+ assert!(u.host == ~"rust-lang.org");
+ assert!(u.path == ~"/doc");
+ assert!(u.query == ~[(~"s", ~"v")]);
+ assert!(u.fragment.get_ref() == &~"something");
+ }
+
+ #[test]
+ fn test_url_parse_host_slash() {
+ let urlstr = ~"http://0.42.42.42/";
+ let url = from_str(urlstr).unwrap();
+ assert!(url.host == ~"0.42.42.42");
+ assert!(url.path == ~"/");
+ }
+
+ #[test]
+ fn test_url_with_underscores() {
+ let urlstr = ~"http://dotcom.com/file_name.html";
+ let url = from_str(urlstr).unwrap();
+ assert!(url.path == ~"/file_name.html");
+ }
+
+ #[test]
+ fn test_url_with_dashes() {
+ let urlstr = ~"http://dotcom.com/file-name.html";
+ let url = from_str(urlstr).unwrap();
+ assert!(url.path == ~"/file-name.html");
+ }
+
+ #[test]
+ fn test_no_scheme() {
+ assert!(get_scheme("noschemehere.html").is_err());
+ }
+
+ #[test]
+ fn test_invalid_scheme_errors() {
+ assert!(from_str("99://something").is_err());
+ assert!(from_str("://something").is_err());
+ }
+
+ #[test]
+ fn test_full_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_userless_url_parse_and_format() {
+ let url = ~"http://rust-lang.org/doc?s=v#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_queryless_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_empty_query_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc?#something";
+ let should_be = ~"http://user:pass@rust-lang.org/doc#something";
+ assert_eq!(from_str(url).unwrap().to_str(), should_be);
+ }
+
+ #[test]
+ fn test_fragmentless_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org/doc?q=v";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_minimal_url_parse_and_format() {
+ let url = ~"http://rust-lang.org/doc";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_scheme_host_only_url_parse_and_format() {
+ let url = ~"http://rust-lang.org";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_pathless_url_parse_and_format() {
+ let url = ~"http://user:pass@rust-lang.org?q=v#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_scheme_host_fragment_only_url_parse_and_format() {
+ let url = ~"http://rust-lang.org#something";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_url_component_encoding() {
+ let url = ~"http://rust-lang.org/doc%20uments?ba%25d%20=%23%26%2B";
+ let u = from_str(url).unwrap();
+ assert!(u.path == ~"/doc uments");
+ assert!(u.query == ~[(~"ba%d ", ~"#&+")]);
+ }
+
+ #[test]
+ fn test_url_without_authority() {
+ let url = ~"mailto:test@email.com";
+ assert_eq!(from_str(url).unwrap().to_str(), url);
+ }
+
+ #[test]
+ fn test_encode() {
+ assert_eq!(encode(""), ~"");
+ assert_eq!(encode("http://example.com"), ~"http://example.com");
+ assert_eq!(encode("foo bar% baz"), ~"foo%20bar%25%20baz");
+ assert_eq!(encode(" "), ~"%20");
+ assert_eq!(encode("!"), ~"!");
+ assert_eq!(encode("\""), ~"\"");
+ assert_eq!(encode("#"), ~"#");
+ assert_eq!(encode("$"), ~"$");
+ assert_eq!(encode("%"), ~"%25");
+ assert_eq!(encode("&"), ~"&");
+ assert_eq!(encode("'"), ~"%27");
+ assert_eq!(encode("("), ~"(");
+ assert_eq!(encode(")"), ~")");
+ assert_eq!(encode("*"), ~"*");
+ assert_eq!(encode("+"), ~"+");
+ assert_eq!(encode(","), ~",");
+ assert_eq!(encode("/"), ~"/");
+ assert_eq!(encode(":"), ~":");
+ assert_eq!(encode(";"), ~";");
+ assert_eq!(encode("="), ~"=");
+ assert_eq!(encode("?"), ~"?");
+ assert_eq!(encode("@"), ~"@");
+ assert_eq!(encode("["), ~"[");
+ assert_eq!(encode("]"), ~"]");
+ }
+
+ #[test]
+ fn test_encode_component() {
+ assert_eq!(encode_component(""), ~"");
+ assert!(encode_component("http://example.com") ==
+ ~"http%3A%2F%2Fexample.com");
+ assert!(encode_component("foo bar% baz") ==
+ ~"foo%20bar%25%20baz");
+ assert_eq!(encode_component(" "), ~"%20");
+ assert_eq!(encode_component("!"), ~"%21");
+ assert_eq!(encode_component("#"), ~"%23");
+ assert_eq!(encode_component("$"), ~"%24");
+ assert_eq!(encode_component("%"), ~"%25");
+ assert_eq!(encode_component("&"), ~"%26");
+ assert_eq!(encode_component("'"), ~"%27");
+ assert_eq!(encode_component("("), ~"%28");
+ assert_eq!(encode_component(")"), ~"%29");
+ assert_eq!(encode_component("*"), ~"%2A");
+ assert_eq!(encode_component("+"), ~"%2B");
+ assert_eq!(encode_component(","), ~"%2C");
+ assert_eq!(encode_component("/"), ~"%2F");
+ assert_eq!(encode_component(":"), ~"%3A");
+ assert_eq!(encode_component(";"), ~"%3B");
+ assert_eq!(encode_component("="), ~"%3D");
+ assert_eq!(encode_component("?"), ~"%3F");
+ assert_eq!(encode_component("@"), ~"%40");
+ assert_eq!(encode_component("["), ~"%5B");
+ assert_eq!(encode_component("]"), ~"%5D");
+ }
+
+ #[test]
+ fn test_decode() {
+ assert_eq!(decode(""), ~"");
+ assert_eq!(decode("abc/def 123"), ~"abc/def 123");
+ assert_eq!(decode("abc%2Fdef%20123"), ~"abc%2Fdef 123");
+ assert_eq!(decode("%20"), ~" ");
+ assert_eq!(decode("%21"), ~"%21");
+ assert_eq!(decode("%22"), ~"%22");
+ assert_eq!(decode("%23"), ~"%23");
+ assert_eq!(decode("%24"), ~"%24");
+ assert_eq!(decode("%25"), ~"%");
+ assert_eq!(decode("%26"), ~"%26");
+ assert_eq!(decode("%27"), ~"'");
+ assert_eq!(decode("%28"), ~"%28");
+ assert_eq!(decode("%29"), ~"%29");
+ assert_eq!(decode("%2A"), ~"%2A");
+ assert_eq!(decode("%2B"), ~"%2B");
+ assert_eq!(decode("%2C"), ~"%2C");
+ assert_eq!(decode("%2F"), ~"%2F");
+ assert_eq!(decode("%3A"), ~"%3A");
+ assert_eq!(decode("%3B"), ~"%3B");
+ assert_eq!(decode("%3D"), ~"%3D");
+ assert_eq!(decode("%3F"), ~"%3F");
+ assert_eq!(decode("%40"), ~"%40");
+ assert_eq!(decode("%5B"), ~"%5B");
+ assert_eq!(decode("%5D"), ~"%5D");
+ }
+
+ #[test]
+ fn test_decode_component() {
+ assert_eq!(decode_component(""), ~"");
+ assert_eq!(decode_component("abc/def 123"), ~"abc/def 123");
+ assert_eq!(decode_component("abc%2Fdef%20123"), ~"abc/def 123");
+ assert_eq!(decode_component("%20"), ~" ");
+ assert_eq!(decode_component("%21"), ~"!");
+ assert_eq!(decode_component("%22"), ~"\"");
+ assert_eq!(decode_component("%23"), ~"#");
+ assert_eq!(decode_component("%24"), ~"$");
+ assert_eq!(decode_component("%25"), ~"%");
+ assert_eq!(decode_component("%26"), ~"&");
+ assert_eq!(decode_component("%27"), ~"'");
+ assert_eq!(decode_component("%28"), ~"(");
+ assert_eq!(decode_component("%29"), ~")");
+ assert_eq!(decode_component("%2A"), ~"*");
+ assert_eq!(decode_component("%2B"), ~"+");
+ assert_eq!(decode_component("%2C"), ~",");
+ assert_eq!(decode_component("%2F"), ~"/");
+ assert_eq!(decode_component("%3A"), ~":");
+ assert_eq!(decode_component("%3B"), ~";");
+ assert_eq!(decode_component("%3D"), ~"=");
+ assert_eq!(decode_component("%3F"), ~"?");
+ assert_eq!(decode_component("%40"), ~"@");
+ assert_eq!(decode_component("%5B"), ~"[");
+ assert_eq!(decode_component("%5D"), ~"]");
+ }
+
+ #[test]
+ fn test_encode_form_urlencoded() {
+ let mut m = HashMap::new();
+ assert_eq!(encode_form_urlencoded(&m), ~"");
+
+ m.insert(~"", ~[]);
+ m.insert(~"foo", ~[]);
+ assert_eq!(encode_form_urlencoded(&m), ~"");
+
+ let mut m = HashMap::new();
+ m.insert(~"foo", ~[~"bar", ~"123"]);
+ assert_eq!(encode_form_urlencoded(&m), ~"foo=bar&foo=123");
+
+ let mut m = HashMap::new();
+ m.insert(~"foo bar", ~[~"abc", ~"12 = 34"]);
+ assert!(encode_form_urlencoded(&m) ==
+ ~"foo+bar=abc&foo+bar=12+%3D+34");
+ }
+
+ #[test]
+ fn test_decode_form_urlencoded() {
+ // FIXME #4449: Commented out because this causes an ICE, but only
+ // on FreeBSD
+ /*
+ assert_eq!(decode_form_urlencoded([]).len(), 0);
+
+ let s = "a=1&foo+bar=abc&foo+bar=12+%3D+34".as_bytes();
+ let form = decode_form_urlencoded(s);
+ assert_eq!(form.len(), 2);
+ assert_eq!(form.get_ref(&~"a"), &~[~"1"]);
+ assert_eq!(form.get_ref(&~"foo bar"), &~[~"abc", ~"12 = 34"]);
+ */
+ }
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
- * Rust bindings to libuv
- *
- * This is the base-module for various levels of bindings to
- * the libuv library.
- *
- * These modules are seeing heavy work, currently, and the final
- * API layout should not be inferred from its current form.
- *
- * This base module currently contains a historical, rust-based
- * implementation of a few libuv operations that hews closely to
- * the patterns of the libuv C-API. It was used, mostly, to explore
- * some implementation details and will most likely be deprecated
- * in the near future.
- *
- * The `ll` module contains low-level mappings for working directly
- * with the libuv C-API.
- *
- * The `hl` module contains a set of tools library developers can
- * use for interacting with an active libuv loop. This modules's
- * API is meant to be used to write high-level,
- * rust-idiomatic abstractions for utilizes libuv's asynchronous IO
- * facilities.
- */
-
-pub use ll = super::uv_ll;
-pub use iotask = uv_iotask;
-pub use global_loop = uv_global_loop;
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A process-wide libuv event loop for library use.
-
-
-use iotask = uv_iotask;
-use uv_iotask::{IoTask, spawn_iotask};
-
-use std::comm::Chan;
-use std::option::{Some, None};
-use std::task::task;
-use std::unstable::global::{global_data_clone_create, global_data_clone};
-use std::unstable::weak_task::weaken_task;
-
-/**
- * Race-free helper to get access to a global task where a libuv
- * loop is running.
- *
- * Use `uv::hl::interact` to do operations against the global
- * loop that this function returns.
- *
- * # Return
- *
- * * A `hl::high_level_loop` that encapsulates communication with the global
- * loop.
- */
-pub fn get() -> IoTask {
- return get_monitor_task_gl();
-}
-
-#[doc(hidden)]
-fn get_monitor_task_gl() -> IoTask {
-
- type MonChan = Chan<IoTask>;
-
- struct GlobalIoTask(IoTask);
-
- impl Clone for GlobalIoTask {
- fn clone(&self) -> GlobalIoTask {
- GlobalIoTask((**self).clone())
- }
- }
-
- fn key(_: GlobalIoTask) { }
-
- match unsafe { global_data_clone(key) } {
- Some(GlobalIoTask(iotask)) => iotask,
- None => {
- let iotask: IoTask = spawn_loop();
- let mut installed = false;
- let final_iotask = unsafe {
- do global_data_clone_create(key) {
- installed = true;
- ~GlobalIoTask(iotask.clone())
- }
- };
- if installed {
- let mut task = task();
- task.unlinked();
- do task.spawn {
- unsafe {
- debug!("global monitor task starting");
- // As a weak task the runtime will notify us
- // when to exit
- do weaken_task |weak_exit_po| {
- debug!("global monitor task is weak");
- weak_exit_po.recv();
- iotask::exit(&iotask);
- debug!("global monitor task is unweak");
- };
- debug!("global monitor task exiting");
- }
- }
- } else {
- iotask::exit(&iotask);
- }
-
- match final_iotask {
- GlobalIoTask(iotask) => iotask
- }
- }
- }
-}
-
-fn spawn_loop() -> IoTask {
- let mut builder = task();
-
- do builder.add_wrapper |task_body| {
- let result: ~fn() = || {
- // The I/O loop task also needs to be weak so it doesn't keep
- // the runtime alive
- unsafe {
- do weaken_task |_| {
- debug!("global libuv task is now weak");
- task_body();
-
- // We don't wait for the exit message on weak_exit_po
- // because the monitor task will tell the uv loop when to
- // exit
-
- debug!("global libuv task is leaving weakened state");
- }
- }
- };
- result
- };
-
- builder.unlinked();
- spawn_iotask(builder)
-}
-
-#[cfg(test)]
-mod test {
-
- use get_gl = uv_global_loop::get;
- use uv::iotask;
- use uv::ll;
- use uv_iotask::IoTask;
-
- use std::libc;
- use std::task;
- use std::cast::transmute;
- use std::libc::c_void;
- use std::comm::{stream, SharedChan, Chan};
-
- extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) {
- unsafe {
- let exit_ch_ptr = ll::get_data_for_uv_handle(
- timer_ptr as *libc::c_void);
- let exit_ch = transmute::<*c_void, ~Chan<bool>>(exit_ch_ptr);
- exit_ch.send(true);
- debug!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
- exit_ch_ptr);
- }
- }
- extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
- _status: libc::c_int) {
- unsafe {
- debug!(~"in simple timer cb");
- ll::timer_stop(timer_ptr);
- let hl_loop = &get_gl();
- do iotask::interact(hl_loop) |_loop_ptr| {
- debug!(~"closing timer");
- ll::close(timer_ptr, simple_timer_close_cb);
- debug!(~"about to deref exit_ch_ptr");
- debug!(~"after msg sent on deref'd exit_ch");
- };
- debug!(~"exiting simple timer cb");
- }
- }
-
- fn impl_uv_hl_simple_timer(iotask: &IoTask) {
- unsafe {
- let (exit_po, exit_ch) = stream::<bool>();
- let exit_ch_ptr: *libc::c_void = transmute(~exit_ch);
- debug!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
- exit_ch_ptr);
- let timer_handle = ll::timer_t();
- let timer_ptr: *ll::uv_timer_t = &timer_handle;
- do iotask::interact(iotask) |loop_ptr| {
- debug!(~"user code inside interact loop!!!");
- let init_status = ll::timer_init(loop_ptr, timer_ptr);
- if(init_status == 0i32) {
- ll::set_data_for_uv_handle(
- timer_ptr as *libc::c_void,
- exit_ch_ptr);
- let start_status = ll::timer_start(timer_ptr,
- simple_timer_cb,
- 1u, 0u);
- if(start_status != 0i32) {
- fail!("failure on ll::timer_start()");
- }
- }
- else {
- fail!("failure on ll::timer_init()");
- }
- };
- exit_po.recv();
- debug!(
- ~"global_loop timer test: msg recv on exit_po, done..");
- }
- }
-
- #[test]
- fn test_gl_uv_global_loop_high_level_global_timer() {
- let hl_loop = &get_gl();
- let (exit_po, exit_ch) = stream::<()>();
- task::spawn_sched(task::ManualThreads(1u), || {
- let hl_loop = &get_gl();
- impl_uv_hl_simple_timer(hl_loop);
- exit_ch.send(());
- });
- impl_uv_hl_simple_timer(hl_loop);
- exit_po.recv();
- }
-
- // keeping this test ignored until some kind of stress-test-harness
- // is set up for the build bots
- #[test]
- #[ignore]
- fn test_stress_gl_uv_global_loop_high_level_global_timer() {
- let (exit_po, exit_ch) = stream::<()>();
- let exit_ch = SharedChan::new(exit_ch);
- let cycles = 5000u;
- for cycles.times {
- let exit_ch_clone = exit_ch.clone();
- task::spawn_sched(task::ManualThreads(1u), || {
- let hl_loop = &get_gl();
- impl_uv_hl_simple_timer(hl_loop);
- exit_ch_clone.send(());
- });
- };
- for cycles.times {
- exit_po.recv();
- };
- debug!("test_stress_gl_uv_global_loop_high_level_global_timer \
- exiting successfully!");
- }
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
- * A task-based interface to the uv loop
- *
- * The I/O task runs in its own single-threaded scheduler. By using the
- * `interact` function you can execute code in a uv callback.
- */
-
-#[allow(missing_doc)];
-
-
-use ll = uv_ll;
-
-use std::comm::{stream, Port, Chan, SharedChan};
-use std::libc::c_void;
-use std::libc;
-use std::task;
-
-/// Used to abstract-away direct interaction with a libuv loop.
-pub struct IoTask {
- async_handle: *ll::uv_async_t,
- op_chan: SharedChan<IoTaskMsg>
-}
-
-impl Clone for IoTask {
- fn clone(&self) -> IoTask {
- IoTask{
- async_handle: self.async_handle,
- op_chan: self.op_chan.clone()
- }
- }
-}
-
-pub fn spawn_iotask(mut task: task::TaskBuilder) -> IoTask {
- let (iotask_port, iotask_chan) = stream();
-
- task.sched_mode(task::SingleThreaded);
- do task.spawn {
- debug!("entering libuv task");
- run_loop(&iotask_chan);
- debug!("libuv task exiting");
- };
-
- iotask_port.recv()
-}
-
-
-/**
- * Provide a callback to be processed by `iotask`
- *
- * The primary way to do operations again a running `iotask` that
- * doesn't involve creating a uv handle via `safe_handle`
- *
- * # Warning
- *
- * This function is the only safe way to interact with _any_ `iotask`.
- * Using functions in the `uv::ll` module outside of the `cb` passed into
- * this function is _very dangerous_.
- *
- * # Arguments
- *
- * * iotask - a uv I/O task that you want to do operations against
- * * cb - a function callback to be processed on the running loop's
- * thread. The only parameter passed in is an opaque pointer representing the
- * running `uv_loop_t*`. In the context of this callback, it is safe to use
- * this pointer to do various uv_* API calls contained within the `uv::ll`
- * module. It is not safe to send the `loop_ptr` param to this callback out
- * via ports/chans.
- */
-pub fn interact(iotask: &IoTask, cb: ~fn(*c_void)) {
- send_msg(iotask, Interaction(cb));
-}
-
-/**
- * Shut down the I/O task
- *
- * Is used to signal to the loop that it should close the internally-held
- * async handle and do a sanity check to make sure that all other handles are
- * closed, causing a failure otherwise.
- */
-pub fn exit(iotask: &IoTask) {
- send_msg(iotask, TeardownLoop);
-}
-
-
-// INTERNAL API
-
-enum IoTaskMsg {
- Interaction(~fn(*libc::c_void)),
- TeardownLoop
-}
-
-/// Run the loop and begin handling messages
-fn run_loop(iotask_ch: &Chan<IoTask>) {
-
- unsafe {
- debug!("creating loop");
- let loop_ptr = ll::loop_new();
-
- // set up the special async handle we'll use to allow multi-task
- // communication with this loop
- let async = ll::async_t();
- let async_handle: *ll::uv_async_t = &async;
-
- // associate the async handle with the loop
- ll::async_init(loop_ptr, async_handle, wake_up_cb);
-
- let (msg_po, msg_ch) = stream::<IoTaskMsg>();
-
- // initialize our loop data and store it in the loop
- let data: IoTaskLoopData = IoTaskLoopData {
- async_handle: async_handle,
- msg_po: msg_po
- };
- ll::set_data_for_uv_handle(async_handle, &data);
-
- // Send out a handle through which folks can talk to us
- // while we dwell in the I/O loop
- let iotask = IoTask {
- async_handle: async_handle,
- op_chan: SharedChan::new(msg_ch)
- };
- iotask_ch.send(iotask);
-
- debug!("about to run uv loop");
- // enter the loop... this blocks until the loop is done..
- ll::run(loop_ptr);
- debug!("uv loop ended");
- ll::loop_delete(loop_ptr);
- }
-}
-
-// data that lives for the lifetime of the high-evel oo
-struct IoTaskLoopData {
- async_handle: *ll::uv_async_t,
- msg_po: Port<IoTaskMsg>,
-}
-
-fn send_msg(iotask: &IoTask,
- msg: IoTaskMsg) {
- iotask.op_chan.send(msg);
- unsafe {
- ll::async_send(iotask.async_handle);
- }
-}
-
-/// Dispatch all pending messages
-extern fn wake_up_cb(async_handle: *ll::uv_async_t,
- status: int) {
-
- debug!("wake_up_cb extern.. handle: %? status: %?",
- async_handle, status);
-
- unsafe {
- let loop_ptr = ll::get_loop_for_uv_handle(async_handle);
- let data =
- ll::get_data_for_uv_handle(async_handle) as *IoTaskLoopData;
- let msg_po = &(*data).msg_po;
-
- while msg_po.peek() {
- match msg_po.recv() {
- Interaction(ref cb) => (*cb)(loop_ptr),
- TeardownLoop => begin_teardown(data)
- }
- }
- }
-}
-
-fn begin_teardown(data: *IoTaskLoopData) {
- unsafe {
- debug!("iotask begin_teardown() called, close async_handle");
- let async_handle = (*data).async_handle;
- ll::close(async_handle as *c_void, tear_down_close_cb);
- }
-}
-extern fn tear_down_walk_cb(handle: *libc::c_void, arg: *libc::c_void) {
- debug!("IN TEARDOWN WALK CB");
- // pretty much, if we still have an active handle and it is *not*
- // the async handle that facilities global loop communication, we
- // want to barf out and fail
- assert_eq!(handle, arg);
-}
-
-extern fn tear_down_close_cb(handle: *ll::uv_async_t) {
- unsafe {
- let loop_ptr = ll::get_loop_for_uv_handle(handle);
- debug!("in tear_down_close_cb");
- ll::walk(loop_ptr, tear_down_walk_cb, handle as *libc::c_void);
- }
-}
-
-#[cfg(test)]
-extern fn async_close_cb(handle: *ll::uv_async_t) {
- unsafe {
- debug!("async_close_cb handle %?", handle);
- let exit_ch = &(*(ll::get_data_for_uv_handle(handle)
- as *AhData)).exit_ch;
- let exit_ch = exit_ch.clone();
- exit_ch.send(());
- }
-}
-
-#[cfg(test)]
-extern fn async_handle_cb(handle: *ll::uv_async_t, status: libc::c_int) {
- unsafe {
- debug!("async_handle_cb handle %? status %?",handle,status);
- ll::close(handle, async_close_cb);
- }
-}
-
-#[cfg(test)]
-struct AhData {
- iotask: IoTask,
- exit_ch: SharedChan<()>
-}
-
-#[cfg(test)]
-fn impl_uv_iotask_async(iotask: &IoTask) {
- use std::ptr;
-
- let async_handle = ll::async_t();
- let ah_ptr: *ll::uv_async_t = &async_handle;
- let (exit_po, exit_ch) = stream::<()>();
- let ah_data = AhData {
- iotask: iotask.clone(),
- exit_ch: SharedChan::new(exit_ch)
- };
- let ah_data_ptr: *AhData = ptr::to_unsafe_ptr(&ah_data);
- debug!("about to interact");
- do interact(iotask) |loop_ptr| {
- unsafe {
- debug!("interacting");
- ll::async_init(loop_ptr, ah_ptr, async_handle_cb);
- ll::set_data_for_uv_handle(
- ah_ptr, ah_data_ptr as *libc::c_void);
- ll::async_send(ah_ptr);
- }
- };
- debug!("waiting for async close");
- exit_po.recv();
-}
-
-// this fn documents the bear minimum necessary to roll your own
-// high_level_loop
-#[cfg(test)]
-fn spawn_test_loop(exit_ch: ~Chan<()>) -> IoTask {
- let (iotask_port, iotask_ch) = stream::<IoTask>();
- do task::spawn_sched(task::ManualThreads(1u)) {
- debug!("about to run a test loop");
- run_loop(&iotask_ch);
- exit_ch.send(());
- };
- return iotask_port.recv();
-}
-
-#[cfg(test)]
-extern fn lifetime_handle_close(handle: *libc::c_void) {
- debug!("lifetime_handle_close ptr %?", handle);
-}
-
-#[cfg(test)]
-extern fn lifetime_async_callback(handle: *libc::c_void,
- status: libc::c_int) {
- debug!("lifetime_handle_close ptr %? status %?",
- handle, status);
-}
-
-#[test]
-fn test_uv_iotask_async() {
- let (exit_po, exit_ch) = stream::<()>();
- let iotask = &spawn_test_loop(~exit_ch);
-
- debug!("spawned iotask");
-
- // using this handle to manage the lifetime of the
- // high_level_loop, as it will exit the first time one of
- // the impl_uv_hl_async() is cleaned up with no one ref'd
- // handles on the loop (Which can happen under
- // race-condition type situations.. this ensures that the
- // loop lives until, at least, all of the
- // impl_uv_hl_async() runs have been called, at least.
- let (work_exit_po, work_exit_ch) = stream::<()>();
- let work_exit_ch = SharedChan::new(work_exit_ch);
- for 7u.times {
- let iotask_clone = iotask.clone();
- let work_exit_ch_clone = work_exit_ch.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- debug!("async");
- impl_uv_iotask_async(&iotask_clone);
- debug!("done async");
- work_exit_ch_clone.send(());
- };
- };
- for 7u.times {
- debug!("waiting");
- work_exit_po.recv();
- };
- debug!(~"sending teardown_loop msg..");
- exit(iotask);
- exit_po.recv();
- debug!(~"after recv on exit_po.. exiting..");
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
- * Low-level bindings to the libuv library.
- *
- * This module contains a set of direct, 'bare-metal' wrappers around
- * the libuv C-API.
- *
- * Also contained herein are a set of rust records that map, in
- * approximate memory-size, to the libuv data structures. The record
- * implementations are adjusted, per-platform, to match their respective
- * representations.
- *
- * There are also a collection of helper functions to ease interacting
- * with the low-level API (such as a function to return the latest
- * libuv error as a rust-formatted string).
- *
- * As new functionality, existant in uv.h, is added to the rust stdlib,
- * the mappings should be added in this module.
- *
- * This module's implementation will hopefully be, eventually, replaced
- * with per-platform, generated source files from rust-bindgen.
- */
-
-#[allow(non_camel_case_types)]; // C types
-#[allow(missing_doc)];
-
-
-use std::libc::{c_void, size_t};
-use std::libc;
-use std::ptr::to_unsafe_ptr;
-use std::ptr;
-use std::str;
-use std::vec;
-
-pub type uv_handle_t = c_void;
-pub type uv_loop_t = c_void;
-pub type uv_idle_t = c_void;
-pub type uv_idle_cb = *u8;
-
-// libuv struct mappings
-pub struct uv_ip4_addr {
- ip: ~[u8],
- port: int,
-}
-pub type uv_ip6_addr = uv_ip4_addr;
-
-pub enum uv_handle_type {
- UNKNOWN_HANDLE = 0,
- UV_TCP,
- UV_UDP,
- UV_NAMED_PIPE,
- UV_TTY,
- UV_FILE,
- UV_TIMER,
- UV_PREPARE,
- UV_CHECK,
- UV_IDLE,
- UV_ASYNC,
- UV_ARES_TASK,
- UV_ARES_EVENT,
- UV_PROCESS,
- UV_FS_EVENT
-}
-
-pub type handle_type = libc::c_uint;
-
-pub struct uv_handle_fields {
- loop_handle: *libc::c_void,
- type_: handle_type,
- close_cb: *u8,
- data: *libc::c_void,
-}
-
-// unix size: 8
-pub struct uv_err_t {
- code: libc::c_int,
- sys_errno_: libc::c_int
-}
-
-// don't create one of these directly. instead,
-// count on it appearing in libuv callbacks or embedded
-// in other types as a pointer to be used in other
-// operations (so mostly treat it as opaque, once you
-// have it in this form..)
-pub struct uv_stream_t {
- fields: uv_handle_fields,
-}
-
-// 64bit unix size: 216
-#[cfg(target_os="macos")]
-pub struct uv_tcp_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8, a13: *u8, a14: *u8, a15: *u8,
- a16: *u8, a17: *u8, a18: *u8, a19: *u8,
- a20: *u8, a21: *u8, a22: *u8,
- a23: uv_tcp_t_osx_riders
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_tcp_t_osx_riders {
- a23: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-pub struct uv_tcp_t_osx_riders {
- a23: *u8,
- a24: *u8, a25: *u8,
-}
-#[cfg(target_os="linux")]
-#[cfg(target_os="freebsd")]
-#[cfg(target_os="android")]
-pub struct uv_tcp_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8, a13: *u8, a14: *u8, a15: *u8,
- a16: *u8, a17: *u8, a18: *u8, a19: *u8,
- a20: *u8, a21: *u8,
- a22: uv_tcp_t_32bit_unix_riders,
-}
-// 32bit unix size: 328 (164)
-#[cfg(target_arch="x86_64")]
-pub struct uv_tcp_t_32bit_unix_riders {
- a29: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_tcp_t_32bit_unix_riders {
- a29: *u8, a30: *u8, a31: *u8,
-}
-
-// 32bit win32 size: 240 (120)
-#[cfg(windows)]
-pub struct uv_tcp_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8, a13: *u8, a14: *u8, a15: *u8,
- a16: *u8, a17: *u8, a18: *u8, a19: *u8,
- a20: *u8, a21: *u8, a22: *u8, a23: *u8,
- a24: *u8, a25: *u8,
-}
-
-// unix size: 64
-#[cfg(unix)]
-pub struct uv_connect_t {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8
-}
-// win32 size: 88 (44)
-#[cfg(windows)]
-pub struct uv_connect_t {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8,
-}
-
-// unix size: 16
-pub struct uv_buf_t {
- base: *u8,
- len: libc::size_t,
-}
-// no gen stub method.. should create
-// it via uv::direct::buf_init()
-
-// unix size: 160
-#[cfg(unix)]
-pub struct uv_write_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8,
- a14: uv_write_t_32bit_unix_riders,
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_write_t_32bit_unix_riders {
- a13: *u8, a14: *u8, a15: *u8
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_write_t_32bit_unix_riders {
- a13: *u8, a14: *u8, a15: *u8,
- a16: *u8,
-}
-// win32 size: 136 (68)
-#[cfg(windows)]
-pub struct uv_write_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8,
-}
-// 64bit unix size: 96
-// 32bit unix size: 152 (76)
-#[cfg(unix)]
-pub struct uv_async_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8,
- a07: uv_async_t_32bit_unix_riders,
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_async_t_32bit_unix_riders {
- a10: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_async_t_32bit_unix_riders {
- a10: *u8,
-}
-// win32 size 132 (68)
-#[cfg(windows)]
-pub struct uv_async_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
- a12: *u8,
-}
-
-// 64bit unix size: 120
-// 32bit unix size: 84
-#[cfg(unix)]
-pub struct uv_timer_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8,
- a11: uv_timer_t_32bit_unix_riders,
-}
-#[cfg(target_arch="x86_64")]
-pub struct uv_timer_t_32bit_unix_riders {
- a10: *u8,
-}
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct uv_timer_t_32bit_unix_riders {
- a10: *u8, a11: *u8, a12: *u8
-}
-// win32 size: 64
-#[cfg(windows)]
-pub struct uv_timer_t {
- fields: uv_handle_fields,
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- a08: *u8, a09: *u8, a10: *u8, a11: *u8,
-}
-
-// unix size: 16
-#[deriving(Clone)]
-pub struct sockaddr_in {
- sin_family: u16,
- sin_port: u16,
- sin_addr: u32, // in_addr: this is an opaque, per-platform struct
- sin_zero: (u8, u8, u8, u8, u8, u8, u8, u8),
-}
-
-// unix size: 28 .. FIXME #1645
-// stuck with 32 because of rust padding structs?
-#[cfg(target_arch="x86_64")]
-pub struct sockaddr_in6 {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
-}
-
-#[cfg(target_arch="x86")]
-#[cfg(target_arch="arm")]
-#[cfg(target_arch="mips")]
-pub struct sockaddr_in6 {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- a4: *u8, a5: *u8,
- a6: *u8, a7: *u8,
-}
-
-impl Clone for sockaddr_in6 {
- fn clone(&self) -> sockaddr_in6 {
- *self
- }
-}
-
-// unix size: 28 .. FIXME #1645
-// stuck with 32 because of rust padding structs?
-pub type addr_in = addr_in_impl::addr_in;
-#[cfg(unix)]
-pub mod addr_in_impl {
- #[cfg(target_arch="x86_64")]
- pub struct addr_in {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub struct addr_in {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- a4: *u8, a5: *u8,
- a6: *u8, a7: *u8,
- }
-}
-#[cfg(windows)]
-pub mod addr_in_impl {
- pub struct addr_in {
- a0: *u8, a1: *u8,
- a2: *u8, a3: *u8,
- }
-}
-
-// unix size: 48, 32bit: 32
-pub type addrinfo = addrinfo_impl::addrinfo;
-#[cfg(target_os="linux")]
-#[cfg(target_os="android")]
-pub mod addrinfo_impl {
- #[cfg(target_arch="x86_64")]
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8,
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8, a06: *u8, a07: *u8,
- }
-}
-#[cfg(target_os="macos")]
-#[cfg(target_os="freebsd")]
-pub mod addrinfo_impl {
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8,
- }
-}
-#[cfg(windows)]
-pub mod addrinfo_impl {
- pub struct addrinfo {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8,
- a04: *u8, a05: *u8,
- }
-}
-
-// unix size: 72
-pub struct uv_getaddrinfo_t {
- a00: *u8, a01: *u8, a02: *u8, a03: *u8, a04: *u8, a05: *u8,
- a06: *u8, a07: *u8, a08: *u8, a09: *u8,
- a10: *u8, a11: *u8, a12: *u8, a13: *u8, a14: *u8, a15: *u8
-}
-
-pub mod uv_ll_struct_stubgen {
-
- use std::ptr;
-
- use super::{
- uv_async_t,
- uv_connect_t,
- uv_getaddrinfo_t,
- uv_handle_fields,
- uv_tcp_t,
- uv_timer_t,
- uv_write_t,
- };
-
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- #[cfg(target_os = "macos")]
- #[cfg(target_os = "freebsd")]
- use super::{
- uv_async_t_32bit_unix_riders,
- uv_timer_t_32bit_unix_riders,
- uv_write_t_32bit_unix_riders,
- };
-
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- #[cfg(target_os = "freebsd")]
- use super::uv_tcp_t_32bit_unix_riders;
-
- pub fn gen_stub_uv_tcp_t() -> uv_tcp_t {
- return gen_stub_os();
- #[cfg(target_os = "linux")]
- #[cfg(target_os = "android")]
- #[cfg(target_os = "freebsd")]
- pub fn gen_stub_os() -> uv_tcp_t {
- return gen_stub_arch();
- #[cfg(target_arch="x86_64")]
- pub fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8,
- a22: uv_tcp_t_32bit_unix_riders { a29: 0 as *u8 },
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8,
- a22: uv_tcp_t_32bit_unix_riders {
- a29: 0 as *u8, a30: 0 as *u8, a31: 0 as *u8,
- },
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_os() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8,
- a23: 0 as *u8,
- a24: 0 as *u8, a25: 0 as *u8,
- }
- }
- #[cfg(target_os = "macos")]
- pub fn gen_stub_os() -> uv_tcp_t {
- use super::uv_tcp_t_osx_riders;
-
- return gen_stub_arch();
-
- #[cfg(target_arch = "x86_64")]
- fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8,
- a23: uv_tcp_t_osx_riders {
- a23: 0 as *u8,
- }
- }
- }
-
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch = "arm")]
- fn gen_stub_arch() -> uv_tcp_t {
- uv_tcp_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8, a13: 0 as *u8, a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8, a17: 0 as *u8, a18: 0 as *u8,
- a19: 0 as *u8,
- a20: 0 as *u8, a21: 0 as *u8, a22: 0 as *u8,
- a23: uv_tcp_t_osx_riders {
- a23: 0 as *u8,
- a24: 0 as *u8, a25: 0 as *u8,
- }
- }
- }
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_connect_t() -> uv_connect_t {
- uv_connect_t {
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_connect_t() -> uv_connect_t {
- uv_connect_t {
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_async_t() -> uv_async_t {
- return gen_stub_arch();
- #[cfg(target_arch = "x86_64")]
- pub fn gen_stub_arch() -> uv_async_t {
- uv_async_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: uv_async_t_32bit_unix_riders { a10: 0 as *u8 },
- }
- }
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_async_t {
- uv_async_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: uv_async_t_32bit_unix_riders {
- a10: 0 as *u8,
- }
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_async_t() -> uv_async_t {
- uv_async_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8,
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_timer_t() -> uv_timer_t {
- return gen_stub_arch();
- #[cfg(target_arch = "x86_64")]
- pub fn gen_stub_arch() -> uv_timer_t {
- uv_timer_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8,
- a11: uv_timer_t_32bit_unix_riders {
- a10: 0 as *u8
- },
- }
- }
- #[cfg(target_arch = "x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_timer_t {
- uv_timer_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8,
- a11: uv_timer_t_32bit_unix_riders {
- a10: 0 as *u8, a11: 0 as *u8,
- a12: 0 as *u8,
- },
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_timer_t() -> uv_timer_t {
- uv_timer_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- }
- }
- #[cfg(unix)]
- pub fn gen_stub_uv_write_t() -> uv_write_t {
- return gen_stub_arch();
- #[cfg(target_arch="x86_64")]
- pub fn gen_stub_arch() -> uv_write_t {
- uv_write_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8,
- a14: uv_write_t_32bit_unix_riders { a13: 0 as *u8,
- a14: 0 as *u8,
- a15: 0 as *u8},
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- pub fn gen_stub_arch() -> uv_write_t {
- uv_write_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8,
- a14: uv_write_t_32bit_unix_riders {
- a13: 0 as *u8,
- a14: 0 as *u8,
- a15: 0 as *u8,
- a16: 0 as *u8,
- }
- }
- }
- }
- #[cfg(windows)]
- pub fn gen_stub_uv_write_t() -> uv_write_t {
- uv_write_t {
- fields: uv_handle_fields {
- loop_handle: ptr::null(), type_: 0u32,
- close_cb: ptr::null(),
- data: ptr::null(),
- },
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8,
- a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8,
- a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8, a10: 0 as *u8,
- a11: 0 as *u8,
- a12: 0 as *u8
- }
- }
- pub fn gen_stub_uv_getaddrinfo_t() -> uv_getaddrinfo_t {
- uv_getaddrinfo_t {
- a00: 0 as *u8, a01: 0 as *u8, a02: 0 as *u8, a03: 0 as *u8,
- a04: 0 as *u8, a05: 0 as *u8, a06: 0 as *u8, a07: 0 as *u8,
- a08: 0 as *u8, a09: 0 as *u8,
- a10: 1 as *u8, a11: 1 as *u8, a12: 1 as *u8, a13: 1 as *u8,
- a14: 1 as *u8, a15: 1 as *u8
- }
- }
-}
-
-#[nolink]
-extern {
- // libuv public API
- unsafe fn rust_uv_loop_new() -> *libc::c_void;
- unsafe fn rust_uv_loop_delete(lp: *libc::c_void);
- unsafe fn rust_uv_run(loop_handle: *libc::c_void);
- unsafe fn rust_uv_close(handle: *libc::c_void, cb: *u8);
- unsafe fn rust_uv_walk(loop_handle: *libc::c_void, cb: *u8,
- arg: *libc::c_void);
-
- unsafe fn rust_uv_idle_new() -> *uv_idle_t;
- unsafe fn rust_uv_idle_delete(handle: *uv_idle_t);
- unsafe fn rust_uv_idle_init(loop_handle: *uv_loop_t,
- handle: *uv_idle_t) -> libc::c_int;
- unsafe fn rust_uv_idle_start(handle: *uv_idle_t,
- cb: uv_idle_cb) -> libc::c_int;
- unsafe fn rust_uv_idle_stop(handle: *uv_idle_t) -> libc::c_int;
-
- unsafe fn rust_uv_async_send(handle: *uv_async_t);
- unsafe fn rust_uv_async_init(loop_handle: *libc::c_void,
- async_handle: *uv_async_t,
- cb: *u8) -> libc::c_int;
- unsafe fn rust_uv_tcp_init(
- loop_handle: *libc::c_void,
- handle_ptr: *uv_tcp_t) -> libc::c_int;
- // FIXME ref #2604 .. ?
- unsafe fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8,
- len: libc::size_t);
- unsafe fn rust_uv_last_error(loop_handle: *libc::c_void) -> uv_err_t;
- // FIXME ref #2064
- unsafe fn rust_uv_strerror(err: *uv_err_t) -> *libc::c_char;
- // FIXME ref #2064
- unsafe fn rust_uv_err_name(err: *uv_err_t) -> *libc::c_char;
- unsafe fn rust_uv_ip4_addr(ip: *u8, port: libc::c_int)
- -> sockaddr_in;
- unsafe fn rust_uv_ip6_addr(ip: *u8, port: libc::c_int)
- -> sockaddr_in6;
- unsafe fn rust_uv_ip4_name(src: *sockaddr_in,
- dst: *u8,
- size: libc::size_t)
- -> libc::c_int;
- unsafe fn rust_uv_ip6_name(src: *sockaddr_in6,
- dst: *u8,
- size: libc::size_t)
- -> libc::c_int;
- unsafe fn rust_uv_ip4_port(src: *sockaddr_in) -> libc::c_uint;
- unsafe fn rust_uv_ip6_port(src: *sockaddr_in6) -> libc::c_uint;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- after_cb: *u8,
- addr: *sockaddr_in)
- -> libc::c_int;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t,
- addr: *sockaddr_in) -> libc::c_int;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- after_cb: *u8,
- addr: *sockaddr_in6) -> libc::c_int;
- // FIXME ref #2064
- unsafe fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t,
- addr: *sockaddr_in6) -> libc::c_int;
- unsafe fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in) -> libc::c_int;
- unsafe fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in6) ->libc::c_int;
- unsafe fn rust_uv_listen(stream: *libc::c_void,
- backlog: libc::c_int,
- cb: *u8) -> libc::c_int;
- unsafe fn rust_uv_accept(server: *libc::c_void, client: *libc::c_void)
- -> libc::c_int;
- unsafe fn rust_uv_write(req: *libc::c_void,
- stream: *libc::c_void,
- buf_in: *uv_buf_t,
- buf_cnt: libc::c_int,
- cb: *u8)
- -> libc::c_int;
- unsafe fn rust_uv_read_start(stream: *libc::c_void,
- on_alloc: *u8,
- on_read: *u8)
- -> libc::c_int;
- unsafe fn rust_uv_read_stop(stream: *libc::c_void) -> libc::c_int;
- unsafe fn rust_uv_timer_init(loop_handle: *libc::c_void,
- timer_handle: *uv_timer_t)
- -> libc::c_int;
- unsafe fn rust_uv_timer_start(
- timer_handle: *uv_timer_t,
- cb: *u8,
- timeout: libc::uint64_t,
- repeat: libc::uint64_t) -> libc::c_int;
- unsafe fn rust_uv_timer_stop(handle: *uv_timer_t) -> libc::c_int;
-
- unsafe fn rust_uv_getaddrinfo(loop_ptr: *libc::c_void,
- handle: *uv_getaddrinfo_t,
- cb: *u8,
- node_name_ptr: *u8,
- service_name_ptr: *u8,
- // should probably only pass ptr::null()
- hints: *addrinfo)
- -> libc::c_int;
- unsafe fn rust_uv_freeaddrinfo(res: *addrinfo);
-
- // data accessors/helpers for rust-mapped uv structs
- unsafe fn rust_uv_helper_get_INADDR_NONE() -> u32;
- unsafe fn rust_uv_is_ipv4_addrinfo(input: *addrinfo) -> bool;
- unsafe fn rust_uv_is_ipv6_addrinfo(input: *addrinfo) -> bool;
- unsafe fn rust_uv_get_next_addrinfo(input: *addrinfo) -> *addrinfo;
- unsafe fn rust_uv_addrinfo_as_sockaddr_in(input: *addrinfo)
- -> *sockaddr_in;
- unsafe fn rust_uv_addrinfo_as_sockaddr_in6(input: *addrinfo)
- -> *sockaddr_in6;
- unsafe fn rust_uv_malloc_buf_base_of(sug_size: libc::size_t) -> *u8;
- unsafe fn rust_uv_free_base_of_buf(buf: uv_buf_t);
- unsafe fn rust_uv_get_stream_handle_from_connect_req(
- connect_req: *uv_connect_t)
- -> *uv_stream_t;
- unsafe fn rust_uv_get_stream_handle_from_write_req(
- write_req: *uv_write_t)
- -> *uv_stream_t;
- unsafe fn rust_uv_get_loop_for_uv_handle(handle: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_get_data_for_uv_loop(loop_ptr: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_set_data_for_uv_loop(loop_ptr: *libc::c_void,
- data: *libc::c_void);
- unsafe fn rust_uv_get_data_for_uv_handle(handle: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_set_data_for_uv_handle(handle: *libc::c_void,
- data: *libc::c_void);
- unsafe fn rust_uv_get_data_for_req(req: *libc::c_void)
- -> *libc::c_void;
- unsafe fn rust_uv_set_data_for_req(req: *libc::c_void,
- data: *libc::c_void);
- unsafe fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
- unsafe fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> libc::size_t;
-
- // sizeof testing helpers
- unsafe fn rust_uv_helper_uv_tcp_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_connect_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_buf_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_write_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_err_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_sockaddr_in_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_sockaddr_in6_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_async_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_timer_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_uv_getaddrinfo_t_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_addrinfo_size() -> libc::c_uint;
- unsafe fn rust_uv_helper_addr_in_size() -> libc::c_uint;
-}
-
-pub unsafe fn loop_new() -> *libc::c_void {
- return rust_uv_loop_new();
-}
-
-pub unsafe fn loop_delete(loop_handle: *libc::c_void) {
- rust_uv_loop_delete(loop_handle);
-}
-
-pub unsafe fn run(loop_handle: *libc::c_void) {
- rust_uv_run(loop_handle);
-}
-
-pub unsafe fn close<T>(handle: *T, cb: *u8) {
- rust_uv_close(handle as *libc::c_void, cb);
-}
-
-pub unsafe fn walk(loop_handle: *libc::c_void, cb: *u8, arg: *libc::c_void) {
- rust_uv_walk(loop_handle, cb, arg);
-}
-
-pub unsafe fn idle_new() -> *uv_idle_t {
- rust_uv_idle_new()
-}
-
-pub unsafe fn idle_delete(handle: *uv_idle_t) {
- rust_uv_idle_delete(handle)
-}
-
-pub unsafe fn idle_init(loop_handle: *uv_loop_t,
- handle: *uv_idle_t) -> libc::c_int {
- rust_uv_idle_init(loop_handle, handle)
-}
-
-pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> libc::c_int {
- rust_uv_idle_start(handle, cb)
-}
-
-pub unsafe fn idle_stop(handle: *uv_idle_t) -> libc::c_int {
- rust_uv_idle_stop(handle)
-}
-
-pub unsafe fn tcp_init(loop_handle: *libc::c_void, handle: *uv_tcp_t)
- -> libc::c_int {
- return rust_uv_tcp_init(loop_handle, handle);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in,
- after_connect_cb: *u8)
--> libc::c_int {
- return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr,
- after_connect_cb, addr_ptr);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t,
- tcp_handle_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in6,
- after_connect_cb: *u8)
--> libc::c_int {
- return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr,
- after_connect_cb, addr_ptr);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in) -> libc::c_int {
- return rust_uv_tcp_bind(tcp_server_ptr,
- addr_ptr);
-}
-// FIXME ref #2064
-pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in6) -> libc::c_int {
- return rust_uv_tcp_bind6(tcp_server_ptr,
- addr_ptr);
-}
-
-pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in) -> libc::c_int {
- return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
-}
-
-pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t,
- name: *sockaddr_in6) ->libc::c_int {
- return rust_uv_tcp_getpeername6(tcp_handle_ptr, name);
-}
-
-pub unsafe fn listen<T>(stream: *T, backlog: libc::c_int,
- cb: *u8) -> libc::c_int {
- return rust_uv_listen(stream as *libc::c_void, backlog, cb);
-}
-
-pub unsafe fn accept(server: *libc::c_void, client: *libc::c_void)
- -> libc::c_int {
- return rust_uv_accept(server as *libc::c_void,
- client as *libc::c_void);
-}
-
-pub unsafe fn write<T>(req: *uv_write_t, stream: *T,
- buf_in: *~[uv_buf_t], cb: *u8) -> libc::c_int {
- let buf_ptr = vec::raw::to_ptr(*buf_in);
- let buf_cnt = (*buf_in).len() as i32;
- return rust_uv_write(req as *libc::c_void,
- stream as *libc::c_void,
- buf_ptr, buf_cnt, cb);
-}
-pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8,
- on_read: *u8) -> libc::c_int {
- return rust_uv_read_start(stream as *libc::c_void,
- on_alloc, on_read);
-}
-
-pub unsafe fn read_stop(stream: *uv_stream_t) -> libc::c_int {
- return rust_uv_read_stop(stream as *libc::c_void);
-}
-
-pub unsafe fn last_error(loop_handle: *libc::c_void) -> uv_err_t {
- return rust_uv_last_error(loop_handle);
-}
-
-pub unsafe fn strerror(err: *uv_err_t) -> *libc::c_char {
- return rust_uv_strerror(err);
-}
-pub unsafe fn err_name(err: *uv_err_t) -> *libc::c_char {
- return rust_uv_err_name(err);
-}
-
-pub unsafe fn async_init(loop_handle: *libc::c_void,
- async_handle: *uv_async_t,
- cb: *u8) -> libc::c_int {
- return rust_uv_async_init(loop_handle,
- async_handle,
- cb);
-}
-
-pub unsafe fn async_send(async_handle: *uv_async_t) {
- return rust_uv_async_send(async_handle);
-}
-pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
- let out_buf = uv_buf_t { base: ptr::null(), len: 0 as libc::size_t };
- let out_buf_ptr: *uv_buf_t = &out_buf;
- rust_uv_buf_init(out_buf_ptr, input, len as size_t);
- return out_buf;
-}
-pub unsafe fn ip4_addr(ip: &str, port: int) -> sockaddr_in {
- do str::as_c_str(ip) |ip_buf| {
- rust_uv_ip4_addr(ip_buf as *u8,
- port as libc::c_int)
- }
-}
-pub unsafe fn ip6_addr(ip: &str, port: int) -> sockaddr_in6 {
- do str::as_c_str(ip) |ip_buf| {
- rust_uv_ip6_addr(ip_buf as *u8,
- port as libc::c_int)
- }
-}
-pub unsafe fn ip4_name(src: &sockaddr_in) -> ~str {
- // ipv4 addr max size: 15 + 1 trailing null byte
- let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8];
- do dst.as_imm_buf |dst_buf, size| {
- rust_uv_ip4_name(to_unsafe_ptr(src),
- dst_buf, size as libc::size_t);
- // seems that checking the result of uv_ip4_name
- // doesn't work too well..
- // you're stuck looking at the value of dst_buf
- // to see if it is the string representation of
- // INADDR_NONE (0xffffffff or 255.255.255.255 on
- // many platforms)
- str::raw::from_buf(dst_buf)
- }
-}
-pub unsafe fn ip6_name(src: &sockaddr_in6) -> ~str {
- // ipv6 addr max size: 45 + 1 trailing null byte
- let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
- 0u8,0u8,0u8,0u8,0u8,0u8];
- do dst.as_imm_buf |dst_buf, size| {
- let src_unsafe_ptr = to_unsafe_ptr(src);
- let result = rust_uv_ip6_name(src_unsafe_ptr,
- dst_buf, size as libc::size_t);
- match result {
- 0i32 => str::raw::from_buf(dst_buf),
- _ => ~""
- }
- }
-}
-pub unsafe fn ip4_port(src: &sockaddr_in) -> uint {
- rust_uv_ip4_port(to_unsafe_ptr(src)) as uint
-}
-pub unsafe fn ip6_port(src: &sockaddr_in6) -> uint {
- rust_uv_ip6_port(to_unsafe_ptr(src)) as uint
-}
-
-pub unsafe fn timer_init(loop_ptr: *libc::c_void,
- timer_ptr: *uv_timer_t) -> libc::c_int {
- return rust_uv_timer_init(loop_ptr, timer_ptr);
-}
-pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint,
- repeat: uint) -> libc::c_int {
- return rust_uv_timer_start(timer_ptr, cb, timeout as libc::uint64_t,
- repeat as libc::uint64_t);
-}
-pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> libc::c_int {
- return rust_uv_timer_stop(timer_ptr);
-}
-pub unsafe fn getaddrinfo(loop_ptr: *libc::c_void,
- handle: *uv_getaddrinfo_t,
- cb: *u8,
- node_name_ptr: *u8,
- service_name_ptr: *u8,
- hints: *addrinfo) -> libc::c_int {
- rust_uv_getaddrinfo(loop_ptr,
- handle,
- cb,
- node_name_ptr,
- service_name_ptr,
- hints)
-}
-pub unsafe fn freeaddrinfo(res: *addrinfo) {
- rust_uv_freeaddrinfo(res);
-}
-
-// libuv struct initializers
-pub fn tcp_t() -> uv_tcp_t {
- return uv_ll_struct_stubgen::gen_stub_uv_tcp_t();
-}
-pub fn connect_t() -> uv_connect_t {
- return uv_ll_struct_stubgen::gen_stub_uv_connect_t();
-}
-pub fn write_t() -> uv_write_t {
- return uv_ll_struct_stubgen::gen_stub_uv_write_t();
-}
-pub fn async_t() -> uv_async_t {
- return uv_ll_struct_stubgen::gen_stub_uv_async_t();
-}
-pub fn timer_t() -> uv_timer_t {
- return uv_ll_struct_stubgen::gen_stub_uv_timer_t();
-}
-pub fn getaddrinfo_t() -> uv_getaddrinfo_t {
- return uv_ll_struct_stubgen::gen_stub_uv_getaddrinfo_t();
-}
-
-// data access helpers
-pub unsafe fn get_loop_for_uv_handle<T>(handle: *T)
- -> *libc::c_void {
- return rust_uv_get_loop_for_uv_handle(handle as *libc::c_void);
-}
-pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t)
- -> *uv_stream_t {
- return rust_uv_get_stream_handle_from_connect_req(
- connect);
-}
-pub unsafe fn get_stream_handle_from_write_req(
- write_req: *uv_write_t)
- -> *uv_stream_t {
- return rust_uv_get_stream_handle_from_write_req(
- write_req);
-}
-pub unsafe fn get_data_for_uv_loop(loop_ptr: *libc::c_void) -> *libc::c_void {
- rust_uv_get_data_for_uv_loop(loop_ptr)
-}
-pub unsafe fn set_data_for_uv_loop(loop_ptr: *libc::c_void,
- data: *libc::c_void) {
- rust_uv_set_data_for_uv_loop(loop_ptr, data);
-}
-pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *libc::c_void {
- return rust_uv_get_data_for_uv_handle(handle as *libc::c_void);
-}
-pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
- rust_uv_set_data_for_uv_handle(handle as *libc::c_void,
- data as *libc::c_void);
-}
-pub unsafe fn get_data_for_req<T>(req: *T) -> *libc::c_void {
- return rust_uv_get_data_for_req(req as *libc::c_void);
-}
-pub unsafe fn set_data_for_req<T, U>(req: *T,
- data: *U) {
- rust_uv_set_data_for_req(req as *libc::c_void,
- data as *libc::c_void);
-}
-pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
- return rust_uv_get_base_from_buf(buf);
-}
-pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> libc::size_t {
- return rust_uv_get_len_from_buf(buf);
-}
-pub unsafe fn malloc_buf_base_of(suggested_size: libc::size_t)
- -> *u8 {
- return rust_uv_malloc_buf_base_of(suggested_size);
-}
-pub unsafe fn free_base_of_buf(buf: uv_buf_t) {
- rust_uv_free_base_of_buf(buf);
-}
-
-pub unsafe fn get_last_err_info(uv_loop: *libc::c_void) -> ~str {
- let err = last_error(uv_loop);
- let err_ptr: *uv_err_t = &err;
- let err_name = str::raw::from_c_str(err_name(err_ptr));
- let err_msg = str::raw::from_c_str(strerror(err_ptr));
- return fmt!("LIBUV ERROR: name: %s msg: %s",
- err_name, err_msg);
-}
-
-pub unsafe fn get_last_err_data(uv_loop: *libc::c_void) -> uv_err_data {
- let err = last_error(uv_loop);
- let err_ptr: *uv_err_t = &err;
- let err_name = str::raw::from_c_str(err_name(err_ptr));
- let err_msg = str::raw::from_c_str(strerror(err_ptr));
- uv_err_data { err_name: err_name, err_msg: err_msg }
-}
-
-pub struct uv_err_data {
- err_name: ~str,
- err_msg: ~str,
-}
-
-pub unsafe fn is_ipv4_addrinfo(input: *addrinfo) -> bool {
- rust_uv_is_ipv4_addrinfo(input)
-}
-pub unsafe fn is_ipv6_addrinfo(input: *addrinfo) -> bool {
- rust_uv_is_ipv6_addrinfo(input)
-}
-pub unsafe fn get_INADDR_NONE() -> u32 {
- rust_uv_helper_get_INADDR_NONE()
-}
-pub unsafe fn get_next_addrinfo(input: *addrinfo) -> *addrinfo {
- rust_uv_get_next_addrinfo(input)
-}
-pub unsafe fn addrinfo_as_sockaddr_in(input: *addrinfo) -> *sockaddr_in {
- rust_uv_addrinfo_as_sockaddr_in(input)
-}
-pub unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 {
- rust_uv_addrinfo_as_sockaddr_in6(input)
-}
-
-#[cfg(test)]
-mod test {
-
- use super::*;
-
- use std::comm::{SharedChan, stream, GenericChan, GenericPort};
- use std::libc;
- use std::str;
- use std::sys;
- use std::task;
- use std::vec;
-
- enum tcp_read_data {
- tcp_read_eof,
- tcp_read_more(~[u8]),
- tcp_read_error
- }
-
- struct request_wrapper {
- write_req: *uv_write_t,
- req_buf: *~[uv_buf_t],
- read_chan: SharedChan<~str>,
- }
-
- extern fn after_close_cb(handle: *libc::c_void) {
- debug!("after uv_close! handle ptr: %?",
- handle);
- }
-
- extern fn on_alloc_cb(handle: *libc::c_void,
- suggested_size: libc::size_t)
- -> uv_buf_t {
- unsafe {
- debug!(~"on_alloc_cb!");
- let char_ptr = malloc_buf_base_of(suggested_size);
- debug!("on_alloc_cb h: %? char_ptr: %u sugsize: %u",
- handle,
- char_ptr as uint,
- suggested_size as uint);
- return buf_init(char_ptr, suggested_size as uint);
- }
- }
-
- extern fn on_read_cb(stream: *uv_stream_t,
- nread: libc::ssize_t,
- buf: uv_buf_t) {
- unsafe {
- let nread = nread as int;
- debug!("CLIENT entering on_read_cb nred: %d",
- nread);
- if (nread > 0) {
- // we have data
- debug!("CLIENT read: data! nread: %d", nread);
- read_stop(stream);
- let client_data =
- get_data_for_uv_handle(stream as *libc::c_void)
- as *request_wrapper;
- let buf_base = get_base_from_buf(buf);
- let bytes = vec::from_buf(buf_base, nread as uint);
- let read_chan = (*client_data).read_chan.clone();
- let msg_from_server = str::from_bytes(bytes);
- read_chan.send(msg_from_server);
- close(stream as *libc::c_void, after_close_cb)
- }
- else if (nread == -1) {
- // err .. possibly EOF
- debug!(~"read: eof!");
- }
- else {
- // nread == 0 .. do nothing, just free buf as below
- debug!(~"read: do nothing!");
- }
- // when we're done
- free_base_of_buf(buf);
- debug!(~"CLIENT exiting on_read_cb");
- }
- }
-
- extern fn on_write_complete_cb(write_req: *uv_write_t,
- status: libc::c_int) {
- unsafe {
- debug!(
- "CLIENT beginning on_write_complete_cb status: %d",
- status as int);
- let stream = get_stream_handle_from_write_req(write_req);
- debug!(
- "CLIENT on_write_complete_cb: tcp:%d write_handle:%d",
- stream as int, write_req as int);
- let result = read_start(stream, on_alloc_cb, on_read_cb);
- debug!("CLIENT ending on_write_complete_cb .. status: %d",
- result as int);
- }
- }
-
- extern fn on_connect_cb(connect_req_ptr: *uv_connect_t,
- status: libc::c_int) {
- unsafe {
- debug!("beginning on_connect_cb .. status: %d",
- status as int);
- let stream =
- get_stream_handle_from_connect_req(connect_req_ptr);
- if (status == 0i32) {
- debug!(~"on_connect_cb: in status=0 if..");
- let client_data = get_data_for_req(
- connect_req_ptr as *libc::c_void)
- as *request_wrapper;
- let write_handle = (*client_data).write_req;
- debug!("on_connect_cb: tcp: %d write_hdl: %d",
- stream as int, write_handle as int);
- let write_result = write(write_handle,
- stream as *libc::c_void,
- (*client_data).req_buf,
- on_write_complete_cb);
- debug!("on_connect_cb: write() status: %d",
- write_result as int);
- }
- else {
- let test_loop = get_loop_for_uv_handle(
- stream as *libc::c_void);
- let err_msg = get_last_err_info(test_loop);
- debug!(err_msg);
- assert!(false);
- }
- debug!(~"finishing on_connect_cb");
- }
- }
-
- fn impl_uv_tcp_request(ip: &str, port: int, req_str: &str,
- client_chan: SharedChan<~str>) {
- unsafe {
- let test_loop = loop_new();
- let tcp_handle = tcp_t();
- let tcp_handle_ptr: *uv_tcp_t = &tcp_handle;
- let connect_handle = connect_t();
- let connect_req_ptr: *uv_connect_t = &connect_handle;
-
- // this is the persistent payload of data that we
- // need to pass around to get this example to work.
- // In C, this would be a malloc'd or stack-allocated
- // struct that we'd cast to a void* and store as the
- // data field in our uv_connect_t struct
- let req_str_bytes = req_str.as_bytes();
- let req_msg_ptr: *u8 = vec::raw::to_ptr(req_str_bytes);
- debug!("req_msg ptr: %u", req_msg_ptr as uint);
- let req_msg = ~[
- buf_init(req_msg_ptr, req_str_bytes.len())
- ];
- // this is the enclosing record, we'll pass a ptr to
- // this to C..
- let write_handle = write_t();
- let write_handle_ptr: *uv_write_t = &write_handle;
- debug!("tcp req: tcp stream: %d write_handle: %d",
- tcp_handle_ptr as int,
- write_handle_ptr as int);
- let client_data = request_wrapper {
- write_req: write_handle_ptr,
- req_buf: &req_msg,
- read_chan: client_chan
- };
-
- let tcp_init_result = tcp_init(test_loop as *libc::c_void,
- tcp_handle_ptr);
- if (tcp_init_result == 0) {
- debug!(~"successful tcp_init_result");
-
- debug!(~"building addr...");
- let addr = ip4_addr(ip, port);
- // FIXME ref #2064
- let addr_ptr: *sockaddr_in = &addr;
- debug!("after build addr in rust. port: %u",
- addr.sin_port as uint);
-
- // this should set up the connection request..
- debug!("b4 call tcp_connect connect cb: %u ",
- on_connect_cb as uint);
- let tcp_connect_result = tcp_connect(connect_req_ptr,
- tcp_handle_ptr,
- addr_ptr,
- on_connect_cb);
- if (tcp_connect_result == 0) {
- // not set the data on the connect_req
- // until its initialized
- set_data_for_req(connect_req_ptr as *libc::c_void,
- &client_data);
- set_data_for_uv_handle(tcp_handle_ptr as *libc::c_void,
- &client_data);
- debug!(~"before run tcp req loop");
- run(test_loop);
- debug!(~"after run tcp req loop");
- }
- else {
- debug!(~"tcp_connect() failure");
- assert!(false);
- }
- }
- else {
- debug!(~"tcp_init() failure");
- assert!(false);
- }
- loop_delete(test_loop);
- }
- }
-
- extern fn server_after_close_cb(handle: *libc::c_void) {
- debug!("SERVER server stream closed, should exit. h: %?",
- handle);
- }
-
- extern fn client_stream_after_close_cb(handle: *libc::c_void) {
- unsafe {
- debug!(~"SERVER: closed client stream, now closing server stream");
- let client_data = get_data_for_uv_handle(
- handle) as
- *tcp_server_data;
- close((*client_data).server as *libc::c_void,
- server_after_close_cb);
- }
- }
-
- extern fn after_server_resp_write(req: *uv_write_t) {
- unsafe {
- let client_stream_ptr =
- get_stream_handle_from_write_req(req);
- debug!(~"SERVER: resp sent... closing client stream");
- close(client_stream_ptr as *libc::c_void,
- client_stream_after_close_cb)
- }
- }
-
- extern fn on_server_read_cb(client_stream_ptr: *uv_stream_t,
- nread: libc::ssize_t,
- buf: uv_buf_t) {
- unsafe {
- let nread = nread as int;
- if (nread > 0) {
- // we have data
- debug!("SERVER read: data! nread: %d", nread);
-
- // pull out the contents of the write from the client
- let buf_base = get_base_from_buf(buf);
- let buf_len = get_len_from_buf(buf) as uint;
- debug!("SERVER buf base: %u, len: %u, nread: %d",
- buf_base as uint,
- buf_len as uint,
- nread);
- let bytes = vec::from_buf(buf_base, nread as uint);
- let request_str = str::from_bytes(bytes);
-
- let client_data = get_data_for_uv_handle(
- client_stream_ptr as *libc::c_void) as *tcp_server_data;
-
- let server_kill_msg = (*client_data).server_kill_msg.clone();
- let write_req = (*client_data).server_write_req;
- if request_str.contains(server_kill_msg) {
- debug!(~"SERVER: client req contains kill_msg!");
- debug!(~"SERVER: sending response to client");
- read_stop(client_stream_ptr);
- let server_chan = (*client_data).server_chan.clone();
- server_chan.send(request_str);
- let write_result = write(
- write_req,
- client_stream_ptr as *libc::c_void,
- (*client_data).server_resp_buf,
- after_server_resp_write);
- debug!("SERVER: resp write result: %d",
- write_result as int);
- if (write_result != 0i32) {
- debug!(~"bad result for server resp write()");
- debug!(get_last_err_info(
- get_loop_for_uv_handle(client_stream_ptr
- as *libc::c_void)));
- assert!(false);
- }
- }
- else {
- debug!(~"SERVER: client req !contain kill_msg!");
- }
- }
- else if (nread == -1) {
- // err .. possibly EOF
- debug!(~"read: eof!");
- }
- else {
- // nread == 0 .. do nothing, just free buf as below
- debug!(~"read: do nothing!");
- }
- // when we're done
- free_base_of_buf(buf);
- debug!(~"SERVER exiting on_read_cb");
- }
- }
-
- extern fn server_connection_cb(server_stream_ptr:
- *uv_stream_t,
- status: libc::c_int) {
- unsafe {
- debug!(~"client connecting!");
- let test_loop = get_loop_for_uv_handle(
- server_stream_ptr as *libc::c_void);
- if status != 0i32 {
- let err_msg = get_last_err_info(test_loop);
- debug!("server_connect_cb: non-zero status: %?",
- err_msg);
- return;
- }
- let server_data = get_data_for_uv_handle(
- server_stream_ptr as *libc::c_void) as *tcp_server_data;
- let client_stream_ptr = (*server_data).client;
- let client_init_result = tcp_init(test_loop,
- client_stream_ptr);
- set_data_for_uv_handle(
- client_stream_ptr as *libc::c_void,
- server_data as *libc::c_void);
- if (client_init_result == 0i32) {
- debug!(~"successfully initialized client stream");
- let accept_result = accept(server_stream_ptr as
- *libc::c_void,
- client_stream_ptr as
- *libc::c_void);
- if (accept_result == 0i32) {
- // start reading
- let read_result = read_start(
- client_stream_ptr as *uv_stream_t,
- on_alloc_cb,
- on_server_read_cb);
- if (read_result == 0i32) {
- debug!(~"successful server read start");
- }
- else {
- debug!("server_connection_cb: bad read:%d",
- read_result as int);
- assert!(false);
- }
- }
- else {
- debug!("server_connection_cb: bad accept: %d",
- accept_result as int);
- assert!(false);
- }
- }
- else {
- debug!("server_connection_cb: bad client init: %d",
- client_init_result as int);
- assert!(false);
- }
- }
- }
-
- struct tcp_server_data {
- client: *uv_tcp_t,
- server: *uv_tcp_t,
- server_kill_msg: ~str,
- server_resp_buf: *~[uv_buf_t],
- server_chan: SharedChan<~str>,
- server_write_req: *uv_write_t,
- }
-
- struct async_handle_data {
- continue_chan: SharedChan<bool>,
- }
-
- extern fn async_close_cb(handle: *libc::c_void) {
- debug!("SERVER: closing async cb... h: %?",
- handle);
- }
-
- extern fn continue_async_cb(async_handle: *uv_async_t,
- status: libc::c_int) {
- unsafe {
- // once we're in the body of this callback,
- // the tcp server's loop is set up, so we
- // can continue on to let the tcp client
- // do its thang
- let data = get_data_for_uv_handle(
- async_handle as *libc::c_void) as *async_handle_data;
- let continue_chan = (*data).continue_chan.clone();
- let should_continue = status == 0i32;
- continue_chan.send(should_continue);
- close(async_handle as *libc::c_void, async_close_cb);
- }
- }
-
- fn impl_uv_tcp_server(server_ip: &str,
- server_port: int,
- kill_server_msg: ~str,
- server_resp_msg: ~str,
- server_chan: SharedChan<~str>,
- continue_chan: SharedChan<bool>) {
- unsafe {
- let test_loop = loop_new();
- let tcp_server = tcp_t();
- let tcp_server_ptr: *uv_tcp_t = &tcp_server;
-
- let tcp_client = tcp_t();
- let tcp_client_ptr: *uv_tcp_t = &tcp_client;
-
- let server_write_req = write_t();
- let server_write_req_ptr: *uv_write_t = &server_write_req;
-
- let resp_str_bytes = server_resp_msg.as_bytes();
- let resp_msg_ptr: *u8 = vec::raw::to_ptr(resp_str_bytes);
- debug!("resp_msg ptr: %u", resp_msg_ptr as uint);
- let resp_msg = ~[
- buf_init(resp_msg_ptr, resp_str_bytes.len())
- ];
-
- let continue_async_handle = async_t();
- let continue_async_handle_ptr: *uv_async_t =
- &continue_async_handle;
- let async_data =
- async_handle_data { continue_chan: continue_chan };
- let async_data_ptr: *async_handle_data = &async_data;
-
- let server_data = tcp_server_data {
- client: tcp_client_ptr,
- server: tcp_server_ptr,
- server_kill_msg: kill_server_msg,
- server_resp_buf: &resp_msg,
- server_chan: server_chan,
- server_write_req: server_write_req_ptr
- };
- let server_data_ptr: *tcp_server_data = &server_data;
- set_data_for_uv_handle(tcp_server_ptr as *libc::c_void,
- server_data_ptr as *libc::c_void);
-
- // uv_tcp_init()
- let tcp_init_result = tcp_init(
- test_loop as *libc::c_void, tcp_server_ptr);
- if (tcp_init_result == 0i32) {
- let server_addr = ip4_addr(server_ip, server_port);
- // FIXME ref #2064
- let server_addr_ptr: *sockaddr_in = &server_addr;
-
- // uv_tcp_bind()
- let bind_result = tcp_bind(tcp_server_ptr, server_addr_ptr);
- if (bind_result == 0i32) {
- debug!(~"successful uv_tcp_bind, listening");
-
- // uv_listen()
- let listen_result = listen(tcp_server_ptr as
- *libc::c_void,
- 128i32,
- server_connection_cb);
- if (listen_result == 0i32) {
- // let the test know it can set up the tcp server,
- // now.. this may still present a race, not sure..
- let async_result = async_init(test_loop,
- continue_async_handle_ptr,
- continue_async_cb);
- if (async_result == 0i32) {
- set_data_for_uv_handle(
- continue_async_handle_ptr as *libc::c_void,
- async_data_ptr as *libc::c_void);
- async_send(continue_async_handle_ptr);
- // uv_run()
- run(test_loop);
- debug!(~"server uv::run() has returned");
- }
- else {
- debug!("uv_async_init failure: %d",
- async_result as int);
- assert!(false);
- }
- }
- else {
- debug!("non-zero result on uv_listen: %d",
- listen_result as int);
- assert!(false);
- }
- }
- else {
- debug!("non-zero result on uv_tcp_bind: %d",
- bind_result as int);
- assert!(false);
- }
- }
- else {
- debug!("non-zero result on uv_tcp_init: %d",
- tcp_init_result as int);
- assert!(false);
- }
- loop_delete(test_loop);
- }
- }
-
- // this is the impl for a test that is (maybe) ran on a
- // per-platform/arch basis below
- pub fn impl_uv_tcp_server_and_request() {
- let bind_ip = ~"0.0.0.0";
- let request_ip = ~"127.0.0.1";
- let port = 8886;
- let kill_server_msg = ~"does a dog have buddha nature?";
- let server_resp_msg = ~"mu!";
- let (client_port, client_chan) = stream::<~str>();
- let client_chan = SharedChan::new(client_chan);
- let (server_port, server_chan) = stream::<~str>();
- let server_chan = SharedChan::new(server_chan);
-
- let (continue_port, continue_chan) = stream::<bool>();
- let continue_chan = SharedChan::new(continue_chan);
-
- let kill_server_msg_copy = kill_server_msg.clone();
- let server_resp_msg_copy = server_resp_msg.clone();
- do task::spawn_sched(task::ManualThreads(1)) {
- impl_uv_tcp_server(bind_ip, port,
- kill_server_msg_copy.clone(),
- server_resp_msg_copy.clone(),
- server_chan.clone(),
- continue_chan.clone());
- };
-
- // block until the server up is.. possibly a race?
- debug!(~"before receiving on server continue_port");
- continue_port.recv();
- debug!(~"received on continue port, set up tcp client");
-
- let kill_server_msg_copy = kill_server_msg.clone();
- do task::spawn_sched(task::ManualThreads(1u)) {
- impl_uv_tcp_request(request_ip, port,
- kill_server_msg_copy,
- client_chan.clone());
- };
-
- let msg_from_client = server_port.recv();
- let msg_from_server = client_port.recv();
-
- assert!(msg_from_client.contains(kill_server_msg));
- assert!(msg_from_server.contains(server_resp_msg));
- }
-
- // FIXME don't run on fbsd or linux 32 bit(#2064)
- #[cfg(target_os="win32")]
- #[cfg(target_os="darwin")]
- #[cfg(target_os="linux")]
- #[cfg(target_os="android")]
- mod tcp_and_server_client_test {
- #[cfg(target_arch="x86_64")]
- mod impl64 {
- #[test]
- fn test_uv_ll_tcp_server_and_request() {
- super::super::impl_uv_tcp_server_and_request();
- }
- }
- #[cfg(target_arch="x86")]
- #[cfg(target_arch="arm")]
- #[cfg(target_arch="mips")]
- mod impl32 {
- #[test]
- #[ignore(cfg(target_os = "linux"))]
- fn test_uv_ll_tcp_server_and_request() {
- unsafe {
- super::super::impl_uv_tcp_server_and_request();
- }
- }
- }
- }
-
- fn struct_size_check_common<TStruct>(t_name: ~str,
- foreign_size: libc::c_uint) {
- let rust_size = sys::size_of::<TStruct>();
- let sizes_match = foreign_size as uint == rust_size;
- if !sizes_match {
- let output = fmt!(
- "STRUCT_SIZE FAILURE: %s -- actual: %u expected: %u",
- t_name, rust_size, foreign_size as uint);
- debug!(output);
- }
- assert!(sizes_match);
- }
-
- // struct size tests
- #[test]
- fn test_uv_ll_struct_size_uv_tcp_t() {
- unsafe {
- struct_size_check_common::<uv_tcp_t>(
- ~"uv_tcp_t",
- super::rust_uv_helper_uv_tcp_t_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_uv_connect_t() {
- unsafe {
- struct_size_check_common::<uv_connect_t>(
- ~"uv_connect_t",
- super::rust_uv_helper_uv_connect_t_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_uv_buf_t() {
- unsafe {
- struct_size_check_common::<uv_buf_t>(
- ~"uv_buf_t",
- super::rust_uv_helper_uv_buf_t_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_uv_write_t() {
- unsafe {
- struct_size_check_common::<uv_write_t>(
- ~"uv_write_t",
- super::rust_uv_helper_uv_write_t_size()
- );
- }
- }
-
- #[test]
- fn test_uv_ll_struct_size_sockaddr_in() {
- unsafe {
- struct_size_check_common::<sockaddr_in>(
- ~"sockaddr_in",
- super::rust_uv_helper_sockaddr_in_size()
- );
- }
- }
- #[test]
- fn test_uv_ll_struct_size_sockaddr_in6() {
- unsafe {
- let foreign_handle_size =
- super::rust_uv_helper_sockaddr_in6_size();
- let rust_handle_size = sys::size_of::<sockaddr_in6>();
- let output = fmt!("sockaddr_in6 -- foreign: %u rust: %u",
- foreign_handle_size as uint, rust_handle_size);
- debug!(output);
- // FIXME #1645 .. rust appears to pad structs to the nearest
- // byte..?
- // .. can't get the uv::ll::sockaddr_in6 to == 28 :/
- // .. so the type always appears to be 32 in size.. which is
- // good, i guess.. better too big than too little
- assert!((4u+foreign_handle_size as uint) ==
- rust_handle_size);
- }
- }
- #[test]
- #[ignore(reason = "questionable size calculations")]
- fn test_uv_ll_struct_size_addr_in() {
- unsafe {
- let foreign_handle_size =
- super::rust_uv_helper_addr_in_size();
- let rust_handle_size = sys::size_of::<addr_in>();
- let output = fmt!("addr_in -- foreign: %u rust: %u",
- foreign_handle_size as uint, rust_handle_size);
- debug!(output);
- // FIXME #1645 .. see note above about struct padding
- assert!((4u+foreign_handle_size as uint) ==
- rust_handle_size);
- }
- }
-
- #[test]
- fn test_uv_ll_struct_size_uv_async_t() {
- unsafe {
- struct_size_check_common::<uv_async_t>(
- ~"uv_async_t",
- super::rust_uv_helper_uv_async_t_size()
- );
- }
- }
-
- #[test]
- fn test_uv_ll_struct_size_uv_timer_t() {
- unsafe {
- struct_size_check_common::<uv_timer_t>(
- ~"uv_timer_t",
- super::rust_uv_helper_uv_timer_t_size()
- );
- }
- }
-
- #[test]
- #[ignore(cfg(target_os = "win32"))]
- fn test_uv_ll_struct_size_uv_getaddrinfo_t() {
- unsafe {
- struct_size_check_common::<uv_getaddrinfo_t>(
- ~"uv_getaddrinfo_t",
- super::rust_uv_helper_uv_getaddrinfo_t_size()
- );
- }
- }
- #[test]
- #[ignore(cfg(target_os = "macos"))]
- #[ignore(cfg(target_os = "win32"))]
- fn test_uv_ll_struct_size_addrinfo() {
- unsafe {
- struct_size_check_common::<uv_timer_t>(
- ~"addrinfo",
- super::rust_uv_helper_uv_timer_t_size()
- );
- }
- }
-}
use metadata::cstore;
use std::cast;
- #[cfg(not(stage0))]
use std::local_data;
use std::unstable::intrinsics;
// The stage1 compiler won't work, but that doesn't really matter. TLS
// changed only very recently to allow storage of owned values.
- #[cfg(not(stage0))]
static engine_key: local_data::Key<~Engine> = &local_data::Key;
- #[cfg(not(stage0))]
fn set_engine(engine: ~Engine) {
local_data::set(engine_key, engine)
}
- #[cfg(stage0)]
- fn set_engine(_: ~Engine) {}
- #[cfg(not(stage0))]
pub fn consume_engine() -> Option<~Engine> {
local_data::pop(engine_key)
}
- #[cfg(stage0)]
- pub fn consume_engine() -> Option<~Engine> { None }
}
pub mod write {
*/
pub fn build_link_meta(sess: Session,
- c: &ast::crate,
+ c: &ast::Crate,
output: &Path,
symbol_hasher: &mut hash::State)
-> LinkMeta {
cmh_items: ~[@ast::MetaItem]
}
- fn provided_link_metas(sess: Session, c: &ast::crate) ->
+ fn provided_link_metas(sess: Session, c: &ast::Crate) ->
ProvidedMetas {
let mut name = None;
let mut vers = None;
let mut cmh_items = ~[];
- let linkage_metas = attr::find_linkage_metas(c.node.attrs);
+ let linkage_metas = attr::find_linkage_metas(c.attrs);
attr::require_unique_names(sess.diagnostic(), linkage_metas);
for linkage_metas.iter().advance |meta| {
match meta.name_str_pair() {
}
pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
- ast::crate_cfg {
+ ast::CrateConfig {
let (libc, tos) = match sess.targ_cfg.os {
session::os_win32 => (@"msvcrt.dll", @"win32"),
session::os_macos => (@"libc.dylib", @"macos"),
mk(@"build_input", source_name(input))];
}
-pub fn append_configuration(cfg: &mut ast::crate_cfg, name: @str) {
+pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
if !cfg.iter().any(|mi| mi.name() == name) {
cfg.push(attr::mk_word_item(name))
}
}
pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
- ast::crate_cfg {
+ ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
let default_cfg = default_configuration(sess, argv0, input);
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
fn parse_cfgspecs(cfgspecs: ~[~str],
- demitter: diagnostic::Emitter) -> ast::crate_cfg {
+ demitter: diagnostic::Emitter) -> ast::CrateConfig {
do cfgspecs.consume_iter().transform |s| {
let sess = parse::new_parse_sess(Some(demitter));
parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
- }.collect::<ast::crate_cfg>()
+ }.collect::<ast::CrateConfig>()
}
pub enum input {
str_input(@str)
}
-pub fn parse_input(sess: Session, cfg: ast::crate_cfg, input: &input)
- -> @ast::crate {
+pub fn parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
+ -> @ast::Crate {
match *input {
file_input(ref file) => {
parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess)
#[fixed_stack_segment]
pub fn compile_rest(sess: Session,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
phases: compile_upto,
outputs: Option<@OutputFilenames>,
- curr: Option<@ast::crate>)
- -> (Option<@ast::crate>, Option<ty::ctxt>) {
+ curr: Option<@ast::Crate>)
+ -> (Option<@ast::Crate>, Option<ty::ctxt>) {
let time_passes = sess.time_passes();
}
pub fn compile_upto(sess: Session,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
input: &input,
upto: compile_phase,
outputs: Option<@OutputFilenames>)
- -> (Option<@ast::crate>, Option<ty::ctxt>) {
+ -> (Option<@ast::Crate>, Option<ty::ctxt>) {
let time_passes = sess.time_passes();
let crate = time(time_passes,
~"parsing",
Some(crate))
}
-pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input,
+pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
outdir: &Option<Path>, output: &Option<Path>) {
let upto = if sess.opts.parse_only { cu_parse }
else if sess.opts.no_trans { cu_no_trans }
compile_upto(sess, cfg, input, upto, Some(outputs));
}
-pub fn pretty_print_input(sess: Session, cfg: ast::crate_cfg, input: &input,
+pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
ppm: pp_mode) {
fn ann_paren_for_expr(node: pprust::ann_node) {
match node {
// items to the crate config, and during parsing the entire crate config
// will be added to the crate AST node. This should not be used for
// anything except building the full crate config prior to parsing.
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
binary: @str,
test: bool,
parse_only: bool,
}
pub fn building_library(req_crate_type: crate_type,
- crate: &ast::crate,
+ crate: &ast::Crate,
testing: bool) -> bool {
match req_crate_type {
bin_crate => false,
false
} else {
match syntax::attr::first_attr_value_str_by_name(
- crate.node.attrs,
+ crate.attrs,
"crate_type") {
Some(s) => "lib" == s,
_ => false
attr::mk_attr(attr::mk_name_value_item_str(@"crate_type", t))
}
- fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate {
+ fn make_crate(with_bin: bool, with_lib: bool) -> @ast::Crate {
let mut attrs = ~[];
if with_bin {
attrs.push(make_crate_type_attr(@"bin"));
if with_lib {
attrs.push(make_crate_type_attr(@"lib"));
}
- @codemap::respan(codemap::dummy_sp(), ast::crate_ {
+ @ast::Crate {
module: ast::_mod { view_items: ~[], items: ~[] },
attrs: attrs,
- config: ~[]
- })
+ config: ~[],
+ span: codemap::dummy_sp(),
+ }
}
#[test]
// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate {
+pub fn strip_unconfigured_items(crate: @ast::Crate) -> @ast::Crate {
do strip_items(crate) |attrs| {
- in_cfg(crate.node.config, attrs)
+ in_cfg(crate.config, attrs)
}
}
-pub fn strip_items(crate: &ast::crate, in_cfg: in_cfg_pred)
- -> @ast::crate {
+pub fn strip_items(crate: &ast::Crate, in_cfg: in_cfg_pred)
+ -> @ast::Crate {
let ctxt = @Context { in_cfg: in_cfg };
fn fold_block(
cx: @Context,
- b: &ast::blk,
+ b: &ast::Block,
fld: @fold::ast_fold
-) -> ast::blk {
+) -> ast::Block {
let resulting_stmts = do b.stmts.iter().filter_map |a| {
filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt))
}.collect();
let filtered_view_items = do b.view_items.iter().filter_map |a| {
filter_view_item(cx, a).map(|&x| fld.fold_view_item(x))
}.collect();
- ast::blk {
+ ast::Block {
view_items: filtered_view_items,
stmts: resulting_stmts,
expr: b.expr.map(|x| fld.fold_expr(*x)),
static STD_VERSION: &'static str = "0.8-pre";
-pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::crate)
- -> @ast::crate {
+pub fn maybe_inject_libstd_ref(sess: Session, crate: @ast::Crate)
+ -> @ast::Crate {
if use_std(crate) {
inject_libstd_ref(sess, crate)
} else {
}
}
-fn use_std(crate: &ast::crate) -> bool {
- !attr::contains_name(crate.node.attrs, "no_std")
+fn use_std(crate: &ast::Crate) -> bool {
+ !attr::contains_name(crate.attrs, "no_std")
}
+
fn no_prelude(attrs: &[ast::Attribute]) -> bool {
attr::contains_name(attrs, "no_implicit_prelude")
}
-fn inject_libstd_ref(sess: Session, crate: &ast::crate) -> @ast::crate {
+fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
fn spanned<T>(x: T) -> codemap::spanned<T> {
codemap::spanned { node: x, span: dummy_sp() }
}
let precursor = @fold::AstFoldFns {
- fold_crate: |crate, span, fld| {
+ fold_crate: |crate, fld| {
let n1 = sess.next_node_id();
let vi1 = ast::view_item {
node: ast::view_item_extern_mod(
}
// FIXME #2543: Bad copy.
- let new_crate = ast::crate_ {
+ ast::Crate {
module: new_module,
..(*crate).clone()
- };
- (new_crate, span)
+ }
},
fold_item: |item, fld| {
if !no_prelude(item.attrs) {
struct TestCtxt {
sess: session::Session,
- crate: @ast::crate,
+ crate: @ast::Crate,
path: ~[ast::ident],
ext_cx: @ExtCtxt,
testfns: ~[Test]
// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
pub fn modify_for_testing(sess: session::Session,
- crate: @ast::crate)
- -> @ast::crate {
+ crate: @ast::Crate)
+ -> @ast::Crate {
// We generate the test harness when building in the 'test'
// configuration, either with the '--test' or '--cfg test'
// command line options.
- let should_test = attr::contains_name(crate.node.config, "test");
+ let should_test = attr::contains_name(crate.config, "test");
if should_test {
generate_test_harness(sess, crate)
}
fn generate_test_harness(sess: session::Session,
- crate: @ast::crate)
- -> @ast::crate {
+ crate: @ast::Crate)
+ -> @ast::Crate {
let cx: @mut TestCtxt = @mut TestCtxt {
sess: sess,
crate: crate,
});
let precursor = @fold::AstFoldFns {
- fold_crate: fold::wrap(|a,b| fold_crate(cx, a, b) ),
+ fold_crate: |a,b| fold_crate(cx, a, b),
fold_item: |a,b| fold_item(cx, a, b),
fold_mod: |a,b| fold_mod(cx, a, b),.. *fold::default_ast_fold()};
return res;
}
-fn strip_test_functions(crate: &ast::crate) -> @ast::crate {
+fn strip_test_functions(crate: &ast::Crate) -> @ast::Crate {
// When not compiling with --test we should not compile the
// #[test] functions
do config::strip_items(crate) |attrs| {
fold::noop_fold_mod(&mod_nomain, fld)
}
-fn fold_crate(cx: @mut TestCtxt, c: &ast::crate_, fld: @fold::ast_fold)
- -> ast::crate_ {
+fn fold_crate(cx: @mut TestCtxt, c: &ast::Crate, fld: @fold::ast_fold)
+ -> ast::Crate {
let folded = fold::noop_fold_crate(c, fld);
// Add a special __test module to the crate that will contain code
// generated for the test harness
- ast::crate_ {
+ ast::Crate {
module: add_test_module(cx, &folded.module),
.. folded
}
do i.attrs.iter().any |attr| {
// check ignore(cfg(foo, bar))
"ignore" == attr.name() && match attr.meta_item_list() {
- Some(ref cfgs) => attr::test_cfg(cx.crate.node.config, cfgs.iter().transform(|x| *x)),
+ Some(ref cfgs) => attr::test_cfg(cx.crate.config, cfgs.iter().transform(|x| *x)),
None => true
}
}
}
fn is_extra(cx: &TestCtxt) -> bool {
- let items = attr::find_linkage_metas(cx.crate.node.attrs);
+ let items = attr::find_linkage_metas(cx.crate.attrs);
match attr::last_meta_item_value_str_by_name(items, "name") {
Some(s) if "extra" == s => true,
_ => false
pub unsafe fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef;
#[fast_ffi]
pub unsafe fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef;
+ #[fast_ffi]
+ pub unsafe fn LLVMInstructionEraseFromParent(Inst: ValueRef);
/* Operations on call sites */
#[fast_ffi]
// Traverses an AST, reading all the information about use'd crates and extern
// libraries necessary for later resolving, typechecking, linking, etc.
pub fn read_crates(diag: @span_handler,
- crate: &ast::crate,
+ crate: &ast::Crate,
cstore: @mut cstore::CStore,
filesearch: @FileSearch,
os: loader::os,
os: loader::os,
statik: bool,
crate_cache: @mut ~[cache_entry],
- next_crate_num: ast::crate_num,
+ next_crate_num: ast::CrateNum,
intr: @ident_interner
}
-fn visit_crate(e: &Env, c: &ast::crate) {
+fn visit_crate(e: &Env, c: &ast::Crate) {
let cstore = e.cstore;
- for c.node.attrs.iter().filter(|m| "link_args" == m.name()).advance |a| {
+ for c.attrs.iter().filter(|m| "link_args" == m.name()).advance |a| {
match a.value_str() {
Some(ref linkarg) => {
cstore::add_used_link_args(cstore, *linkarg);
metas: ~[@ast::MetaItem],
hash: @str,
span: span)
- -> ast::crate_num {
+ -> ast::CrateNum {
let metas = metas_with_ident(token::ident_to_str(&ident), metas);
match existing_match(e, metas, hash) {
/// Iterates over all the language items in the given crate.
pub fn each_lang_item(cstore: @mut cstore::CStore,
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
f: &fn(ast::node_id, uint) -> bool) -> bool {
let crate_data = cstore::get_crate_data(cstore, cnum);
decoder::each_lang_item(crate_data, f)
/// Iterates over all the paths in the given crate.
pub fn each_path(cstore: @mut cstore::CStore,
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
f: &fn(&str, decoder::def_like, ast::visibility) -> bool)
-> bool {
let crate_data = cstore::get_crate_data(cstore, cnum);
}
pub fn get_link_args_for_crate(cstore: @mut cstore::CStore,
- crate_num: ast::crate_num)
+ crate_num: ast::CrateNum)
-> ~[~str] {
let cdata = cstore::get_crate_data(cstore, crate_num);
decoder::get_link_args_for_crate(cdata)
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
// own crate numbers.
-pub type cnum_map = @mut HashMap<ast::crate_num, ast::crate_num>;
+pub type cnum_map = @mut HashMap<ast::CrateNum, ast::CrateNum>;
pub struct crate_metadata {
name: @str,
data: @~[u8],
cnum_map: cnum_map,
- cnum: ast::crate_num
+ cnum: ast::CrateNum
}
pub struct CStore {
- priv metas: HashMap <ast::crate_num, @crate_metadata>,
+ priv metas: HashMap <ast::CrateNum, @crate_metadata>,
priv extern_mod_crate_map: extern_mod_crate_map,
priv used_crate_files: ~[Path],
priv used_libraries: ~[@str],
}
// Map from node_id's of local extern mod statements to crate numbers
-type extern_mod_crate_map = HashMap<ast::node_id, ast::crate_num>;
+type extern_mod_crate_map = HashMap<ast::node_id, ast::CrateNum>;
pub fn mk_cstore(intr: @ident_interner) -> CStore {
return CStore {
};
}
-pub fn get_crate_data(cstore: &CStore, cnum: ast::crate_num)
+pub fn get_crate_data(cstore: &CStore, cnum: ast::CrateNum)
-> @crate_metadata {
return *cstore.metas.get(&cnum);
}
-pub fn get_crate_hash(cstore: &CStore, cnum: ast::crate_num) -> @str {
+pub fn get_crate_hash(cstore: &CStore, cnum: ast::CrateNum) -> @str {
let cdata = get_crate_data(cstore, cnum);
decoder::get_crate_hash(cdata.data)
}
-pub fn get_crate_vers(cstore: &CStore, cnum: ast::crate_num) -> @str {
+pub fn get_crate_vers(cstore: &CStore, cnum: ast::CrateNum) -> @str {
let cdata = get_crate_data(cstore, cnum);
decoder::get_crate_vers(cdata.data)
}
pub fn set_crate_data(cstore: &mut CStore,
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
data: @crate_metadata) {
cstore.metas.insert(cnum, data);
}
-pub fn have_crate_data(cstore: &CStore, cnum: ast::crate_num) -> bool {
+pub fn have_crate_data(cstore: &CStore, cnum: ast::CrateNum) -> bool {
cstore.metas.contains_key(&cnum)
}
pub fn iter_crate_data(cstore: &CStore,
- i: &fn(ast::crate_num, @crate_metadata)) {
+ i: &fn(ast::CrateNum, @crate_metadata)) {
for cstore.metas.iter().advance |(&k, &v)| {
i(k, v);
}
pub fn add_extern_mod_stmt_cnum(cstore: &mut CStore,
emod_id: ast::node_id,
- cnum: ast::crate_num) {
+ cnum: ast::CrateNum) {
cstore.extern_mod_crate_map.insert(emod_id, cnum);
}
pub fn find_extern_mod_stmt_cnum(cstore: &CStore,
emod_id: ast::node_id)
- -> Option<ast::crate_num> {
+ -> Option<ast::CrateNum> {
cstore.extern_mod_crate_map.find(&emod_id).map_consume(|x| *x)
}
None
}
-pub type GetCrateDataCb<'self> = &'self fn(ast::crate_num) -> cmd;
+pub type GetCrateDataCb<'self> = &'self fn(ast::CrateNum) -> cmd;
pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option<ebml::Doc> {
fn eq_item(bytes: &[u8], item_id: int) -> bool {
None
}
-fn item_reqd_and_translated_parent_item(cnum: ast::crate_num,
+fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum,
d: ebml::Doc) -> ast::def_id {
let trait_did = item_parent_item(d).expect("item without parent");
ast::def_id { crate: cnum, node: trait_did.node }
}
}
-fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
+fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::CrateNum)
-> def_like {
let fam = item_family(item);
match fam {
}
}
-pub fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) ->
+pub fn lookup_def(cnum: ast::CrateNum, data: @~[u8], did_: ast::def_id) ->
ast::def {
let item = lookup_item(did_.node, data);
let did = ast::def_id { crate: cnum, node: did_.node };
#[deriving(Clone)]
pub struct crate_dep {
- cnum: ast::crate_num,
+ cnum: ast::CrateNum,
name: ast::ident,
vers: @str,
hash: @str
fn encode_info_for_items(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
- crate: &crate)
+ crate: &Crate)
-> ~[entry<int>] {
let index = @mut ~[];
ebml_w.start_tag(tag_items_data);
index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() });
encode_info_for_mod(ecx,
ebml_w,
- &crate.node.module,
+ &crate.module,
crate_node_id,
[],
syntax::parse::token::special_idents::invalid,
// 'name' and 'vers' items, so if the user didn't provide them we will throw
// them in anyway with default values.
fn synthesize_crate_attrs(ecx: &EncodeContext,
- crate: &crate) -> ~[Attribute] {
+ crate: &Crate) -> ~[Attribute] {
fn synthesize_link_attr(ecx: &EncodeContext, items: ~[@MetaItem]) ->
Attribute {
let mut attrs = ~[];
let mut found_link_attr = false;
- for crate.node.attrs.iter().advance |attr| {
+ for crate.attrs.iter().advance |attr| {
attrs.push(
if "link" != attr.name() {
*attr
}
fn encode_misc_info(ecx: &EncodeContext,
- crate: &crate,
+ crate: &Crate,
ebml_w: &mut writer::Encoder) {
ebml_w.start_tag(tag_misc_info);
ebml_w.start_tag(tag_misc_info_crate_items);
- for crate.node.module.items.iter().advance |&item| {
+ for crate.module.items.iter().advance |&item| {
ebml_w.start_tag(tag_mod_child);
ebml_w.wr_str(def_to_str(local_def(item.id)));
ebml_w.end_tag();
0x74, //'t' as u8,
0, 0, 0, 1 ];
-pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
+pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
let wr = @io::BytesWriter::new();
let stats = Stats {
inline_bytes: 0,
let r = os::list_dir_path(lib_search_path);
for r.iter().advance |path| {
debug!("testing %s", path.to_str());
- let maybe_picked = pick(*path);
+ let maybe_picked = pick(path);
if maybe_picked.is_some() {
debug!("picked %s", path.to_str());
rslt = maybe_picked;
// nested items, as otherwise it would get confused when translating
// inlined items.
fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item {
- fn drop_nested_items(blk: &ast::blk, fld: @fold::ast_fold) -> ast::blk {
+ fn drop_nested_items(blk: &ast::Block, fld: @fold::ast_fold) -> ast::Block {
let stmts_sans_items = do blk.stmts.iter().filter_map |stmt| {
match stmt.node {
ast::stmt_expr(_, _) | ast::stmt_semi(_, _) |
ast::stmt_mac(*) => fail!("unexpanded macro in astencode")
}
}.collect();
- let blk_sans_items = ast::blk {
+ let blk_sans_items = ast::Block {
view_items: ~[], // I don't know if we need the view_items here,
// but it doesn't break tests!
stmts: stmts_sans_items,
#[cfg(test)]
trait fake_ext_ctxt {
- fn cfg(&self) -> ast::crate_cfg;
+ fn cfg(&self) -> ast::CrateConfig;
fn parse_sess(&self) -> @mut parse::ParseSess;
fn call_site(&self) -> span;
fn ident_of(&self, st: &str) -> ast::ident;
#[cfg(test)]
impl fake_ext_ctxt for fake_session {
- fn cfg(&self) -> ast::crate_cfg { ~[] }
+ fn cfg(&self) -> ast::CrateConfig { ~[] }
fn parse_sess(&self) -> @mut parse::ParseSess { *self }
fn call_site(&self) -> span {
codemap::span {
dfcx_loans: &LoanDataFlow,
move_data: move_data::FlowedMoveData,
all_loans: &[Loan],
- body: &ast::blk) {
+ body: &ast::Block) {
debug!("check_loans(body id=%?)", body.id);
let clcx = CheckLoanCtxt {
fn check_loans_in_fn<'a>(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(this, visitor): (CheckLoanCtxt<'a>,
}
}
-fn check_loans_in_local<'a>(local: @ast::local,
+fn check_loans_in_local<'a>(local: @ast::Local,
(this, vt): (CheckLoanCtxt<'a>,
visit::vt<CheckLoanCtxt<'a>>)) {
visit::visit_local(local, (this, vt));
visit::visit_pat(pat, (this, vt));
}
-fn check_loans_in_block<'a>(blk: &ast::blk,
+fn check_loans_in_block<'a>(blk: &ast::Block,
(this, vt): (CheckLoanCtxt<'a>,
visit::vt<CheckLoanCtxt<'a>>))
{
pub fn gather_loans(bccx: @BorrowckCtxt,
decl: &ast::fn_decl,
- body: &ast::blk)
+ body: &ast::Block)
-> (id_range, @mut ~[Loan], @mut move_data::MoveData) {
let glcx = @mut GatherLoanCtxt {
bccx: bccx,
fn gather_loans_in_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(this, v): (@mut GatherLoanCtxt,
}
}
-fn gather_loans_in_block(blk: &ast::blk,
+fn gather_loans_in_block(blk: &ast::Block,
(this, vt): (@mut GatherLoanCtxt,
visit::vt<@mut GatherLoanCtxt>)) {
this.id_range.add(blk.id);
visit::visit_block(blk, (this, vt));
}
-fn gather_loans_in_local(local: @ast::local,
+fn gather_loans_in_local(local: @ast::Local,
(this, vt): (@mut GatherLoanCtxt,
visit::vt<@mut GatherLoanCtxt>)) {
- match local.node.init {
+ match local.init {
None => {
// Variable declarations without initializers are considered "moves":
let tcx = this.bccx.tcx;
- do pat_util::pat_bindings(tcx.def_map, local.node.pat)
+ do pat_util::pat_bindings(tcx.def_map, local.pat)
|_, id, span, _| {
gather_moves::gather_decl(this.bccx,
this.move_data,
Some(init) => {
// Variable declarations with initializers are considered "assigns":
let tcx = this.bccx.tcx;
- do pat_util::pat_bindings(tcx.def_map, local.node.pat)
+ do pat_util::pat_bindings(tcx.def_map, local.pat)
|_, id, span, _| {
gather_moves::gather_assignment(this.bccx,
this.move_data,
id);
}
let init_cmt = this.bccx.cat_expr(init);
- this.gather_pat(init_cmt, local.node.pat, None);
+ this.gather_pat(init_cmt, local.pat, None);
}
}
fn gather_fn_arg_patterns(&mut self,
decl: &ast::fn_decl,
- body: &ast::blk) {
+ body: &ast::Block) {
/*!
* Walks the patterns for fn arguments, checking that they
* do not attempt illegal moves or create refs that outlive
moves_map: moves::MovesMap,
moved_variables_set: moves::MovedVariablesSet,
capture_map: moves::CaptureMap,
- crate: &ast::crate) -> (root_map, write_guard_map)
+ crate: &ast::Crate) -> (root_map, write_guard_map)
{
let bccx = @BorrowckCtxt {
tcx: tcx,
fn borrowck_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(this, v): (@BorrowckCtxt,
tcx: ty::ctxt,
method_map: typeck::method_map,
id_range: ast_util::id_range,
- body: &ast::blk)
+ body: &ast::Block)
-> FlowedMoveData
{
let mut dfcx_moves =
pub fn construct(tcx: ty::ctxt,
method_map: typeck::method_map,
- blk: &ast::blk) -> CFG {
+ blk: &ast::Block) -> CFG {
let mut cfg_builder = CFGBuilder {
exit_map: HashMap::new(),
graph: graph::Graph::new(),
}
impl CFGBuilder {
- fn block(&mut self, blk: &ast::blk, pred: CFGIndex) -> CFGIndex {
+ fn block(&mut self, blk: &ast::Block, pred: CFGIndex) -> CFGIndex {
let mut stmts_exit = pred;
for blk.stmts.iter().advance |&stmt| {
stmts_exit = self.stmt(stmt, stmts_exit);
fn decl(&mut self, decl: @ast::decl, pred: CFGIndex) -> CFGIndex {
match decl.node {
ast::decl_local(local) => {
- let init_exit = self.opt_expr(local.node.init, pred);
- self.pat(local.node.pat, init_exit)
+ let init_exit = self.opt_expr(local.init, pred);
+ self.pat(local.pat, init_exit)
}
ast::decl_item(_) => {
ast::expr_struct(_, ref fields, base) => {
let base_exit = self.opt_expr(base, pred);
let field_exprs: ~[@ast::expr] =
- fields.iter().transform(|f| f.node.expr).collect();
+ fields.iter().transform(|f| f.expr).collect();
self.straightline(expr, base_exit, field_exprs)
}
impl CFG {
pub fn new(tcx: ty::ctxt,
method_map: typeck::method_map,
- blk: &ast::blk) -> CFG {
+ blk: &ast::Block) -> CFG {
construct::construct(tcx, method_map, blk)
}
}
\ No newline at end of file
use syntax::{visit, ast_util, ast_map};
pub fn check_crate(sess: Session,
- crate: &crate,
+ crate: &Crate,
ast_map: ast_map::map,
def_map: resolve::DefMap,
method_map: typeck::method_map,
can_ret: bool
}
-pub fn check_crate(tcx: ty::ctxt, crate: &crate) {
+pub fn check_crate(tcx: ty::ctxt, crate: &Crate) {
visit::visit_crate(crate,
(Context { in_loop: false, can_ret: true },
visit::mk_vt(@visit::Visitor {
pub fn check_crate(tcx: ty::ctxt,
method_map: method_map,
moves_map: moves::MovesMap,
- crate: &crate) {
+ crate: &Crate) {
let cx = @MatchCheckCtxt {tcx: tcx,
method_map: method_map,
moves_map: moves_map};
}
pub fn check_local(cx: &MatchCheckCtxt,
- loc: @local,
+ loc: @Local,
(s, v): ((),
visit::vt<()>)) {
visit::visit_local(loc, (s, v));
- if is_refutable(cx, loc.node.pat) {
- cx.tcx.sess.span_err(loc.node.pat.span,
+ if is_refutable(cx, loc.pat) {
+ cx.tcx.sess.span_err(loc.pat.span,
"refutable pattern in local binding");
}
// Check legality of move bindings.
- check_legality_of_move_bindings(cx, false, [ loc.node.pat ]);
+ check_legality_of_move_bindings(cx, false, [ loc.pat ]);
}
pub fn check_fn(cx: &MatchCheckCtxt,
kind: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
id: node_id,
(s, v): ((),
ast::expr_struct(_, ref fs, None) => {
let cs = do fs.iter().transform |f| {
- classify(f.node.expr, tcx)
+ classify(f.expr, tcx)
};
join_all(cs)
}
}
}
-pub fn process_crate(crate: &ast::crate,
+pub fn process_crate(crate: &ast::Crate,
tcx: ty::ctxt) {
let v = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_expr_post: |e| { classify(e, tcx); },
impl<O:DataFlowOperator+Clone+'static> DataFlowContext<O> {
// ^^^^^^^^^^^^^ only needed for pretty printing
- pub fn propagate(&mut self, blk: &ast::blk) {
+ pub fn propagate(&mut self, blk: &ast::Block) {
//! Performs the data flow analysis.
if self.bits_per_id == 0 {
});
}
- fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::blk) {
+ fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::Block) {
let pre: @fn(pprust::ann_node) = |node| {
let (ps, id) = match node {
pprust::node_expr(ps, expr) => (ps, expr.id),
}
fn walk_block(&mut self,
- blk: &ast::blk,
+ blk: &ast::Block,
in_out: &mut [uint],
loop_scopes: &mut ~[LoopScope]) {
debug!("DataFlowContext::walk_block(blk.id=%?, in_out=%s)",
loop_scopes: &mut ~[LoopScope]) {
match decl.node {
ast::decl_local(local) => {
- self.walk_opt_expr(local.node.init, in_out, loop_scopes);
- self.walk_pat(local.node.pat, in_out, loop_scopes);
+ self.walk_opt_expr(local.init, in_out, loop_scopes);
+ self.walk_pat(local.pat, in_out, loop_scopes);
}
ast::decl_item(_) => {}
ast::expr_struct(_, ref fields, with_expr) => {
for fields.iter().advance |field| {
- self.walk_expr(field.node.expr, in_out, loop_scopes);
+ self.walk_expr(field.expr, in_out, loop_scopes);
}
self.walk_opt_expr(with_expr, in_out, loop_scopes);
}
pub fn check_crate(tcx: ty::ctxt,
method_map: method_map,
- crate: &ast::crate) {
+ crate: &ast::Crate) {
let context = @mut Context {
method_map: method_map,
unsafe_context: SafeContext,
use driver::session;
use driver::session::Session;
use syntax::parse::token::special_idents;
-use syntax::ast::{crate, node_id, item, item_fn};
+use syntax::ast::{Crate, node_id, item, item_fn};
use syntax::attr;
use syntax::codemap::span;
use syntax::visit::{default_visitor, mk_vt, vt, Visitor, visit_crate, visit_item};
type EntryVisitor = vt<@mut EntryContext>;
-pub fn find_entry_point(session: Session, crate: &crate, ast_map: ast_map::map) {
+pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) {
// FIXME #4404 android JNI hacks
if *session.building_library &&
// Since we want to be able to collect upvars in some arbitrary piece
// of the AST, we take a walker function that we invoke with a visitor
// in order to start the search.
-fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk)
+fn collect_freevars(def_map: resolve::DefMap, blk: &ast::Block)
-> freevar_info {
let seen = @mut HashMap::new();
let refs = @mut ~[];
// efficient as it fully recomputes the free variables at every
// node of interest rather than building up the free variables in
// one pass. This could be improved upon if it turns out to matter.
-pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::crate) ->
+pub fn annotate_freevars(def_map: resolve::DefMap, crate: &ast::Crate) ->
freevar_map {
let freevars = @mut HashMap::new();
let walk_fn: @fn(&visit::fn_kind,
&ast::fn_decl,
- &ast::blk,
+ &ast::Block,
span,
ast::node_id) = |_, _, blk, _, nid| {
let vars = collect_freevars(def_map, blk);
pub fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
- crate: &crate) {
+ crate: &Crate) {
let ctx = Context {
tcx: tcx,
method_map: method_map,
}
}
-fn check_block(block: &blk, (cx, visitor): (Context, visit::vt<Context>)) {
+fn check_block(block: &Block, (cx, visitor): (Context, visit::vt<Context>)) {
visit::visit_block(block, (cx, visitor));
}
fn check_fn(
fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
fn_id: node_id,
(cx, v): (Context,
use driver::session::Session;
use metadata::csearch::each_lang_item;
use metadata::cstore::iter_crate_data;
-use syntax::ast::{crate, def_id, MetaItem};
+use syntax::ast::{Crate, def_id, MetaItem};
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor};
struct LanguageItemCollector<'self> {
items: LanguageItems,
- crate: &'self crate,
+ crate: &'self Crate,
session: Session,
item_refs: HashMap<@str, uint>,
}
impl<'self> LanguageItemCollector<'self> {
- pub fn new<'a>(crate: &'a crate, session: Session)
+ pub fn new<'a>(crate: &'a Crate, session: Session)
-> LanguageItemCollector<'a> {
let mut item_refs = HashMap::new();
}
}
-pub fn collect_language_items(crate: &crate,
+pub fn collect_language_items(crate: &Crate,
session: Session)
-> LanguageItems {
let mut collector = LanguageItemCollector::new(crate, session);
enum AttributedNode<'self> {
Item(@ast::item),
Method(&'self ast::method),
- Crate(@ast::crate),
+ Crate(@ast::Crate),
}
#[deriving(Eq)]
visit::mk_vt(@visit::Visitor {
visit_local: |l, (cx, vt): (@mut Context, visit::vt<@mut Context>)| {
- if l.node.is_mutbl {
- check_pat(cx, l.node.pat);
+ if l.is_mutbl {
+ check_pat(cx, l.pat);
}
visit::visit_local(l, (cx, vt));
},
})
}
-pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
+pub fn check_crate(tcx: ty::ctxt, crate: @ast::Crate) {
let cx = @mut Context {
dict: @get_lint_dict(),
curr: SmallIntMap::new(),
cx.add_lint(lint_missing_doc());
// Actually perform the lint checks (iterating the ast)
- do cx.with_lint_attrs(crate.node.attrs) {
+ do cx.with_lint_attrs(crate.attrs) {
cx.process(Crate(crate));
visit::visit_crate(crate, (cx, visit::mk_vt(@visit::Visitor {
pub fn check_crate(tcx: ty::ctxt,
method_map: typeck::method_map,
capture_map: moves::CaptureMap,
- crate: &crate) {
+ crate: &Crate) {
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: visit_fn,
visit_local: visit_local,
fn visit_fn(fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
id: node_id,
(this, v): (@mut IrMaps,
lsets.warn_about_unused_args(decl, entry_ln);
}
-fn visit_local(local: @local, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
+fn visit_local(local: @Local, (this, vt): (@mut IrMaps, vt<@mut IrMaps>)) {
let def_map = this.tcx.def_map;
- do pat_util::pat_bindings(def_map, local.node.pat) |_bm, p_id, sp, path| {
+ do pat_util::pat_bindings(def_map, local.pat) |_bm, p_id, sp, path| {
debug!("adding local variable %d", p_id);
let name = ast_util::path_to_ident(path);
this.add_live_node_for_node(p_id, VarDefNode(sp));
- let kind = match local.node.init {
+ let kind = match local.init {
Some(_) => FromLetWithInitializer,
None => FromLetNoInitializer
};
this.add_variable(Local(LocalInfo {
id: p_id,
ident: name,
- is_mutbl: local.node.is_mutbl,
+ is_mutbl: local.is_mutbl,
kind: kind
}));
}
// _______________________________________________________________________
- pub fn compute(&self, decl: &fn_decl, body: &blk) -> LiveNode {
+ pub fn compute(&self, decl: &fn_decl, body: &Block) -> LiveNode {
// if there is a `break` or `again` at the top level, then it's
// effectively a return---this only occurs in `for` loops,
// where the body is really a closure.
entry_ln
}
- pub fn propagate_through_fn_block(&self, _: &fn_decl, blk: &blk)
+ pub fn propagate_through_fn_block(&self, _: &fn_decl, blk: &Block)
-> LiveNode {
// the fallthrough exit is only for those cases where we do not
// explicitly return:
self.propagate_through_block(blk, self.s.fallthrough_ln)
}
- pub fn propagate_through_block(&self, blk: &blk, succ: LiveNode)
+ pub fn propagate_through_block(&self, blk: &Block, succ: LiveNode)
-> LiveNode {
let succ = self.propagate_through_opt_expr(blk.expr, succ);
do blk.stmts.rev_iter().fold(succ) |succ, stmt| {
}
}
- pub fn propagate_through_local(&self, local: &local, succ: LiveNode)
+ pub fn propagate_through_local(&self, local: &Local, succ: LiveNode)
-> LiveNode {
// Note: we mark the variable as defined regardless of whether
// there is an initializer. Initially I had thought to only mark
// initialization, which is mildly more complex than checking
// once at the func header but otherwise equivalent.
- let succ = self.propagate_through_opt_expr(local.node.init, succ);
- self.define_bindings_in_pat(local.node.pat, succ)
+ let succ = self.propagate_through_opt_expr(local.init, succ);
+ self.define_bindings_in_pat(local.pat, succ)
}
pub fn propagate_through_exprs(&self, exprs: &[@expr], succ: LiveNode)
expr_struct(_, ref fields, with_expr) => {
let succ = self.propagate_through_opt_expr(with_expr, succ);
do fields.rev_iter().fold(succ) |succ, field| {
- self.propagate_through_expr(field.node.expr, succ)
+ self.propagate_through_expr(field.expr, succ)
}
}
pub fn propagate_through_loop(&self,
expr: &expr,
cond: Option<@expr>,
- body: &blk,
+ body: &Block,
succ: LiveNode)
-> LiveNode {
// _______________________________________________________________________
// Checking for error conditions
-fn check_local(local: @local, (this, vt): (@Liveness, vt<@Liveness>)) {
- match local.node.init {
+fn check_local(local: @Local, (this, vt): (@Liveness, vt<@Liveness>)) {
+ match local.init {
Some(_) => {
- this.warn_about_unused_or_dead_vars_in_pat(local.node.pat);
+ this.warn_about_unused_or_dead_vars_in_pat(local.pat);
}
None => {
// should not be live at this point.
debug!("check_local() with no initializer");
- do this.pat_bindings(local.node.pat) |ln, var, sp, id| {
+ do this.pat_bindings(local.pat) |ln, var, sp, id| {
if !this.warn_about_unused(sp, id, ln, var) {
match this.live_on_exit(ln, var) {
None => { /* not live: good */ }
}
fn check_fn(_fk: &visit::fn_kind, _decl: &fn_decl,
- _body: &blk, _sp: span, _id: node_id,
+ _body: &Block, _sp: span, _id: node_id,
(_self, _v): (@Liveness, vt<@Liveness>)) {
// do not check contents of nested fns
}
pub fn compute_moves(tcx: ty::ctxt,
method_map: method_map,
- crate: &crate) -> MoveMaps
+ crate: &Crate) -> MoveMaps
{
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: compute_modes_for_fn,
///////////////////////////////////////////////////////////////////////////
// Expressions
-fn compute_modes_for_local<'a>(local: @local,
+fn compute_modes_for_local<'a>(local: @Local,
(cx, v): (VisitContext,
vt<VisitContext>)) {
- cx.use_pat(local.node.pat);
- for local.node.init.iter().advance |&init| {
+ cx.use_pat(local.pat);
+ for local.init.iter().advance |&init| {
cx.use_expr(init, Read, v);
}
}
fn compute_modes_for_fn(fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
span: span,
id: node_id,
(cx, v): (VisitContext,
};
}
- pub fn consume_block(&self, blk: &blk, visitor: vt<VisitContext>) {
+ pub fn consume_block(&self, blk: &Block, visitor: vt<VisitContext>) {
/*!
* Indicates that the value of `blk` will be consumed,
* meaning either copied or moved depending on its type.
expr_struct(_, ref fields, opt_with) => {
for fields.iter().advance |field| {
- self.consume_expr(field.node.expr, visitor);
+ self.consume_expr(field.expr, visitor);
}
for opt_with.iter().advance |with_expr| {
// specified and (2) have a type that
// moves-by-default:
let consume_with = with_fields.iter().any(|tf| {
- !fields.iter().any(|f| f.node.ident == tf.ident) &&
+ !fields.iter().any(|f| f.ident == tf.ident) &&
ty::type_moves_by_default(self.tcx, tf.mt.ty)
});
pub fn check_crate<'mm>(tcx: ty::ctxt,
method_map: &'mm method_map,
- crate: &ast::crate) {
+ crate: &ast::Crate) {
let privileged_items = @mut ~[];
// Adds an item to its scope.
Some(ref entry) => {
debug!("(privacy checking) checking \
impl method");
- check_method(expr.span,
- &entry.origin,
- ident);
+ check_method(expr.span, &entry.origin, ident);
}
}
}
for (*fields).iter().advance |field| {
debug!("(privacy checking) checking \
field in struct literal");
- check_field(expr.span, id,
- field.node.ident);
+ check_field(expr.span, id, field.ident);
}
}
}
checking field in \
struct variant \
literal");
- check_field(expr.span, variant_id,
- field.node.ident);
+ check_field(expr.span, variant_id, field.ident);
}
}
_ => {
for fields.iter().advance |field| {
debug!("(privacy checking) checking \
struct pattern");
- check_field(pattern.span, id,
- field.ident);
+ check_field(pattern.span, id, field.ident);
}
}
}
debug!("(privacy checking) \
checking field in \
struct variant pattern");
- check_field(pattern.span,
- variant_id,
- field.ident);
+ check_field(pattern.span, variant_id, field.ident);
}
}
_ => {
// Step 1: Mark all public symbols, and add all public symbols that might
// be inlined to a worklist.
- fn mark_public_symbols(&self, crate: @crate) {
+ fn mark_public_symbols(&self, crate: @Crate) {
let reachable_symbols = self.reachable_symbols;
let worklist = self.worklist;
let visitor = visit::mk_vt(@Visitor {
pub fn find_reachable(tcx: ty::ctxt,
method_map: typeck::method_map,
- crate: @crate)
+ crate: @Crate)
-> @mut HashSet<node_id> {
// XXX(pcwalton): We only need to mark symbols that are exported. But this
// is more complicated than just looking at whether the symbol is `pub`,
}
}
-fn resolve_block(blk: &ast::blk, (cx, visitor): (Context, visit::vt<Context>)) {
+fn resolve_block(blk: &ast::Block, (cx, visitor): (Context, visit::vt<Context>)) {
// Record the parent of this block.
parent_to_expr(cx, blk.id, blk.span);
visit::visit_expr(expr, (new_cx, visitor));
}
-fn resolve_local(local: @ast::local,
+fn resolve_local(local: @ast::Local,
(cx, visitor) : (Context,
visit::vt<Context>)) {
assert_eq!(cx.var_parent, cx.parent);
- parent_to_expr(cx, local.node.id, local.span);
+ parent_to_expr(cx, local.id, local.span);
visit::visit_local(local, (cx, visitor));
}
fn resolve_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
sp: span,
id: ast::node_id,
(cx, visitor): (Context,
pub fn resolve_crate(sess: Session,
def_map: resolve::DefMap,
- crate: &ast::crate) -> @mut RegionMaps
+ crate: &ast::Crate) -> @mut RegionMaps
{
let region_maps = @mut RegionMaps {
scope_map: HashMap::new(),
fn determine_rp_in_fn(fk: &visit::fn_kind,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
_: span,
_: ast::node_id,
(cx, visitor): (@mut DetermineRpCtxt,
pub fn determine_rp_in_crate(sess: Session,
ast_map: ast_map::map,
def_map: resolve::DefMap,
- crate: &ast::crate)
+ crate: &ast::Crate)
-> region_paramd_items {
let cx = @mut DetermineRpCtxt {
sess: sess,
pub fn Resolver(session: Session,
lang_items: LanguageItems,
- crate: @crate)
+ crate: @Crate)
-> Resolver {
let graph_root = @mut NameBindings();
pub struct Resolver {
session: @Session,
lang_items: LanguageItems,
- crate: @crate,
+ crate: @Crate,
intr: @ident_interner,
}
}
- pub fn block_needs_anonymous_module(@mut self, block: &blk) -> bool {
+ pub fn block_needs_anonymous_module(@mut self, block: &Block) -> bool {
// If the block has view items, we need an anonymous module.
if block.view_items.len() > 0 {
return true;
}
pub fn build_reduced_graph_for_block(@mut self,
- block: &blk,
+ block: &Block,
(parent, visitor):
(ReducedGraphParent,
vt<ReducedGraphParent>)) {
rib_kind: RibKind,
optional_declaration: Option<&fn_decl>,
type_parameters: TypeParameters,
- block: &blk,
+ block: &Block,
self_binding: SelfBinding,
visitor: ResolveVisitor) {
// Create a value rib for the function.
visit_mod(module_, span, id, ((), visitor));
}
- pub fn resolve_local(@mut self, local: @local, visitor: ResolveVisitor) {
- let mutability = if local.node.is_mutbl {Mutable} else {Immutable};
+ pub fn resolve_local(@mut self, local: @Local, visitor: ResolveVisitor) {
+ let mutability = if local.is_mutbl {Mutable} else {Immutable};
// Resolve the type.
- self.resolve_type(&local.node.ty, visitor);
+ self.resolve_type(&local.ty, visitor);
// Resolve the initializer, if necessary.
- match local.node.init {
+ match local.init {
None => {
// Nothing to do.
}
}
// Resolve the pattern.
- self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability,
+ self.resolve_pattern(local.pat, LocalIrrefutableMode, mutability,
None, visitor);
}
self.value_ribs.pop();
}
- pub fn resolve_block(@mut self, block: &blk, visitor: ResolveVisitor) {
+ pub fn resolve_block(@mut self, block: &Block, visitor: ResolveVisitor) {
debug!("(resolving block) entering block");
self.value_ribs.push(@Rib(NormalRibKind));
i -= 1;
match this.type_ribs[i].kind {
MethodRibKind(node_id, _) =>
- for this.crate.node.module.items.iter().advance |item| {
+ for this.crate.module.items.iter().advance |item| {
if item.id == node_id {
match item.node {
item_struct(class_def, _) => {
/// Entry point to crate resolution.
pub fn resolve_crate(session: Session,
lang_items: LanguageItems,
- crate: @crate)
+ crate: @Crate)
-> CrateMap {
let resolver = @mut Resolver(session, lang_items, crate);
resolver.resolve();
use middle::trans::adt;
use middle::trans::base;
use middle::trans::build::*;
+use middle::trans::builder::{Builder, noname};
use middle::trans::callee;
use middle::trans::common::*;
use middle::trans::consts;
pub use middle::trans::context::task_llcx;
-#[cfg(not(stage0))]
static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
-#[cfg(stage0)]
-fn task_local_insn_key(_: @~[&'static str]) {}
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k));
Call(bcx, ccx.upcalls.trace, args);
}
-pub fn ignore_lhs(_bcx: block, local: &ast::local) -> bool {
- match local.node.pat.node {
+pub fn ignore_lhs(_bcx: block, local: &ast::Local) -> bool {
+ match local.pat.node {
ast::pat_wild => true, _ => false
}
}
-pub fn init_local(bcx: block, local: &ast::local) -> block {
+pub fn init_local(bcx: block, local: &ast::Local) -> block {
debug!("init_local(bcx=%s, local.id=%?)",
- bcx.to_str(), local.node.id);
+ bcx.to_str(), local.id);
let _indenter = indenter();
let _icx = push_ctxt("init_local");
if ignore_lhs(bcx, local) {
// Handle let _ = e; just like e;
- match local.node.init {
+ match local.init {
Some(init) => {
return expr::trans_into(bcx, init, expr::Ignore);
}
}
}
- _match::store_local(bcx, local.node.pat, local.node.init)
+ _match::store_local(bcx, local.pat, local.init)
}
pub fn trans_stmt(cx: block, s: &ast::stmt) -> block {
DatumBlock {bcx: leave_block(bcx, scope_cx), datum: datum}
}
-pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) {
+pub fn block_locals(b: &ast::Block, it: &fn(@ast::Local)) {
for b.stmts.iter().advance |s| {
match s.node {
ast::stmt_decl(d, _) => {
}
pub fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) {
+ if cx.unreachable { return; }
let _icx = push_ctxt("zero_mem");
let bcx = cx;
let ccx = cx.ccx();
let llty = type_of::type_of(ccx, t);
- memzero(bcx, llptr, llty);
+ memzero(&B(bcx), llptr, llty);
}
// Always use this function instead of storing a zero constant to the memory
// allocation for large data structures, and the generated code will be
// awful. (A telltale sign of this is large quantities of
// `mov [byte ptr foo],0` in the generated code.)
-pub fn memzero(cx: block, llptr: ValueRef, ty: Type) {
+pub fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
let _icx = push_ctxt("memzero");
- let ccx = cx.ccx();
+ let ccx = b.ccx;
let intrinsic_key = match ccx.sess.targ_cfg.arch {
X86 | Arm | Mips => "llvm.memset.p0i8.i32",
};
let llintrinsicfn = ccx.intrinsics.get_copy(&intrinsic_key);
- let llptr = PointerCast(cx, llptr, Type::i8().ptr_to());
+ let llptr = b.pointercast(llptr, Type::i8().ptr_to());
let llzeroval = C_u8(0);
- let size = IntCast(cx, machine::llsize_of(ccx, ty), ccx.int_type);
+ let size = machine::llsize_of(ccx, ty);
let align = C_i32(llalign_of_min(ccx, ty) as i32);
let volatile = C_i1(false);
- Call(cx, llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
+ b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
}
pub fn alloc_ty(bcx: block, t: ty::t, name: &str) -> ValueRef {
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
}
}
- let initcx = base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas());
- let p = Alloca(initcx, ty, name);
- if zero { memzero(initcx, p, ty); }
+ let p = Alloca(cx, ty, name);
+ if zero {
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get());
+ memzero(&b, p, ty);
+ }
p
}
return llvm::LLVMGetUndef(ty.to_ref());
}
}
- return ArrayAlloca(base::raw_block(cx.fcx, false, cx.fcx.get_llstaticallocas()), ty, v);
+ return ArrayAlloca(cx, ty, v);
}
pub struct BasicBlocks {
llvm::LLVMGetParam(fcx.llfn, 0)
} else {
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
- alloca(raw_block(fcx, false, fcx.get_llstaticallocas()), lloutputtype,
- "__make_return_pointer")
+ let bcx = fcx.entry_bcx.get();
+ Alloca(bcx, lloutputtype, "__make_return_pointer")
}
}
}
output_type: ty::t,
skip_retptr: bool,
param_substs: Option<@param_substs>,
+ opt_node_info: Option<NodeInfo>,
sp: Option<span>)
-> fn_ctxt {
for param_substs.iter().advance |p| { p.validate(); }
llvm::LLVMGetUndef(Type::i8p().to_ref())
},
llretptr: None,
- llstaticallocas: None,
- llloadenv: None,
+ entry_bcx: None,
+ alloca_insert_pt: None,
llreturn: None,
llself: None,
personality: None,
fcx.llenv = unsafe {
llvm::LLVMGetParam(llfndecl, fcx.env_arg_pos() as c_uint)
};
+
+ unsafe {
+ let entry_bcx = top_scope_block(fcx, opt_node_info);
+ Load(entry_bcx, C_null(Type::i8p()));
+
+ fcx.entry_bcx = Some(entry_bcx);
+ fcx.alloca_insert_pt = Some(llvm::LLVMGetFirstInstruction(entry_bcx.llbb));
+ }
+
if !ty::type_is_nil(substd_output_type) && !(is_immediate && skip_retptr) {
fcx.llretptr = Some(make_return_pointer(fcx, substd_output_type));
}
output_type: ty::t,
sp: Option<span>)
-> fn_ctxt {
- new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, sp)
+ new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, false, None, None, sp)
}
// NB: must keep 4 fns in sync:
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
// and builds the return block.
-pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
+pub fn finish_fn(fcx: fn_ctxt, last_bcx: block) {
let _icx = push_ctxt("finish_fn");
- tie_up_header_blocks(fcx, lltop);
let ret_cx = match fcx.llreturn {
Some(llreturn) => {
None => last_bcx
};
build_return_block(fcx, ret_cx);
+ fcx.cleanup();
}
// Builds the return block for a function.
}
}
-pub fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
- let _icx = push_ctxt("tie_up_header_blocks");
- let llnext = match fcx.llloadenv {
- Some(ll) => {
- unsafe {
- llvm::LLVMMoveBasicBlockBefore(ll, lltop);
- }
- Br(raw_block(fcx, false, ll), lltop);
- ll
- }
- None => lltop
- };
- match fcx.llstaticallocas {
- Some(ll) => {
- unsafe {
- llvm::LLVMMoveBasicBlockBefore(ll, llnext);
- }
- Br(raw_block(fcx, false, ll), llnext);
- }
- None => ()
- }
-}
-
pub enum self_arg { impl_self(ty::t, ty::SelfMode), no_self, }
// trans_closure: Builds an LLVM function out of a source function.
pub fn trans_closure(ccx: @mut CrateContext,
path: path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
llfndecl: ValueRef,
self_arg: self_arg,
param_substs: Option<@param_substs>,
output_type,
false,
param_substs,
+ body.info(),
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
// Create the first basic block in the function and keep a handle on it to
// pass to finish_fn later.
- let bcx_top = top_scope_block(fcx, body.info());
+ let bcx_top = fcx.entry_bcx.get();
let mut bcx = bcx_top;
- let lltop = bcx.llbb;
let block_ty = node_id_type(bcx, body.id);
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
}
// Insert the mandatory first few basic blocks before lltop.
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
// trans_fn: creates an LLVM function corresponding to a source language
pub fn trans_fn(ccx: @mut CrateContext,
path: path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
llfndecl: ValueRef,
self_arg: self_arg,
param_substs: Option<@param_substs>,
result_ty,
false,
param_substs,
+ None,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let arg_tys = ty::ty_fn_args(ctor_ty);
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
let arg_ty = arg_tys[i];
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
}
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
// be updated if this assertion starts to fail.
assert!(fcx.has_immediate_return_value);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
-
+ let bcx = fcx.entry_bcx.get();
// Call main.
let llenvarg = unsafe {
let env_arg = fcx.env_arg_pos();
let args = ~[llenvarg];
Call(bcx, main_llfn, args);
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
return llfdecl;
}
}
}
-pub fn trans_constants(ccx: @mut CrateContext, crate: &ast::crate) {
+pub fn trans_constants(ccx: @mut CrateContext, crate: &ast::Crate) {
visit::visit_crate(
crate, ((),
visit::mk_simple_visitor(@visit::SimpleVisitor {
}
}
-pub fn write_metadata(cx: &mut CrateContext, crate: &ast::crate) {
+pub fn write_metadata(cx: &mut CrateContext, crate: &ast::Crate) {
if !*cx.sess.building_library { return; }
let encode_inlined_item: encoder::encode_inlined_item =
}
pub fn trans_crate(sess: session::Session,
- crate: &ast::crate,
+ crate: &ast::Crate,
tcx: ty::ctxt,
output: &Path,
emap2: resolve::ExportMap2,
{
let _icx = push_ctxt("text");
- trans_mod(ccx, &crate.node.module);
+ trans_mod(ccx, &crate.module);
}
decl_gc_metadata(ccx, llmod_id);
use lib::llvm::llvm;
use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
-use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
-use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
+use lib::llvm::{Opcode, IntPredicate, RealPredicate};
+use lib::llvm::{ValueRef, BasicBlockRef};
use lib;
use middle::trans::common::*;
-use middle::trans::machine::llalign_of_min;
use syntax::codemap::span;
-use middle::trans::base;
+use middle::trans::builder::Builder;
use middle::trans::type_::Type;
use std::cast;
use std::libc::{c_uint, c_ulonglong, c_char};
-use std::hashmap::HashMap;
-use std::str;
-use std::vec;
pub fn terminate(cx: block, _: &str) {
cx.terminated = true;
}
}
-pub fn B(cx: block) -> BuilderRef {
- unsafe {
- let b = cx.fcx.ccx.builder.B;
- llvm::LLVMPositionBuilderAtEnd(b, cx.llbb);
- return b;
- }
-}
-
-pub fn count_insn(cx: block, category: &str) {
- if cx.ccx().sess.trans_stats() {
- cx.ccx().stats.n_llvm_insns += 1;
- }
- do base::with_insn_ctxt |v| {
- let h = &mut cx.ccx().stats.llvm_insns;
-
- // Build version of path with cycles removed.
-
- // Pass 1: scan table mapping str -> rightmost pos.
- let mut mm = HashMap::new();
- let len = v.len();
- let mut i = 0u;
- while i < len {
- mm.insert(v[i], i);
- i += 1u;
- }
-
- // Pass 2: concat strings for each elt, skipping
- // forwards over any cycles by advancing to rightmost
- // occurrence of each element in path.
- let mut s = ~".";
- i = 0u;
- while i < len {
- i = *mm.get(&v[i]);
- s.push_char('/');
- s.push_str(v[i]);
- i += 1u;
- }
-
- s.push_char('/');
- s.push_str(category);
-
- let n = match h.find(&s) {
- Some(&n) => n,
- _ => 0u
- };
- h.insert(s, n+1u);
- }
+pub fn B(cx: block) -> Builder {
+ let b = cx.fcx.ccx.builder();
+ b.position_at_end(cx.llbb);
+ b
}
-
// The difference between a block being unreachable and being terminated is
// somewhat obscure, and has to do with error checking. When a block is
// terminated, we're saying that trying to add any further statements in the
// further instructions to the block should simply be ignored.
pub fn RetVoid(cx: block) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "RetVoid");
- count_insn(cx, "retvoid");
- llvm::LLVMBuildRetVoid(B(cx));
- }
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "RetVoid");
+ B(cx).ret_void();
}
pub fn Ret(cx: block, V: ValueRef) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "Ret");
- count_insn(cx, "ret");
- llvm::LLVMBuildRet(B(cx), V);
- }
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "Ret");
+ B(cx).ret(V);
}
pub fn AggregateRet(cx: block, RetVals: &[ValueRef]) {
if cx.unreachable { return; }
check_not_terminated(cx);
terminate(cx, "AggregateRet");
- unsafe {
- llvm::LLVMBuildAggregateRet(B(cx), vec::raw::to_ptr(RetVals),
- RetVals.len() as c_uint);
- }
+ B(cx).aggregate_ret(RetVals);
}
pub fn Br(cx: block, Dest: BasicBlockRef) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "Br");
- count_insn(cx, "br");
- llvm::LLVMBuildBr(B(cx), Dest);
- }
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "Br");
+ B(cx).br(Dest);
}
pub fn CondBr(cx: block, If: ValueRef, Then: BasicBlockRef,
Else: BasicBlockRef) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "CondBr");
- count_insn(cx, "condbr");
- llvm::LLVMBuildCondBr(B(cx), If, Then, Else);
- }
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "CondBr");
+ B(cx).cond_br(If, Then, Else);
}
pub fn Switch(cx: block, V: ValueRef, Else: BasicBlockRef, NumCases: uint)
-> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- check_not_terminated(cx);
- terminate(cx, "Switch");
- return llvm::LLVMBuildSwitch(B(cx), V, Else, NumCases as c_uint);
- }
+ if cx.unreachable { return _Undef(V); }
+ check_not_terminated(cx);
+ terminate(cx, "Switch");
+ B(cx).switch(V, Else, NumCases)
}
pub fn AddCase(S: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef) {
}
pub fn IndirectBr(cx: block, Addr: ValueRef, NumDests: uint) {
- unsafe {
- if cx.unreachable { return; }
- check_not_terminated(cx);
- terminate(cx, "IndirectBr");
- count_insn(cx, "indirectbr");
- llvm::LLVMBuildIndirectBr(B(cx), Addr, NumDests as c_uint);
- }
-}
-
-// This is a really awful way to get a zero-length c-string, but better (and a
-// lot more efficient) than doing str::as_c_str("", ...) every time.
-pub fn noname() -> *c_char {
- unsafe {
- static cnull: uint = 0u;
- return cast::transmute(&cnull);
- }
+ if cx.unreachable { return; }
+ check_not_terminated(cx);
+ terminate(cx, "IndirectBr");
+ B(cx).indirect_br(Addr, NumDests);
}
pub fn Invoke(cx: block,
debug!("Invoke(%s with arguments (%s))",
cx.val_to_str(Fn),
Args.map(|a| cx.val_to_str(*a)).connect(", "));
- unsafe {
- count_insn(cx, "invoke");
- llvm::LLVMBuildInvoke(B(cx),
- Fn,
- vec::raw::to_ptr(Args),
- Args.len() as c_uint,
- Then,
- Catch,
- noname())
- }
+ B(cx).invoke(Fn, Args, Then, Catch)
}
pub fn FastInvoke(cx: block, Fn: ValueRef, Args: &[ValueRef],
if cx.unreachable { return; }
check_not_terminated(cx);
terminate(cx, "FastInvoke");
- unsafe {
- count_insn(cx, "fastinvoke");
- let v = llvm::LLVMBuildInvoke(B(cx), Fn, vec::raw::to_ptr(Args),
- Args.len() as c_uint,
- Then, Catch, noname());
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
- }
+ B(cx).fast_invoke(Fn, Args, Then, Catch);
}
pub fn Unreachable(cx: block) {
- unsafe {
- if cx.unreachable { return; }
- cx.unreachable = true;
- if !cx.terminated {
- count_insn(cx, "unreachable");
- llvm::LLVMBuildUnreachable(B(cx));
- }
+ if cx.unreachable { return; }
+ cx.unreachable = true;
+ if !cx.terminated {
+ B(cx).unreachable();
}
}
/* Arithmetic */
pub fn Add(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "add");
- return llvm::LLVMBuildAdd(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).add(LHS, RHS)
}
pub fn NSWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nswadd");
- return llvm::LLVMBuildNSWAdd(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nswadd(LHS, RHS)
}
pub fn NUWAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nuwadd");
- return llvm::LLVMBuildNUWAdd(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nuwadd(LHS, RHS)
}
pub fn FAdd(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "fadd");
- return llvm::LLVMBuildFAdd(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fadd(LHS, RHS)
}
pub fn Sub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "sub");
- return llvm::LLVMBuildSub(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).sub(LHS, RHS)
}
pub fn NSWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nwsub");
- return llvm::LLVMBuildNSWSub(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nswsub(LHS, RHS)
}
pub fn NUWSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nuwsub");
- return llvm::LLVMBuildNUWSub(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nuwsub(LHS, RHS)
}
pub fn FSub(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "sub");
- return llvm::LLVMBuildFSub(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fsub(LHS, RHS)
}
pub fn Mul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "mul");
- return llvm::LLVMBuildMul(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).mul(LHS, RHS)
}
pub fn NSWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nswmul");
- return llvm::LLVMBuildNSWMul(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nswmul(LHS, RHS)
}
pub fn NUWMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "nuwmul");
- return llvm::LLVMBuildNUWMul(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).nuwmul(LHS, RHS)
}
pub fn FMul(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "fmul");
- return llvm::LLVMBuildFMul(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fmul(LHS, RHS)
}
pub fn UDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "udiv");
- return llvm::LLVMBuildUDiv(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).udiv(LHS, RHS)
}
pub fn SDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "sdiv");
- return llvm::LLVMBuildSDiv(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).sdiv(LHS, RHS)
}
pub fn ExactSDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "extractsdiv");
- return llvm::LLVMBuildExactSDiv(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).exactsdiv(LHS, RHS)
}
pub fn FDiv(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "fdiv");
- return llvm::LLVMBuildFDiv(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).fdiv(LHS, RHS)
}
pub fn URem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "urem");
- return llvm::LLVMBuildURem(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).urem(LHS, RHS)
}
pub fn SRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "srem");
- return llvm::LLVMBuildSRem(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).srem(LHS, RHS)
}
pub fn FRem(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "frem");
- return llvm::LLVMBuildFRem(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).frem(LHS, RHS)
}
pub fn Shl(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "shl");
- return llvm::LLVMBuildShl(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).shl(LHS, RHS)
}
pub fn LShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "lshr");
- return llvm::LLVMBuildLShr(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).lshr(LHS, RHS)
}
pub fn AShr(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "ashr");
- return llvm::LLVMBuildAShr(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).ashr(LHS, RHS)
}
pub fn And(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "and");
- return llvm::LLVMBuildAnd(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).and(LHS, RHS)
}
pub fn Or(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "or");
- return llvm::LLVMBuildOr(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).or(LHS, RHS)
}
pub fn Xor(cx: block, LHS: ValueRef, RHS: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "xor");
- return llvm::LLVMBuildXor(B(cx), LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).xor(LHS, RHS)
}
pub fn BinOp(cx: block, Op: Opcode, LHS: ValueRef, RHS: ValueRef)
-> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(LHS); }
- count_insn(cx, "binop");
- return llvm::LLVMBuildBinOp(B(cx), Op, LHS, RHS, noname());
- }
+ if cx.unreachable { return _Undef(LHS); }
+ B(cx).binop(Op, LHS, RHS)
}
pub fn Neg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "neg");
- return llvm::LLVMBuildNeg(B(cx), V, noname());
- }
+ if cx.unreachable { return _Undef(V); }
+ B(cx).neg(V)
}
pub fn NSWNeg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "nswneg");
- return llvm::LLVMBuildNSWNeg(B(cx), V, noname());
- }
+ if cx.unreachable { return _Undef(V); }
+ B(cx).nswneg(V)
}
pub fn NUWNeg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "nuwneg");
- return llvm::LLVMBuildNUWNeg(B(cx), V, noname());
- }
+ if cx.unreachable { return _Undef(V); }
+ B(cx).nuwneg(V)
}
pub fn FNeg(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "fneg");
- return llvm::LLVMBuildFNeg(B(cx), V, noname());
- }
+ if cx.unreachable { return _Undef(V); }
+ B(cx).fneg(V)
}
pub fn Not(cx: block, V: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(V); }
- count_insn(cx, "not");
- return llvm::LLVMBuildNot(B(cx), V, noname());
- }
+ if cx.unreachable { return _Undef(V); }
+ B(cx).not(V)
}
/* Memory */
pub fn Malloc(cx: block, Ty: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "malloc");
- return llvm::LLVMBuildMalloc(B(cx), Ty.to_ref(), noname());
+ B(cx).malloc(Ty)
}
}
pub fn ArrayMalloc(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "arraymalloc");
- return llvm::LLVMBuildArrayMalloc(B(cx), Ty.to_ref(), Val, noname());
+ B(cx).array_malloc(Ty, Val)
}
}
pub fn Alloca(cx: block, Ty: Type, name: &str) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
- count_insn(cx, "alloca");
- if name.is_empty() {
- llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), noname())
- } else {
- str::as_c_str(
- name,
- |c| llvm::LLVMBuildAlloca(B(cx), Ty.to_ref(), c))
- }
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get());
+ b.alloca(Ty, name)
}
}
pub fn ArrayAlloca(cx: block, Ty: Type, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.ptr_to().to_ref()); }
- count_insn(cx, "arrayalloca");
- return llvm::LLVMBuildArrayAlloca(B(cx), Ty.to_ref(), Val, noname());
+ let b = cx.fcx.ccx.builder();
+ b.position_before(cx.fcx.alloca_insert_pt.get());
+ b.array_alloca(Ty, Val)
}
}
pub fn Free(cx: block, PointerVal: ValueRef) {
- unsafe {
- if cx.unreachable { return; }
- count_insn(cx, "free");
- llvm::LLVMBuildFree(B(cx), PointerVal);
- }
+ if cx.unreachable { return; }
+ B(cx).free(PointerVal)
}
pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef {
};
return llvm::LLVMGetUndef(eltty.to_ref());
}
- count_insn(cx, "load");
- return llvm::LLVMBuildLoad(B(cx), PointerVal, noname());
+ B(cx).load(PointerVal)
}
}
if cx.unreachable {
return llvm::LLVMGetUndef(ccx.int_type.to_ref());
}
- count_insn(cx, "load.atomic");
- let align = llalign_of_min(ccx, ccx.int_type);
- return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, noname(), order, align as c_uint);
+ B(cx).atomic_load(PointerVal, order)
}
}
pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong,
hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
- let value = Load(cx, PointerVal);
-
- if !cx.unreachable {
+ if cx.unreachable {
+ let ccx = cx.fcx.ccx;
+ let ty = val_ty(PointerVal);
+ let eltty = if ty.kind() == lib::llvm::Array {
+ ty.element_type()
+ } else {
+ ccx.int_type
+ };
unsafe {
- let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(PointerVal));
- let min = llvm::LLVMConstInt(t, lo, signed);
- let max = llvm::LLVMConstInt(t, hi, signed);
-
- do [min, max].as_imm_buf |ptr, len| {
- llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
- llvm::LLVMMDNodeInContext(cx.fcx.ccx.llcx,
- ptr, len as c_uint));
- }
+ llvm::LLVMGetUndef(eltty.to_ref())
}
+ } else {
+ B(cx).load_range_assert(PointerVal, lo, hi, signed)
}
-
- value
}
pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) {
- unsafe {
- if cx.unreachable { return; }
- debug!("Store %s -> %s",
- cx.val_to_str(Val),
- cx.val_to_str(Ptr));
- count_insn(cx, "store");
- llvm::LLVMBuildStore(B(cx), Val, Ptr);
- }
+ if cx.unreachable { return; }
+ B(cx).store(Val, Ptr)
}
pub fn AtomicStore(cx: block, Val: ValueRef, Ptr: ValueRef, order: AtomicOrdering) {
- unsafe {
- if cx.unreachable { return; }
- debug!("Store %s -> %s",
- cx.val_to_str(Val),
- cx.val_to_str(Ptr));
- count_insn(cx, "store.atomic");
- let align = llalign_of_min(cx.ccx(), cx.ccx().int_type);
- llvm::LLVMBuildAtomicStore(B(cx), Val, Ptr, order, align as c_uint);
- }
+ if cx.unreachable { return; }
+ B(cx).atomic_store(Val, Ptr, order)
}
pub fn GEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
- count_insn(cx, "gep");
- return llvm::LLVMBuildGEP(B(cx), Pointer, vec::raw::to_ptr(Indices),
- Indices.len() as c_uint, noname());
+ B(cx).gep(Pointer, Indices)
}
}
// in C_i32()
#[inline]
pub fn GEPi(cx: block, base: ValueRef, ixs: &[uint]) -> ValueRef {
- // Small vector optimization. This should catch 100% of the cases that
- // we care about.
- if ixs.len() < 16 {
- let mut small_vec = [ C_i32(0), ..16 ];
- for small_vec.mut_iter().zip(ixs.iter()).advance |(small_vec_e, &ix)| {
- *small_vec_e = C_i32(ix as i32);
- }
- InBoundsGEP(cx, base, small_vec.slice(0, ixs.len()))
- } else {
- let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>();
- count_insn(cx, "gepi");
- InBoundsGEP(cx, base, v)
+ unsafe {
+ if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
+ B(cx).gepi(base, ixs)
}
}
pub fn InBoundsGEP(cx: block, Pointer: ValueRef, Indices: &[ValueRef]) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
- count_insn(cx, "inboundsgep");
- return llvm::LLVMBuildInBoundsGEP(
- B(cx), Pointer, vec::raw::to_ptr(Indices), Indices.len() as c_uint, noname());
+ B(cx).inbounds_gep(Pointer, Indices)
}
}
pub fn StructGEP(cx: block, Pointer: ValueRef, Idx: uint) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().ptr_to().to_ref()); }
- count_insn(cx, "structgep");
- return llvm::LLVMBuildStructGEP(B(cx),
- Pointer,
- Idx as c_uint,
- noname());
+ B(cx).struct_gep(Pointer, Idx)
}
}
pub fn GlobalString(cx: block, _Str: *c_char) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "globalstring");
- return llvm::LLVMBuildGlobalString(B(cx), _Str, noname());
+ B(cx).global_string(_Str)
}
}
pub fn GlobalStringPtr(cx: block, _Str: *c_char) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i8p().to_ref()); }
- count_insn(cx, "globalstringptr");
- return llvm::LLVMBuildGlobalStringPtr(B(cx), _Str, noname());
+ B(cx).global_string_ptr(_Str)
}
}
pub fn Trunc(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "trunc");
- return llvm::LLVMBuildTrunc(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).trunc(Val, DestTy)
}
}
pub fn ZExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "zext");
- return llvm::LLVMBuildZExt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).zext(Val, DestTy)
}
}
pub fn SExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "sext");
- return llvm::LLVMBuildSExt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).sext(Val, DestTy)
}
}
pub fn FPToUI(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fptoui");
- return llvm::LLVMBuildFPToUI(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fptoui(Val, DestTy)
}
}
pub fn FPToSI(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fptosi");
- return llvm::LLVMBuildFPToSI(B(cx), Val, DestTy.to_ref(),noname());
+ B(cx).fptosi(Val, DestTy)
}
}
pub fn UIToFP(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "uitofp");
- return llvm::LLVMBuildUIToFP(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).uitofp(Val, DestTy)
}
}
pub fn SIToFP(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "sitofp");
- return llvm::LLVMBuildSIToFP(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).sitofp(Val, DestTy)
}
}
pub fn FPTrunc(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fptrunc");
- return llvm::LLVMBuildFPTrunc(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fptrunc(Val, DestTy)
}
}
pub fn FPExt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fpext");
- return llvm::LLVMBuildFPExt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fpext(Val, DestTy)
}
}
pub fn PtrToInt(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "ptrtoint");
- return llvm::LLVMBuildPtrToInt(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).ptrtoint(Val, DestTy)
}
}
pub fn IntToPtr(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "inttoptr");
- return llvm::LLVMBuildIntToPtr(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).inttoptr(Val, DestTy)
}
}
pub fn BitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "bitcast");
- return llvm::LLVMBuildBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).bitcast(Val, DestTy)
}
}
pub fn ZExtOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "zextorbitcast");
- return llvm::LLVMBuildZExtOrBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).zext_or_bitcast(Val, DestTy)
}
}
pub fn SExtOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "sextorbitcast");
- return llvm::LLVMBuildSExtOrBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).sext_or_bitcast(Val, DestTy)
}
}
pub fn TruncOrBitCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "truncorbitcast");
- return llvm::LLVMBuildTruncOrBitCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).trunc_or_bitcast(Val, DestTy)
}
}
pub fn Cast(cx: block, Op: Opcode, Val: ValueRef, DestTy: Type, _: *u8)
-> ValueRef {
unsafe {
- count_insn(cx, "cast");
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- return llvm::LLVMBuildCast(B(cx), Op, Val, DestTy.to_ref(), noname());
+ B(cx).cast(Op, Val, DestTy)
}
}
pub fn PointerCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "pointercast");
- return llvm::LLVMBuildPointerCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).pointercast(Val, DestTy)
}
}
pub fn IntCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "intcast");
- return llvm::LLVMBuildIntCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).intcast(Val, DestTy)
}
}
pub fn FPCast(cx: block, Val: ValueRef, DestTy: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(DestTy.to_ref()); }
- count_insn(cx, "fpcast");
- return llvm::LLVMBuildFPCast(B(cx), Val, DestTy.to_ref(), noname());
+ B(cx).fpcast(Val, DestTy)
}
}
-> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "icmp");
- return llvm::LLVMBuildICmp(B(cx), Op as c_uint, LHS, RHS, noname());
+ B(cx).icmp(Op, LHS, RHS)
}
}
-> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "fcmp");
- return llvm::LLVMBuildFCmp(B(cx), Op as c_uint, LHS, RHS, noname());
+ B(cx).fcmp(Op, LHS, RHS)
}
}
pub fn EmptyPhi(cx: block, Ty: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); }
- count_insn(cx, "emptyphi");
- return llvm::LLVMBuildPhi(B(cx), Ty.to_ref(), noname());
+ B(cx).empty_phi(Ty)
}
}
-pub fn Phi(cx: block, Ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef])
- -> ValueRef {
+pub fn Phi(cx: block, Ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); }
- assert_eq!(vals.len(), bbs.len());
- let phi = EmptyPhi(cx, Ty);
- count_insn(cx, "addincoming");
- llvm::LLVMAddIncoming(phi, vec::raw::to_ptr(vals),
- vec::raw::to_ptr(bbs),
- vals.len() as c_uint);
- return phi;
+ B(cx).phi(Ty, vals, bbs)
}
}
} else {
ccx.int_type
};
- count_insn(cx, "ret_undef");
- return llvm::LLVMGetUndef(retty.to_ref());
+ B(cx).count_insn("ret_undef");
+ llvm::LLVMGetUndef(retty.to_ref())
}
}
-pub fn add_span_comment(bcx: block, sp: span, text: &str) {
- let ccx = bcx.ccx();
- if ccx.sess.asm_comments() {
- let s = fmt!("%s (%s)", text, ccx.sess.codemap.span_to_str(sp));
- debug!("%s", s);
- add_comment(bcx, s);
- }
+pub fn add_span_comment(cx: block, sp: span, text: &str) {
+ B(cx).add_span_comment(sp, text)
}
-pub fn add_comment(bcx: block, text: &str) {
- unsafe {
- let ccx = bcx.ccx();
- if ccx.sess.asm_comments() {
- let sanitized = text.replace("$", "");
- let comment_text = ~"# " +
- sanitized.replace("\n", "\n\t# ");
- count_insn(bcx, "inlineasm");
- let asm = do comment_text.as_c_str |c| {
- llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
- c, noname(), False, False)
- };
- Call(bcx, asm, []);
- }
- }
+pub fn add_comment(cx: block, text: &str) {
+ B(cx).add_comment(text)
}
pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
inputs: &[ValueRef], output: Type,
volatile: bool, alignstack: bool,
dia: AsmDialect) -> ValueRef {
- unsafe {
- count_insn(cx, "inlineasm");
-
- let volatile = if volatile { lib::llvm::True }
- else { lib::llvm::False };
- let alignstack = if alignstack { lib::llvm::True }
- else { lib::llvm::False };
-
- let argtys = do inputs.map |v| {
- debug!("Asm Input Type: %?", cx.val_to_str(*v));
- val_ty(*v)
- };
-
- debug!("Asm Output Type: %?", cx.ccx().tn.type_to_str(output));
- let fty = Type::func(argtys, &output);
- let v = llvm::LLVMInlineAsm(fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
-
- Call(cx, v, inputs)
- }
+ B(cx).inline_asm_call(asm, cons, inputs, output, volatile, alignstack, dia)
}
pub fn Call(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- unsafe {
- count_insn(cx, "call");
-
- debug!("Call(Fn=%s, Args=%?)",
- cx.val_to_str(Fn),
- Args.map(|arg| cx.val_to_str(*arg)));
-
- do Args.as_imm_buf |ptr, len| {
- llvm::LLVMBuildCall(B(cx), Fn, ptr, len as c_uint, noname())
- }
- }
+ B(cx).call(Fn, Args)
}
pub fn FastCall(cx: block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- unsafe {
- count_insn(cx, "fastcall");
- let v = llvm::LLVMBuildCall(B(cx), Fn, vec::raw::to_ptr(Args),
- Args.len() as c_uint, noname());
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
- return v;
- }
+ B(cx).call(Fn, Args)
}
pub fn CallWithConv(cx: block, Fn: ValueRef, Args: &[ValueRef],
Conv: CallConv) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- unsafe {
- count_insn(cx, "callwithconv");
- let v = llvm::LLVMBuildCall(B(cx), Fn, vec::raw::to_ptr(Args),
- Args.len() as c_uint, noname());
- lib::llvm::SetInstructionCallConv(v, Conv);
- return v;
- }
+ B(cx).call_with_conv(Fn, Args, Conv)
}
-pub fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) ->
- ValueRef {
- unsafe {
- if cx.unreachable { return _Undef(Then); }
- count_insn(cx, "select");
- return llvm::LLVMBuildSelect(B(cx), If, Then, Else, noname());
- }
+pub fn Select(cx: block, If: ValueRef, Then: ValueRef, Else: ValueRef) -> ValueRef {
+ if cx.unreachable { return _Undef(Then); }
+ B(cx).select(If, Then, Else)
}
pub fn VAArg(cx: block, list: ValueRef, Ty: Type) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Ty.to_ref()); }
- count_insn(cx, "vaarg");
- return llvm::LLVMBuildVAArg(B(cx), list, Ty.to_ref(), noname());
+ B(cx).va_arg(list, Ty)
}
}
-pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) ->
- ValueRef {
+pub fn ExtractElement(cx: block, VecVal: ValueRef, Index: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "extractelement");
- return llvm::LLVMBuildExtractElement(B(cx), VecVal, Index, noname());
+ B(cx).extract_element(VecVal, Index)
}
}
Index: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "insertelement");
- llvm::LLVMBuildInsertElement(B(cx), VecVal, EltVal, Index, noname())
+ B(cx).insert_element(VecVal, EltVal, Index)
}
}
Mask: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "shufflevector");
- llvm::LLVMBuildShuffleVector(B(cx), V1, V2, Mask, noname())
+ B(cx).shuffle_vector(V1, V2, Mask)
}
}
pub fn VectorSplat(cx: block, NumElts: uint, EltVal: ValueRef) -> ValueRef {
unsafe {
- let elt_ty = val_ty(EltVal);
- let Undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, NumElts as u64).to_ref());
- let VecVal = InsertElement(cx, Undef, EltVal, C_i32(0));
- ShuffleVector(cx, VecVal, Undef, C_null(Type::vector(&Type::i32(), NumElts as u64)))
+ if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
+ B(cx).vector_splat(NumElts, EltVal)
}
}
pub fn ExtractValue(cx: block, AggVal: ValueRef, Index: uint) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
- count_insn(cx, "extractvalue");
- return llvm::LLVMBuildExtractValue(
- B(cx), AggVal, Index as c_uint, noname());
+ B(cx).extract_value(AggVal, Index)
}
}
-pub fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef,
- Index: uint) {
- unsafe {
- if cx.unreachable { return; }
- count_insn(cx, "insertvalue");
- llvm::LLVMBuildInsertValue(B(cx), AggVal, EltVal, Index as c_uint,
- noname());
- }
+pub fn InsertValue(cx: block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) {
+ if cx.unreachable { return; }
+ B(cx).insert_value(AggVal, EltVal, Index)
}
pub fn IsNull(cx: block, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "isnull");
- return llvm::LLVMBuildIsNull(B(cx), Val, noname());
+ B(cx).is_null(Val)
}
}
pub fn IsNotNull(cx: block, Val: ValueRef) -> ValueRef {
unsafe {
if cx.unreachable { return llvm::LLVMGetUndef(Type::i1().to_ref()); }
- count_insn(cx, "isnotnull");
- return llvm::LLVMBuildIsNotNull(B(cx), Val, noname());
+ B(cx).is_not_null(Val)
}
}
unsafe {
let ccx = cx.fcx.ccx;
if cx.unreachable { return llvm::LLVMGetUndef(ccx.int_type.to_ref()); }
- count_insn(cx, "ptrdiff");
- return llvm::LLVMBuildPtrDiff(B(cx), LHS, RHS, noname());
+ B(cx).ptrdiff(LHS, RHS)
}
}
pub fn Trap(cx: block) {
- unsafe {
- if cx.unreachable { return; }
- let b = B(cx);
- let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(b);
- let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
- let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
- let T: ValueRef = str::as_c_str("llvm.trap", |buf| {
- llvm::LLVMGetNamedFunction(M, buf)
- });
- assert!((T as int != 0));
- let Args: ~[ValueRef] = ~[];
- count_insn(cx, "trap");
- llvm::LLVMBuildCall(b, T, vec::raw::to_ptr(Args), Args.len() as c_uint, noname());
- }
+ if cx.unreachable { return; }
+ B(cx).trap();
}
pub fn LandingPad(cx: block, Ty: Type, PersFn: ValueRef,
NumClauses: uint) -> ValueRef {
- unsafe {
- check_not_terminated(cx);
- assert!(!cx.unreachable);
- count_insn(cx, "landingpad");
- return llvm::LLVMBuildLandingPad(
- B(cx), Ty.to_ref(), PersFn, NumClauses as c_uint, noname());
- }
+ check_not_terminated(cx);
+ assert!(!cx.unreachable);
+ B(cx).landing_pad(Ty, PersFn, NumClauses)
}
pub fn SetCleanup(cx: block, LandingPad: ValueRef) {
- unsafe {
- count_insn(cx, "setcleanup");
- llvm::LLVMSetCleanup(LandingPad, lib::llvm::True);
- }
+ B(cx).set_cleanup(LandingPad)
}
pub fn Resume(cx: block, Exn: ValueRef) -> ValueRef {
- unsafe {
- check_not_terminated(cx);
- terminate(cx, "Resume");
- count_insn(cx, "resume");
- return llvm::LLVMBuildResume(B(cx), Exn);
- }
+ check_not_terminated(cx);
+ terminate(cx, "Resume");
+ B(cx).resume(Exn)
}
// Atomic Operations
pub fn AtomicCmpXchg(cx: block, dst: ValueRef,
cmp: ValueRef, src: ValueRef,
order: AtomicOrdering) -> ValueRef {
- unsafe {
- llvm::LLVMBuildAtomicCmpXchg(B(cx), dst, cmp, src, order)
- }
+ B(cx).atomic_cmpxchg(dst, cmp, src, order)
}
pub fn AtomicRMW(cx: block, op: AtomicBinOp,
dst: ValueRef, src: ValueRef,
order: AtomicOrdering) -> ValueRef {
- unsafe {
- llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order)
- }
+ B(cx).atomic_rmw(op, dst, src, order)
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use lib;
+use lib::llvm::llvm;
+use lib::llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect};
+use lib::llvm::{Opcode, IntPredicate, RealPredicate, False};
+use lib::llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef};
+use middle::trans::base;
+use middle::trans::common::*;
+use middle::trans::machine::llalign_of_min;
+use middle::trans::type_::Type;
+use std::cast;
+use std::hashmap::HashMap;
+use std::libc::{c_uint, c_ulonglong, c_char};
+use std::str;
+use std::vec;
+use syntax::codemap::span;
+
+pub struct Builder {
+ llbuilder: BuilderRef,
+ ccx: @mut CrateContext,
+}
+
+// This is a really awful way to get a zero-length c-string, but better (and a
+// lot more efficient) than doing str::as_c_str("", ...) every time.
+pub fn noname() -> *c_char {
+ unsafe {
+ static cnull: uint = 0u;
+ cast::transmute(&cnull)
+ }
+}
+
+impl Builder {
+ pub fn new(ccx: @mut CrateContext) -> Builder {
+ Builder {
+ llbuilder: ccx.builder.B,
+ ccx: ccx,
+ }
+ }
+
+ pub fn count_insn(&self, category: &str) {
+ if self.ccx.sess.trans_stats() {
+ self.ccx.stats.n_llvm_insns += 1;
+ }
+ if self.ccx.sess.count_llvm_insns() {
+ do base::with_insn_ctxt |v| {
+ let h = &mut self.ccx.stats.llvm_insns;
+
+ // Build version of path with cycles removed.
+
+ // Pass 1: scan table mapping str -> rightmost pos.
+ let mut mm = HashMap::new();
+ let len = v.len();
+ let mut i = 0u;
+ while i < len {
+ mm.insert(v[i], i);
+ i += 1u;
+ }
+
+ // Pass 2: concat strings for each elt, skipping
+ // forwards over any cycles by advancing to rightmost
+ // occurrence of each element in path.
+ let mut s = ~".";
+ i = 0u;
+ while i < len {
+ i = *mm.get(&v[i]);
+ s.push_char('/');
+ s.push_str(v[i]);
+ i += 1u;
+ }
+
+ s.push_char('/');
+ s.push_str(category);
+
+ let n = match h.find(&s) {
+ Some(&n) => n,
+ _ => 0u
+ };
+ h.insert(s, n+1u);
+ }
+ }
+ }
+
+ pub fn position_before(&self, insn: ValueRef) {
+ unsafe {
+ llvm::LLVMPositionBuilderBefore(self.llbuilder, insn);
+ }
+ }
+
+ pub fn position_at_end(&self, llbb: BasicBlockRef) {
+ unsafe {
+ llvm::LLVMPositionBuilderAtEnd(self.llbuilder, llbb);
+ }
+ }
+
+ pub fn ret_void(&self) {
+ self.count_insn("retvoid");
+ unsafe {
+ llvm::LLVMBuildRetVoid(self.llbuilder);
+ }
+ }
+
+ pub fn ret(&self, v: ValueRef) {
+ self.count_insn("ret");
+ unsafe {
+ llvm::LLVMBuildRet(self.llbuilder, v);
+ }
+ }
+
+ pub fn aggregate_ret(&self, ret_vals: &[ValueRef]) {
+ unsafe {
+ llvm::LLVMBuildAggregateRet(self.llbuilder,
+ vec::raw::to_ptr(ret_vals),
+ ret_vals.len() as c_uint);
+ }
+ }
+
+ pub fn br(&self, dest: BasicBlockRef) {
+ self.count_insn("br");
+ unsafe {
+ llvm::LLVMBuildBr(self.llbuilder, dest);
+ }
+ }
+
+ pub fn cond_br(&self, cond: ValueRef, then_llbb: BasicBlockRef, else_llbb: BasicBlockRef) {
+ self.count_insn("condbr");
+ unsafe {
+ llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
+ }
+ }
+
+ pub fn switch(&self, v: ValueRef, else_llbb: BasicBlockRef, num_cases: uint) -> ValueRef {
+ unsafe {
+ llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, num_cases as c_uint)
+ }
+ }
+
+ pub fn indirect_br(&self, addr: ValueRef, num_dests: uint) {
+ self.count_insn("indirectbr");
+ unsafe {
+ llvm::LLVMBuildIndirectBr(self.llbuilder, addr, num_dests as c_uint);
+ }
+ }
+
+ pub fn invoke(&self,
+ llfn: ValueRef,
+ args: &[ValueRef],
+ then: BasicBlockRef,
+ catch: BasicBlockRef)
+ -> ValueRef {
+ self.count_insn("invoke");
+ unsafe {
+ llvm::LLVMBuildInvoke(self.llbuilder,
+ llfn,
+ vec::raw::to_ptr(args),
+ args.len() as c_uint,
+ then,
+ catch,
+ noname())
+ }
+ }
+
+ pub fn fast_invoke(&self,
+ llfn: ValueRef,
+ args: &[ValueRef],
+ then: BasicBlockRef,
+ catch: BasicBlockRef) {
+ self.count_insn("fastinvoke");
+ let v = self.invoke(llfn, args, then, catch);
+ lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
+ }
+
+ pub fn unreachable(&self) {
+ self.count_insn("unreachable");
+ unsafe {
+ llvm::LLVMBuildUnreachable(self.llbuilder);
+ }
+ }
+
+ /* Arithmetic */
+ pub fn add(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("add");
+ unsafe {
+ llvm::LLVMBuildAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nswadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nswadd");
+ unsafe {
+ llvm::LLVMBuildNSWAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nuwadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nuwadd");
+ unsafe {
+ llvm::LLVMBuildNUWAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fadd(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fadd");
+ unsafe {
+ llvm::LLVMBuildFAdd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn sub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("sub");
+ unsafe {
+ llvm::LLVMBuildSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nwsub");
+ unsafe {
+ llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nuwsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nuwsub");
+ unsafe {
+ llvm::LLVMBuildNUWSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("sub");
+ unsafe {
+ llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn mul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("mul");
+ unsafe {
+ llvm::LLVMBuildMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nswmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nswmul");
+ unsafe {
+ llvm::LLVMBuildNSWMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn nuwmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("nuwmul");
+ unsafe {
+ llvm::LLVMBuildNUWMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fmul(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fmul");
+ unsafe {
+ llvm::LLVMBuildFMul(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn udiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("udiv");
+ unsafe {
+ llvm::LLVMBuildUDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn sdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("sdiv");
+ unsafe {
+ llvm::LLVMBuildSDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn exactsdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("exactsdiv");
+ unsafe {
+ llvm::LLVMBuildExactSDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fdiv(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fdiv");
+ unsafe {
+ llvm::LLVMBuildFDiv(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn urem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("urem");
+ unsafe {
+ llvm::LLVMBuildURem(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn srem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("srem");
+ unsafe {
+ llvm::LLVMBuildSRem(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn frem(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("frem");
+ unsafe {
+ llvm::LLVMBuildFRem(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn shl(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("shl");
+ unsafe {
+ llvm::LLVMBuildShl(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn lshr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("lshr");
+ unsafe {
+ llvm::LLVMBuildLShr(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn ashr(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("ashr");
+ unsafe {
+ llvm::LLVMBuildAShr(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn and(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("and");
+ unsafe {
+ llvm::LLVMBuildAnd(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn or(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("or");
+ unsafe {
+ llvm::LLVMBuildOr(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn xor(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("xor");
+ unsafe {
+ llvm::LLVMBuildXor(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn binop(&self, op: Opcode, lhs: ValueRef, rhs: ValueRef)
+ -> ValueRef {
+ self.count_insn("binop");
+ unsafe {
+ llvm::LLVMBuildBinOp(self.llbuilder, op, lhs, rhs, noname())
+ }
+ }
+
+ pub fn neg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("neg");
+ unsafe {
+ llvm::LLVMBuildNeg(self.llbuilder, V, noname())
+ }
+ }
+
+ pub fn nswneg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("nswneg");
+ unsafe {
+ llvm::LLVMBuildNSWNeg(self.llbuilder, V, noname())
+ }
+ }
+
+ pub fn nuwneg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("nuwneg");
+ unsafe {
+ llvm::LLVMBuildNUWNeg(self.llbuilder, V, noname())
+ }
+ }
+ pub fn fneg(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("fneg");
+ unsafe {
+ llvm::LLVMBuildFNeg(self.llbuilder, V, noname())
+ }
+ }
+
+ pub fn not(&self, V: ValueRef) -> ValueRef {
+ self.count_insn("not");
+ unsafe {
+ llvm::LLVMBuildNot(self.llbuilder, V, noname())
+ }
+ }
+
+ /* Memory */
+ pub fn malloc(&self, ty: Type) -> ValueRef {
+ self.count_insn("malloc");
+ unsafe {
+ llvm::LLVMBuildMalloc(self.llbuilder, ty.to_ref(), noname())
+ }
+ }
+
+ pub fn array_malloc(&self, ty: Type, val: ValueRef) -> ValueRef {
+ self.count_insn("arraymalloc");
+ unsafe {
+ llvm::LLVMBuildArrayMalloc(self.llbuilder, ty.to_ref(), val, noname())
+ }
+ }
+
+ pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
+ self.count_insn("alloca");
+ unsafe {
+ if name.is_empty() {
+ llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname())
+ } else {
+ str::as_c_str(
+ name,
+ |c| llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), c))
+ }
+ }
+ }
+
+ pub fn array_alloca(&self, ty: Type, val: ValueRef) -> ValueRef {
+ self.count_insn("arrayalloca");
+ unsafe {
+ llvm::LLVMBuildArrayAlloca(self.llbuilder, ty.to_ref(), val, noname())
+ }
+ }
+
+ pub fn free(&self, ptr: ValueRef) {
+ self.count_insn("free");
+ unsafe {
+ llvm::LLVMBuildFree(self.llbuilder, ptr);
+ }
+ }
+
+ pub fn load(&self, ptr: ValueRef) -> ValueRef {
+ self.count_insn("load");
+ unsafe {
+ llvm::LLVMBuildLoad(self.llbuilder, ptr, noname())
+ }
+ }
+
+ pub fn atomic_load(&self, ptr: ValueRef, order: AtomicOrdering) -> ValueRef {
+ self.count_insn("load.atomic");
+ unsafe {
+ let align = llalign_of_min(self.ccx, self.ccx.int_type);
+ llvm::LLVMBuildAtomicLoad(self.llbuilder, ptr, noname(), order, align as c_uint)
+ }
+ }
+
+
+ pub fn load_range_assert(&self, ptr: ValueRef, lo: c_ulonglong,
+ hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
+ let value = self.load(ptr);
+
+ unsafe {
+ let t = llvm::LLVMGetElementType(llvm::LLVMTypeOf(ptr));
+ let min = llvm::LLVMConstInt(t, lo, signed);
+ let max = llvm::LLVMConstInt(t, hi, signed);
+
+ do [min, max].as_imm_buf |ptr, len| {
+ llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
+ llvm::LLVMMDNodeInContext(self.ccx.llcx,
+ ptr, len as c_uint));
+ }
+ }
+
+ value
+ }
+
+ pub fn store(&self, val: ValueRef, ptr: ValueRef) {
+ debug!("Store %s -> %s",
+ self.ccx.tn.val_to_str(val),
+ self.ccx.tn.val_to_str(ptr));
+ self.count_insn("store");
+ unsafe {
+ llvm::LLVMBuildStore(self.llbuilder, val, ptr);
+ }
+ }
+
+ pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
+ debug!("Store %s -> %s",
+ self.ccx.tn.val_to_str(val),
+ self.ccx.tn.val_to_str(ptr));
+ self.count_insn("store.atomic");
+ let align = llalign_of_min(self.ccx, self.ccx.int_type);
+ unsafe {
+ llvm::LLVMBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint);
+ }
+ }
+
+ pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
+ self.count_insn("gep");
+ unsafe {
+ llvm::LLVMBuildGEP(self.llbuilder, ptr, vec::raw::to_ptr(indices),
+ indices.len() as c_uint, noname())
+ }
+ }
+
+ // Simple wrapper around GEP that takes an array of ints and wraps them
+ // in C_i32()
+ #[inline]
+ pub fn gepi(&self, base: ValueRef, ixs: &[uint]) -> ValueRef {
+ // Small vector optimization. This should catch 100% of the cases that
+ // we care about.
+ if ixs.len() < 16 {
+ let mut small_vec = [ C_i32(0), ..16 ];
+ for small_vec.mut_iter().zip(ixs.iter()).advance |(small_vec_e, &ix)| {
+ *small_vec_e = C_i32(ix as i32);
+ }
+ self.inbounds_gep(base, small_vec.slice(0, ixs.len()))
+ } else {
+ let v = do ixs.iter().transform |i| { C_i32(*i as i32) }.collect::<~[ValueRef]>();
+ self.count_insn("gepi");
+ self.inbounds_gep(base, v)
+ }
+ }
+
+ pub fn inbounds_gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
+ self.count_insn("inboundsgep");
+ unsafe {
+ llvm::LLVMBuildInBoundsGEP(
+ self.llbuilder, ptr, vec::raw::to_ptr(indices), indices.len() as c_uint, noname())
+ }
+ }
+
+ pub fn struct_gep(&self, ptr: ValueRef, idx: uint) -> ValueRef {
+ self.count_insn("structgep");
+ unsafe {
+ llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, noname())
+ }
+ }
+
+ pub fn global_string(&self, _Str: *c_char) -> ValueRef {
+ self.count_insn("globalstring");
+ unsafe {
+ llvm::LLVMBuildGlobalString(self.llbuilder, _Str, noname())
+ }
+ }
+
+ pub fn global_string_ptr(&self, _Str: *c_char) -> ValueRef {
+ self.count_insn("globalstringptr");
+ unsafe {
+ llvm::LLVMBuildGlobalStringPtr(self.llbuilder, _Str, noname())
+ }
+ }
+
+ /* Casts */
+ pub fn trunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("trunc");
+ unsafe {
+ llvm::LLVMBuildTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn zext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("zext");
+ unsafe {
+ llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn sext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("sext");
+ unsafe {
+ llvm::LLVMBuildSExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fptoui(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fptoui");
+ unsafe {
+ llvm::LLVMBuildFPToUI(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fptosi(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fptosi");
+ unsafe {
+ llvm::LLVMBuildFPToSI(self.llbuilder, val, dest_ty.to_ref(),noname())
+ }
+ }
+
+ pub fn uitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("uitofp");
+ unsafe {
+ llvm::LLVMBuildUIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn sitofp(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("sitofp");
+ unsafe {
+ llvm::LLVMBuildSIToFP(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fptrunc(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fptrunc");
+ unsafe {
+ llvm::LLVMBuildFPTrunc(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fpext(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fpext");
+ unsafe {
+ llvm::LLVMBuildFPExt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn ptrtoint(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("ptrtoint");
+ unsafe {
+ llvm::LLVMBuildPtrToInt(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn inttoptr(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("inttoptr");
+ unsafe {
+ llvm::LLVMBuildIntToPtr(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("bitcast");
+ unsafe {
+ llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn zext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("zextorbitcast");
+ unsafe {
+ llvm::LLVMBuildZExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn sext_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("sextorbitcast");
+ unsafe {
+ llvm::LLVMBuildSExtOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn trunc_or_bitcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("truncorbitcast");
+ unsafe {
+ llvm::LLVMBuildTruncOrBitCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn cast(&self, op: Opcode, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("cast");
+ unsafe {
+ llvm::LLVMBuildCast(self.llbuilder, op, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn pointercast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("pointercast");
+ unsafe {
+ llvm::LLVMBuildPointerCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn intcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("intcast");
+ unsafe {
+ llvm::LLVMBuildIntCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+ pub fn fpcast(&self, val: ValueRef, dest_ty: Type) -> ValueRef {
+ self.count_insn("fpcast");
+ unsafe {
+ llvm::LLVMBuildFPCast(self.llbuilder, val, dest_ty.to_ref(), noname())
+ }
+ }
+
+
+ /* Comparisons */
+ pub fn icmp(&self, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("icmp");
+ unsafe {
+ llvm::LLVMBuildICmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
+ }
+ }
+
+ pub fn fcmp(&self, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("fcmp");
+ unsafe {
+ llvm::LLVMBuildFCmp(self.llbuilder, op as c_uint, lhs, rhs, noname())
+ }
+ }
+
+ /* Miscellaneous instructions */
+ pub fn empty_phi(&self, ty: Type) -> ValueRef {
+ self.count_insn("emptyphi");
+ unsafe {
+ llvm::LLVMBuildPhi(self.llbuilder, ty.to_ref(), noname())
+ }
+ }
+
+ pub fn phi(&self, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef {
+ assert_eq!(vals.len(), bbs.len());
+ let phi = self.empty_phi(ty);
+ self.count_insn("addincoming");
+ unsafe {
+ llvm::LLVMAddIncoming(phi, vec::raw::to_ptr(vals),
+ vec::raw::to_ptr(bbs),
+ vals.len() as c_uint);
+ phi
+ }
+ }
+
+ pub fn add_span_comment(&self, sp: span, text: &str) {
+ if self.ccx.sess.asm_comments() {
+ let s = fmt!("%s (%s)", text, self.ccx.sess.codemap.span_to_str(sp));
+ debug!("%s", s);
+ self.add_comment(s);
+ }
+ }
+
+ pub fn add_comment(&self, text: &str) {
+ if self.ccx.sess.asm_comments() {
+ let sanitized = text.replace("$", "");
+ let comment_text = fmt!("# %s", sanitized.replace("\n", "\n\t# "));
+ self.count_insn("inlineasm");
+ let asm = do comment_text.as_c_str |c| {
+ unsafe {
+ llvm::LLVMConstInlineAsm(Type::func([], &Type::void()).to_ref(),
+ c, noname(), False, False)
+ }
+ };
+ self.call(asm, []);
+ }
+ }
+
+ pub fn inline_asm_call(&self, asm: *c_char, cons: *c_char,
+ inputs: &[ValueRef], output: Type,
+ volatile: bool, alignstack: bool,
+ dia: AsmDialect) -> ValueRef {
+ self.count_insn("inlineasm");
+
+ let volatile = if volatile { lib::llvm::True }
+ else { lib::llvm::False };
+ let alignstack = if alignstack { lib::llvm::True }
+ else { lib::llvm::False };
+
+ let argtys = do inputs.map |v| {
+ debug!("Asm Input Type: %?", self.ccx.tn.val_to_str(*v));
+ val_ty(*v)
+ };
+
+ debug!("Asm Output Type: %?", self.ccx.tn.type_to_str(output));
+ let fty = Type::func(argtys, &output);
+ unsafe {
+ let v = llvm::LLVMInlineAsm(
+ fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
+ self.call(v, inputs)
+ }
+ }
+
+ pub fn call(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
+ self.count_insn("call");
+
+ debug!("Call(llfn=%s, args=%?)",
+ self.ccx.tn.val_to_str(llfn),
+ args.map(|arg| self.ccx.tn.val_to_str(*arg)));
+
+ do args.as_imm_buf |ptr, len| {
+ unsafe {
+ llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
+ }
+ }
+ }
+
+ pub fn fastcall(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
+ self.count_insn("fastcall");
+ unsafe {
+ let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
+ args.len() as c_uint, noname());
+ lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
+ v
+ }
+ }
+
+ pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
+ conv: CallConv) -> ValueRef {
+ self.count_insn("callwithconv");
+ unsafe {
+ let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
+ args.len() as c_uint, noname());
+ lib::llvm::SetInstructionCallConv(v, conv);
+ v
+ }
+ }
+
+ pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
+ self.count_insn("select");
+ unsafe {
+ llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, noname())
+ }
+ }
+
+ pub fn va_arg(&self, list: ValueRef, ty: Type) -> ValueRef {
+ self.count_insn("vaarg");
+ unsafe {
+ llvm::LLVMBuildVAArg(self.llbuilder, list, ty.to_ref(), noname())
+ }
+ }
+
+ pub fn extract_element(&self, vec: ValueRef, idx: ValueRef) -> ValueRef {
+ self.count_insn("extractelement");
+ unsafe {
+ llvm::LLVMBuildExtractElement(self.llbuilder, vec, idx, noname())
+ }
+ }
+
+ pub fn insert_element(&self, vec: ValueRef, elt: ValueRef, idx: ValueRef) -> ValueRef {
+ self.count_insn("insertelement");
+ unsafe {
+ llvm::LLVMBuildInsertElement(self.llbuilder, vec, elt, idx, noname())
+ }
+ }
+
+ pub fn shuffle_vector(&self, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef {
+ self.count_insn("shufflevector");
+ unsafe {
+ llvm::LLVMBuildShuffleVector(self.llbuilder, v1, v2, mask, noname())
+ }
+ }
+
+ pub fn vector_splat(&self, num_elts: uint, elt: ValueRef) -> ValueRef {
+ unsafe {
+ let elt_ty = val_ty(elt);
+ let Undef = llvm::LLVMGetUndef(Type::vector(&elt_ty, num_elts as u64).to_ref());
+ let vec = self.insert_element(Undef, elt, C_i32(0));
+ self.shuffle_vector(vec, Undef, C_null(Type::vector(&Type::i32(), num_elts as u64)))
+ }
+ }
+
+ pub fn extract_value(&self, agg_val: ValueRef, idx: uint) -> ValueRef {
+ self.count_insn("extractvalue");
+ unsafe {
+ llvm::LLVMBuildExtractValue(self.llbuilder, agg_val, idx as c_uint, noname())
+ }
+ }
+
+ pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
+ idx: uint) {
+ self.count_insn("insertvalue");
+ unsafe {
+ llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
+ noname());
+ }
+ }
+
+ pub fn is_null(&self, val: ValueRef) -> ValueRef {
+ self.count_insn("isnull");
+ unsafe {
+ llvm::LLVMBuildIsNull(self.llbuilder, val, noname())
+ }
+ }
+
+ pub fn is_not_null(&self, val: ValueRef) -> ValueRef {
+ self.count_insn("isnotnull");
+ unsafe {
+ llvm::LLVMBuildIsNotNull(self.llbuilder, val, noname())
+ }
+ }
+
+ pub fn ptrdiff(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
+ self.count_insn("ptrdiff");
+ unsafe {
+ llvm::LLVMBuildPtrDiff(self.llbuilder, lhs, rhs, noname())
+ }
+ }
+
+ pub fn trap(&self) {
+ unsafe {
+ let BB: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder);
+ let FN: ValueRef = llvm::LLVMGetBasicBlockParent(BB);
+ let M: ModuleRef = llvm::LLVMGetGlobalParent(FN);
+ let T: ValueRef = str::as_c_str("llvm.trap", |buf| {
+ llvm::LLVMGetNamedFunction(M, buf)
+ });
+ assert!((T as int != 0));
+ let args: &[ValueRef] = [];
+ self.count_insn("trap");
+ llvm::LLVMBuildCall(
+ self.llbuilder, T, vec::raw::to_ptr(args), args.len() as c_uint, noname());
+ }
+ }
+
+ pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, num_clauses: uint) -> ValueRef {
+ self.count_insn("landingpad");
+ unsafe {
+ llvm::LLVMBuildLandingPad(
+ self.llbuilder, ty.to_ref(), pers_fn, num_clauses as c_uint, noname())
+ }
+ }
+
+ pub fn set_cleanup(&self, landing_pad: ValueRef) {
+ self.count_insn("setcleanup");
+ unsafe {
+ llvm::LLVMSetCleanup(landing_pad, lib::llvm::True);
+ }
+ }
+
+ pub fn resume(&self, exn: ValueRef) -> ValueRef {
+ self.count_insn("resume");
+ unsafe {
+ llvm::LLVMBuildResume(self.llbuilder, exn)
+ }
+ }
+
+ // Atomic Operations
+ pub fn atomic_cmpxchg(&self, dst: ValueRef,
+ cmp: ValueRef, src: ValueRef,
+ order: AtomicOrdering) -> ValueRef {
+ unsafe {
+ llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, order)
+ }
+ }
+ pub fn atomic_rmw(&self, op: AtomicBinOp,
+ dst: ValueRef, src: ValueRef,
+ order: AtomicOrdering) -> ValueRef {
+ unsafe {
+ llvm::LLVMBuildAtomicRMW(self.llbuilder, op, dst, src, order)
+ }
+ }
+}
ArgVals(args), Some(dest), DontAutorefArg).bcx;
}
-pub fn body_contains_ret(body: &ast::blk) -> bool {
+pub fn body_contains_ret(body: &ast::Block) -> bool {
let cx = @mut false;
visit::visit_block(body, (cx, visit::mk_vt(@visit::Visitor {
visit_item: |_i, (_cx, _v)| { },
use back::abi;
use back::link::{mangle_internal_name_by_path_and_seq};
-use lib::llvm::{llvm, ValueRef};
+use lib::llvm::ValueRef;
use middle::moves;
use middle::trans::base::*;
use middle::trans::build::*;
use middle::trans::type_::Type;
-use std::str;
use std::vec;
use syntax::ast;
use syntax::ast_map::path_name;
sigil: ast::Sigil) {
let _icx = push_ctxt("closure::load_environment");
- let llloadenv = match fcx.llloadenv {
- Some(ll) => ll,
- None => {
- let ll =
- str::as_c_str("load_env",
- |buf|
- unsafe {
- llvm::LLVMAppendBasicBlockInContext(fcx.ccx.llcx,
- fcx.llfn,
- buf)
- });
- fcx.llloadenv = Some(ll);
- ll
- }
- };
+ // Don't bother to create the block if there's nothing to load
+ if cap_vars.len() == 0 && !load_ret_handle {
+ return;
+ }
- let bcx = raw_block(fcx, false, llloadenv);
+ let bcx = fcx.entry_bcx.get();
// Load a pointer to the closure data, skipping over the box header:
let llcdata = opaque_box_body(bcx, cdata_ty, fcx.llenv);
pub fn trans_expr_fn(bcx: block,
sigil: ast::Sigil,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
outer_id: ast::node_id,
user_id: ast::node_id,
is_loop_body: Option<Option<ValueRef>>,
// always be Some.
llretptr: Option<ValueRef>,
+ entry_bcx: Option<block>,
+
// These elements: "hoisted basic blocks" containing
// administrative activities that have to happen in only one place in
// the function, due to LLVM's quirks.
- // A block for all the function's static allocas, so that LLVM
- // will coalesce them into a single alloca call.
- llstaticallocas: Option<BasicBlockRef>,
- // A block containing code that copies incoming arguments to space
- // already allocated by code in one of the llallocas blocks.
- // (LLVM requires that arguments be copied to local allocas before
- // allowing most any operation to be performed on them.)
- llloadenv: Option<BasicBlockRef>,
+ // A marker for the place where we want to insert the function's static
+ // allocas, so that LLVM will coalesce them into a single alloca call.
+ alloca_insert_pt: Option<ValueRef>,
llreturn: Option<BasicBlockRef>,
// The 'self' value currently in use in this function, if there
// is one.
}
}
- pub fn get_llstaticallocas(&mut self) -> BasicBlockRef {
- if self.llstaticallocas.is_none() {
- self.llstaticallocas = Some(base::mk_staticallocas_basic_block(self.llfn));
+ pub fn cleanup(&mut self) {
+ unsafe {
+ llvm::LLVMInstructionEraseFromParent(self.alloca_insert_pt.get());
}
-
- self.llstaticallocas.get()
+ // Remove the cycle between fcx and bcx, so memory can be freed
+ self.entry_bcx = None;
}
pub fn get_llreturn(&mut self) -> BasicBlockRef {
}
}
-impl get_node_info for ast::blk {
+impl get_node_info for ast::Block {
fn info(&self) -> Option<NodeInfo> {
Some(NodeInfo {id: self.id,
callee_id: None,
do expr::with_field_tys(tcx, ety, Some(e.id))
|discr, field_tys| {
let cs = field_tys.map(|field_ty| {
- match fs.iter().find_(|f| field_ty.ident == f.node.ident) {
- Some(f) => const_expr(cx, (*f).node.expr),
+ match fs.iter().find_(|f| field_ty.ident == f.ident) {
+ Some(f) => const_expr(cx, (*f).expr),
None => {
cx.tcx.sess.span_bug(e.span, "missing struct field");
}
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
+use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::type_use;
use middle::ty;
}
}
}
+
+ pub fn builder(@mut self) -> Builder {
+ Builder::new(self)
+ }
}
#[unsafe_destructor]
}
}
-#[cfg(stage0)]
-fn task_local_llcx_key(_v: @ContextRef) {}
-#[cfg(not(stage0))]
static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
pub fn task_llcx() -> ContextRef {
use syntax::ast_util;
use syntax::codemap::span;
-pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block {
+pub fn trans_block(bcx: block, b: &ast::Block, dest: expr::Dest) -> block {
let _icx = push_ctxt("trans_block");
let mut bcx = bcx;
for b.stmts.iter().advance |s| {
pub fn trans_if(bcx: block,
cond: @ast::expr,
- thn: &ast::blk,
+ thn: &ast::Block,
els: Option<@ast::expr>,
dest: expr::Dest)
-> block {
return out;
}
-pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::blk) -> block {
+pub fn trans_while(bcx: block, cond: @ast::expr, body: &ast::Block) -> block {
let _icx = push_ctxt("trans_while");
let next_bcx = sub_block(bcx, "while next");
}
pub fn trans_loop(bcx:block,
- body: &ast::blk,
+ body: &ast::Block,
opt_label: Option<ident>)
-> block {
let _icx = push_ctxt("trans_loop");
///
/// Adds the created metadata nodes directly to the crate's IR.
/// The return value should be ignored if called from outside of the debuginfo module.
-pub fn create_local_var_metadata(bcx: block, local: @ast::local) -> DIVariable {
+pub fn create_local_var_metadata(bcx: block, local: @ast::Local) -> DIVariable {
let cx = bcx.ccx();
- let ident = match local.node.pat.node {
+ let ident = match local.pat.node {
ast::pat_ident(_, ref pth, _) => ast_util::path_to_ident(pth),
// FIXME this should be handled (#2533)
_ => {
debug!("create_local_var_metadata: %s", name);
let loc = span_start(cx, local.span);
- let ty = node_id_type(bcx, local.node.id);
- let type_metadata = type_metadata(cx, ty, local.node.ty.span);
+ let ty = node_id_type(bcx, local.id);
+ let type_metadata = type_metadata(cx, ty, local.ty.span);
let file_metadata = file_metadata(cx, loc.file.name);
let context = match bcx.parent {
};
// FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc
- let llptr = match bcx.fcx.lllocals.find_copy(&local.node.pat.id) {
+ let llptr = match bcx.fcx.lllocals.find_copy(&local.pat.id) {
Some(v) => v,
None => {
bcx.tcx().sess.span_bug(
local.span,
- fmt!("No entry in lllocals table for %?", local.node.id));
+ fmt!("No entry in lllocals table for %?", local.id));
}
};
set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_metadata, bcx.llbb);
- llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
+ llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
return var_metadata;
unsafe {
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx), llptr, var_metadata, bcx.llbb);
- llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
+ llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
}
return Some(var_metadata);
}
span);
}
-// The stage0 snapshot does not yet support the fixes from PR #7557, so there are two versions of
-// following function for now
-#[cfg(not(stage0))]
fn enum_metadata(cx: &mut CrateContext,
enum_type: ty::t,
enum_def_id: ast::def_id,
}
}
-#[cfg(stage0)]
-fn enum_metadata(cx: &mut CrateContext,
- enum_type: ty::t,
- enum_def_id: ast::def_id,
- substs: &ty::substs,
- span: span)
- -> DIType {
-
- let enum_name = ty_to_str(cx.tcx, enum_type);
-
- // For empty enums there is an early exit. Just describe it as an empty struct with the
- // appropriate type name
- if ty::type_is_empty(cx.tcx, enum_type) {
- return composite_type_metadata(cx, Type::nil(), enum_name, &[], &[], &[], span);
- }
-
- // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
- // needed in all of the following cases.
- let discriminant_llvm_type = Type::enum_discrim(cx);
- let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
-
- assert!(Type::enum_discrim(cx) == cx.int_type);
- let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span);
-
- let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
-
- let enumerators_metadata: ~[DIDescriptor] = variants
- .iter()
- .transform(|v| {
- let name: &str = cx.sess.str_of(v.name);
- let discriminant_value = v.disr_val as c_ulonglong;
-
- do name.as_c_str |name| {
- unsafe {
- llvm::LLVMDIBuilderCreateEnumerator(
- DIB(cx),
- name,
- discriminant_value)
- }
- }
- })
- .collect();
-
- let loc = span_start(cx, span);
- let file_metadata = file_metadata(cx, loc.file.name);
-
- let discriminant_type_metadata = do enum_name.as_c_str |enum_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateEnumerationType(
- DIB(cx),
- file_metadata,
- enum_name,
- file_metadata,
- loc.line as c_uint,
- bytes_to_bits(discriminant_size),
- bytes_to_bits(discriminant_align),
- create_DIArray(DIB(cx), enumerators_metadata),
- discriminant_type_metadata)
- }
- };
-
- if ty::type_is_c_like_enum(cx.tcx, enum_type) {
- return discriminant_type_metadata;
- }
-
- let is_univariant = variants.len() == 1;
-
- let variants_metadata = do variants.map |&vi| {
-
- let raw_types: &[ty::t] = vi.args;
- let arg_types = do raw_types.map |&raw_type| { ty::subst(cx.tcx, substs, raw_type) };
-
- let mut arg_llvm_types = do arg_types.map |&ty| { type_of::type_of(cx, ty) };
- let mut arg_names = match vi.arg_names {
- Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() },
- None => do arg_types.map |_| { ~"" }
- };
-
- let mut arg_metadata = do arg_types.map |&ty| { type_metadata(cx, ty, span) };
-
- if !is_univariant {
- arg_llvm_types.insert(0, discriminant_llvm_type);
- arg_names.insert(0, ~"");
- arg_metadata.insert(0, discriminant_type_metadata);
- }
-
- let variant_llvm_type = Type::struct_(arg_llvm_types, false);
- let (variant_type_size, variant_type_align) = size_and_align_of(cx, variant_llvm_type);
-
- let variant_type_metadata = composite_type_metadata(
- cx,
- variant_llvm_type,
- &"",
- arg_llvm_types,
- arg_names,
- arg_metadata,
- span);
-
- do "".as_c_str |name| {
- unsafe {
- llvm::LLVMDIBuilderCreateMemberType(
- DIB(cx),
- file_metadata,
- name,
- file_metadata,
- loc.line as c_uint,
- bytes_to_bits(variant_type_size),
- bytes_to_bits(variant_type_align),
- bytes_to_bits(0),
- 0,
- variant_type_metadata)
- }
- }
- };
-
- let enum_llvm_type = type_of::type_of(cx, enum_type);
- let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
-
- return do enum_name.as_c_str |enum_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateUnionType(
- DIB(cx),
- file_metadata,
- enum_name,
- file_metadata,
- loc.line as c_uint,
- bytes_to_bits(enum_type_size),
- bytes_to_bits(enum_type_align),
- 0, // Flags
- create_DIArray(DIB(cx), variants_metadata),
- 0) // RuntimeLang
- }
- };
-}
-
-
/// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
///
/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
}
fn trans_rec_or_struct(bcx: block,
- fields: &[ast::field],
+ fields: &[ast::Field],
base: Option<@ast::expr>,
expr_span: codemap::span,
id: ast::node_id,
let mut need_base = vec::from_elem(field_tys.len(), true);
let numbered_fields = do fields.map |field| {
- let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.node.ident);
+ let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.ident);
match opt_pos {
Some(i) => {
need_base[i] = false;
- (i, field.node.expr)
+ (i, field.expr)
}
None => {
tcx.sess.span_bug(field.span,
// Declare the body of the shim function:
let fcx = new_fn_ctxt(ccx, ~[], llshimfn, tys.fn_sig.output, None);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let llargbundle = get_param(llshimfn, 0u);
let llargvals = arg_builder(bcx, tys, llargbundle);
// Don't finish up the function in the usual way, because this doesn't
// follow the normal Rust calling conventions.
- tie_up_header_blocks(fcx, lltop);
-
let ret_cx = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
None => bcx
};
RetVoid(ret_cx);
+ fcx.cleanup();
return llshimfn;
}
ret_builder: wrap_ret_builder) {
let _icx = push_ctxt("foreign::build_wrap_fn_");
let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, tys.fn_sig.output, None);
+ let bcx = fcx.entry_bcx.get();
// Patch up the return type if it's not immediate and we're returning via
// the C ABI.
if needs_c_return && !ty::type_is_immediate(ccx.tcx, tys.fn_sig.output) {
let lloutputtype = type_of::type_of(fcx.ccx, tys.fn_sig.output);
- fcx.llretptr = Some(alloca(raw_block(fcx, false, fcx.get_llstaticallocas()),
- lloutputtype,
- ""));
+ fcx.llretptr = Some(alloca(bcx, lloutputtype, ""));
}
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
-
// Allocate the struct and write the arguments into it.
let llargbundle = alloca(bcx, tys.bundle_ty, "__llargbundle");
arg_builder(bcx, tys, llwrapfn, llargbundle);
Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]);
ret_builder(bcx, tys, llargbundle);
- // Perform a custom version of `finish_fn`. First, tie up the header
- // blocks.
- tie_up_header_blocks(fcx, lltop);
-
// Then return according to the C ABI.
let return_context = match fcx.llreturn {
Some(llreturn) => raw_block(fcx, false, llreturn),
let llretptr = BitCast(return_context, fcx.llretptr.get(), return_type.ptr_to());
Ret(return_context, Load(return_context, llretptr));
}
+ fcx.cleanup();
}
// For each foreign function F, we generate a wrapper function W and a shim
debug!("build_direct_fn(%s)", link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
let ty = ty::lookup_item_type(ccx.tcx,
ast_util::local_def(item.id)).ty;
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all
debug!("build_fast_ffi_fn(%s)", link_name(ccx, item));
let fcx = new_fn_ctxt(ccx, ~[], decl, tys.fn_sig.output, None);
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let llbasefn = base_fn(ccx, link_name(ccx, item), tys, cc);
set_no_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
Store(bcx, retval, fcx.llretptr.get());
}
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
}
fn build_wrap_fn(ccx: @mut CrateContext,
output_type,
true,
Some(substs),
+ None,
Some(item.span));
set_always_inline(fcx.llfn);
set_fixed_stack_segment(fcx.llfn);
}
- let mut bcx = top_scope_block(fcx, None);
+ let mut bcx = fcx.entry_bcx.get();
let first_real_arg = fcx.arg_pos(0u);
let nm = ccx.sess.str_of(item.ident);
}
}
+ fcx.cleanup();
return;
}
ccx.sess.span_bug(item.span, "unknown intrinsic");
}
}
+ fcx.cleanup();
}
/**
pub fn trans_foreign_fn(ccx: @mut CrateContext,
path: ast_map::path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
llwrapfn: ValueRef,
id: ast::node_id) {
let _icx = push_ctxt("foreign::build_foreign_fn");
fn build_rust_fn(ccx: @mut CrateContext,
path: &ast_map::path,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
id: ast::node_id)
-> ValueRef {
let _icx = push_ctxt("foreign::foreign::build_rust_fn");
let _icx = push_ctxt("decr_refcnt_maybe_free");
let ccx = bcx.ccx();
- do with_cond(bcx, IsNotNull(bcx, box_ptr)) |bcx| {
- let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
- let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
- Store(bcx, rc, rc_ptr);
- let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
- do with_cond(bcx, zero_test) |bcx| {
- match box_ptr_ptr {
- Some(p) => free_ty(bcx, p, t),
- None => free_ty_immediate(bcx, box_ptr, t)
- }
- }
- }
+ let decr_bcx = sub_block(bcx, "decr");
+ let free_bcx = sub_block(decr_bcx, "free");
+ let next_bcx = sub_block(bcx, "next");
+ CondBr(bcx, IsNotNull(bcx, box_ptr), decr_bcx.llbb, next_bcx.llbb);
+
+ let rc_ptr = GEPi(decr_bcx, box_ptr, [0u, abi::box_field_refcnt]);
+ let rc = Sub(decr_bcx, Load(decr_bcx, rc_ptr), C_int(ccx, 1));
+ Store(decr_bcx, rc, rc_ptr);
+ CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
+
+ let free_bcx = match box_ptr_ptr {
+ Some(p) => free_ty(free_bcx, p, t),
+ None => free_ty_immediate(free_bcx, box_ptr, t)
+ };
+ Br(free_bcx, next_bcx.llbb);
+
+ next_bcx
}
// Zero out the struct
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(v));
- memzero(bcx, v, ty);
+ memzero(&B(bcx), v, ty);
}
}
// llfn is expected be declared to take a parameter of the appropriate
// type, so we don't need to explicitly cast the function parameter.
- let bcx = top_scope_block(fcx, None);
- let lltop = bcx.llbb;
+ let bcx = fcx.entry_bcx.get();
let rawptr0_arg = fcx.arg_pos(0u);
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
let bcx = helper(bcx, llrawptr0, t);
- finish_fn(fcx, lltop, bcx);
+ finish_fn(fcx, bcx);
return llfn;
}
pub mod consts;
pub mod type_of;
pub mod build;
+pub mod builder;
pub mod base;
pub mod _match;
pub mod uniq;
//
llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
};
- let mut bcx = top_scope_block(fcx, None);
+ let mut bcx = fcx.entry_bcx.get();
let arg = BitCast(bcx, arg, llptrty);
let ret = adt::trans_get_discr(bcx, repr, arg);
Store(bcx, ret, fcx.llretptr.get());
Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
None => bcx = cleanup_block(bcx, Some(bcx.llbb))
};
- finish_fn(fcx, bcx.llbb, bcx);
+ finish_fn(fcx, bcx);
llfdecl
};
}
}
-pub fn handle_body(cx: &Context, body: &blk) {
+pub fn handle_body(cx: &Context, body: &Block) {
let v = visit::mk_vt(@visit::Visitor {
visit_expr: |e, (cx, v)| {
visit::visit_expr(e, (cx, v));
},
visit_local: |l, (cx, v)| {
visit::visit_local(l, (cx, v));
- node_type_needs(cx, use_repr, l.node.id);
+ node_type_needs(cx, use_repr, l.id);
},
visit_pat: |p, (cx, v)| {
visit::visit_pat(p, (cx, v));
}
// Type accessors for AST nodes
-pub fn block_ty(cx: ctxt, b: &ast::blk) -> t {
+pub fn block_ty(cx: ctxt, b: &ast::Block) -> t {
return node_id_to_type(cx, b.id);
}
PurityState { def: def, purity: purity, from_fn: true }
}
- pub fn recurse(&mut self, blk: &ast::blk) -> PurityState {
+ pub fn recurse(&mut self, blk: &ast::Block) -> PurityState {
match self.purity {
// If this unsafe, then if the outer function was already marked as
// unsafe we shouldn't attribute the unsafe'ness to the block. This
}
}
-pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) {
+pub fn check_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
let visit = visit::mk_simple_visitor(@visit::SimpleVisitor {
visit_item: |a| check_item(ccx, a),
.. *visit::default_simple_visitor()
pub fn check_bare_fn(ccx: @mut CrateCtxt,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
id: ast::node_id,
self_info: Option<SelfInfo>) {
let fty = ty::node_id_to_type(ccx.tcx, id);
fn_sig: &ty::FnSig,
decl: &ast::fn_decl,
id: ast::node_id,
- body: &ast::blk,
+ body: &ast::Block,
fn_kind: FnKind,
inherited_isr: isr_alist,
inherited: @inherited) -> @mut FnCtxt
fn gather_locals(fcx: @mut FnCtxt,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
arg_tys: &[ty::t],
opt_self_info: Option<SelfInfo>) {
let tcx = fcx.ccx.tcx;
}
// Add explicitly-declared locals.
- let visit_local: @fn(@ast::local, ((), visit::vt<()>)) =
+ let visit_local: @fn(@ast::Local, ((), visit::vt<()>)) =
|local, (e, v)| {
- let o_ty = match local.node.ty.node {
+ let o_ty = match local.ty.node {
ast::ty_infer => None,
- _ => Some(fcx.to_ty(&local.node.ty))
+ _ => Some(fcx.to_ty(&local.ty))
};
- assign(local.node.id, o_ty);
+ assign(local.id, o_ty);
debug!("Local variable %s is assigned type %s",
- fcx.pat_to_str(local.node.pat),
+ fcx.pat_to_str(local.pat),
fcx.infcx().ty_to_str(
- fcx.inh.locals.get_copy(&local.node.id)));
+ fcx.inh.locals.get_copy(&local.id)));
visit::visit_local(local, (e, v));
};
visit::visit_pat(p, (e, v));
};
- let visit_block: @fn(&ast::blk, ((), visit::vt<()>)) = |b, (e, v)| {
+ let visit_block: @fn(&ast::Block, ((), visit::vt<()>)) = |b, (e, v)| {
// non-obvious: the `blk` variable maps to region lb, so
// we have to keep this up-to-date. This
// is... unfortunate. It'd be nice to not need this.
// Don't descend into fns and items
fn visit_fn(_fk: &visit::fn_kind, _decl: &ast::fn_decl,
- _body: &ast::blk, _sp: span,
+ _body: &ast::Block, _sp: span,
_id: ast::node_id, (_t,_v): ((), visit::vt<()>)) {
}
fn visit_item(_i: @ast::item, (_e,_v): ((), visit::vt<()>)) { }
// or if-check
fn check_then_else(fcx: @mut FnCtxt,
cond_expr: @ast::expr,
- then_blk: &ast::blk,
+ then_blk: &ast::Block,
opt_else_expr: Option<@ast::expr>,
id: ast::node_id,
sp: span,
expr: @ast::expr,
ast_sigil_opt: Option<ast::Sigil>,
decl: &ast::fn_decl,
- body: &ast::blk,
+ body: &ast::Block,
fn_kind: FnKind,
expected: Option<ty::t>) {
let tcx = fcx.ccx.tcx;
node_id: ast::node_id,
substitutions: ty::substs,
field_types: &[ty::field_ty],
- ast_fields: &[ast::field],
+ ast_fields: &[ast::Field],
check_completeness: bool) {
let tcx = fcx.ccx.tcx;
for ast_fields.iter().advance |field| {
let mut expected_field_type = ty::mk_err();
- let pair = class_field_map.find(&field.node.ident).
+ let pair = class_field_map.find(&field.ident).
map_consume(|x| *x);
match pair {
None => {
tcx.sess.span_err(
field.span,
fmt!("structure has no field named `%s`",
- tcx.sess.str_of(field.node.ident)));
+ tcx.sess.str_of(field.ident)));
error_happened = true;
}
Some((_, true)) => {
tcx.sess.span_err(
field.span,
fmt!("field `%s` specified more than once",
- tcx.sess.str_of(field.node.ident)));
+ tcx.sess.str_of(field.ident)));
error_happened = true;
}
Some((field_id, false)) => {
ty::lookup_field_type(
tcx, class_id, field_id, &substitutions);
class_field_map.insert(
- field.node.ident, (field_id, true));
+ field.ident, (field_id, true));
fields_found += 1;
}
}
// an error, so we can continue typechecking
check_expr_coercable_to_type(
fcx,
- field.node.expr,
+ field.expr,
expected_field_type);
}
id: ast::node_id,
span: codemap::span,
class_id: ast::def_id,
- fields: &[ast::field],
+ fields: &[ast::Field],
base_expr: Option<@ast::expr>) {
let tcx = fcx.ccx.tcx;
span: codemap::span,
enum_id: ast::def_id,
variant_id: ast::def_id,
- fields: &[ast::field]) {
+ fields: &[ast::Field]) {
let tcx = fcx.ccx.tcx;
// Look up the number of type parameters and the raw type, and
check_expr_coercable_to_type(fcx, init, local_ty)
}
-pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) {
+pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::Local) {
let tcx = fcx.ccx.tcx;
- let t = fcx.local_ty(local.span, local.node.id);
- fcx.write_ty(local.node.id, t);
+ let t = fcx.local_ty(local.span, local.id);
+ fcx.write_ty(local.id, t);
- match local.node.init {
+ match local.init {
Some(init) => {
- check_decl_initializer(fcx, local.node.id, init);
+ check_decl_initializer(fcx, local.id, init);
let init_ty = fcx.expr_ty(init);
if ty::type_is_error(init_ty) || ty::type_is_bot(init_ty) {
- fcx.write_ty(local.node.id, init_ty);
+ fcx.write_ty(local.id, init_ty);
}
}
_ => {}
let pcx = pat_ctxt {
fcx: fcx,
- map: pat_id_map(tcx.def_map, local.node.pat),
+ map: pat_id_map(tcx.def_map, local.pat),
};
- _match::check_pat(&pcx, local.node.pat, t);
- let pat_ty = fcx.node_ty(local.node.pat.id);
+ _match::check_pat(&pcx, local.pat, t);
+ let pat_ty = fcx.node_ty(local.pat.id);
if ty::type_is_error(pat_ty) || ty::type_is_bot(pat_ty) {
- fcx.write_ty(local.node.id, pat_ty);
+ fcx.write_ty(local.id, pat_ty);
}
}
match decl.node {
ast::decl_local(ref l) => {
check_decl_local(fcx, *l);
- let l_t = fcx.node_ty(l.node.id);
+ let l_t = fcx.node_ty(l.id);
saw_bot = saw_bot || ty::type_is_bot(l_t);
saw_err = saw_err || ty::type_is_error(l_t);
}
}
}
-pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::blk) {
+pub fn check_block_no_value(fcx: @mut FnCtxt, blk: &ast::Block) {
check_block_with_expected(fcx, blk, Some(ty::mk_nil()));
let blkty = fcx.node_ty(blk.id);
if ty::type_is_error(blkty) {
}
}
-pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::blk) {
+pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::Block) {
check_block_with_expected(fcx0, blk, None)
}
pub fn check_block_with_expected(fcx: @mut FnCtxt,
- blk: &ast::blk,
+ blk: &ast::Block,
expected: Option<ty::t>) {
let purity_state = fcx.ps.recurse(blk);
let prev = replace(&mut fcx.ps, purity_state);
}
// Returns true if b contains a break that can exit from b
-pub fn may_break(cx: ty::ctxt, id: ast::node_id, b: &ast::blk) -> bool {
+pub fn may_break(cx: ty::ctxt, id: ast::node_id, b: &ast::Block) -> bool {
// First: is there an unlabeled break immediately
// inside the loop?
(loop_query(b, |e| {
fcx.infcx().resolve_regions();
}
-pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) {
+pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::Block) {
let rcx = @mut Rcx { fcx: fcx, errors_reported: 0,
repeating_scope: blk.id };
if fcx.err_count_since_creation() == 0 {
// Ignore items
}
-fn visit_block(b: &ast::blk, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_block(b: &ast::Block, (rcx, v): (@mut Rcx, rvt)) {
rcx.fcx.tcx().region_maps.record_cleanup_scope(b.id);
visit::visit_block(b, (rcx, v));
}
visit::visit_arm(arm, (rcx, v));
}
-fn visit_local(l: @ast::local, (rcx, v): (@mut Rcx, rvt)) {
+fn visit_local(l: @ast::Local, (rcx, v): (@mut Rcx, rvt)) {
// see above
- constrain_bindings_in_pat(l.node.pat, rcx);
+ constrain_bindings_in_pat(l.pat, rcx);
visit::visit_local(l, (rcx, v));
}
// Detect points where a trait-bounded type parameter is
// instantiated, resolve the impls for the parameters.
-pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) {
+pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::Block) {
visit::visit_block(bl, (fcx, visit::mk_vt(@visit::Visitor {
visit_expr: resolve_expr,
visit_item: |_,_| {},
visit::visit_expr(e, (wbcx, v));
}
-fn visit_block(b: &ast::blk, (wbcx, v): (@mut WbCtxt, wb_vt)) {
+fn visit_block(b: &ast::Block, (wbcx, v): (@mut WbCtxt, wb_vt)) {
if !wbcx.success {
return;
}
visit::visit_pat(p, (wbcx, v));
}
-fn visit_local(l: @ast::local, (wbcx, v): (@mut WbCtxt, wb_vt)) {
+fn visit_local(l: @ast::Local, (wbcx, v): (@mut WbCtxt, wb_vt)) {
if !wbcx.success { return; }
- let var_ty = wbcx.fcx.local_ty(l.span, l.node.id);
+ let var_ty = wbcx.fcx.local_ty(l.span, l.id);
match resolve_type(wbcx.fcx.infcx(), var_ty, resolve_all | force_all) {
Ok(lty) => {
debug!("Type for local %s (id %d) resolved to %s",
- pat_to_str(l.node.pat, wbcx.fcx.tcx().sess.intr()),
- l.node.id,
+ pat_to_str(l.pat, wbcx.fcx.tcx().sess.intr()),
+ l.id,
wbcx.fcx.infcx().ty_to_str(lty));
- write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.node.id, lty);
+ write_ty_to_tcx(wbcx.fcx.ccx.tcx, l.id, lty);
}
Err(e) => {
wbcx.fcx.ccx.tcx.sess.span_err(
pub fn resolve_type_vars_in_fn(fcx: @mut FnCtxt,
decl: &ast::fn_decl,
- blk: &ast::blk,
+ blk: &ast::Block,
self_info: Option<SelfInfo>) -> bool {
let wbcx = @mut WbCtxt { fcx: fcx, success: true };
let visit = mk_visitor();
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
use middle::typeck::infer;
-use syntax::ast::{crate, def_id, def_struct, def_ty};
+use syntax::ast::{Crate, def_id, def_struct, def_ty};
use syntax::ast::{item, item_enum, item_impl, item_mod, item_struct};
use syntax::ast::{local_crate, trait_ref, ty_path};
use syntax::ast;
}
impl CoherenceChecker {
- pub fn check_coherence(self, crate: &crate) {
+ pub fn check_coherence(self, crate: &Crate) {
// Check implementations and traits. This populates the tables
// containing the inherent methods and extension methods. It also
// builds up the trait inheritance table.
}
// Privileged scope checking
- pub fn check_privileged_scopes(self, crate: &crate) {
+ pub fn check_privileged_scopes(self, crate: &Crate) {
visit_crate(crate, ((), mk_vt(@Visitor {
visit_item: |item, (_context, visitor)| {
match item.node {
)
}
-pub fn check_coherence(crate_context: @mut CrateCtxt, crate: &crate) {
+pub fn check_coherence(crate_context: @mut CrateCtxt, crate: &Crate) {
let coherence_checker = CoherenceChecker(crate_context);
coherence_checker.check_coherence(crate);
}
use syntax::opt_vec;
use syntax::parse::token::special_idents;
-pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::crate) {
+pub fn collect_item_types(ccx: @mut CrateCtxt, crate: &ast::Crate) {
fn collect_intrinsic_type(ccx: &CrateCtxt,
lang_item: ast::def_id) {
let ty::ty_param_bounds_and_ty { ty: ty, _ } =
use syntax::{ast, attr, parse};
struct Env {
- crate: @ast::crate,
+ crate: @ast::Crate,
tcx: ty::ctxt,
infcx: infer::infer_ctxt,
err_messages: @DVec<~str>
pub fn check_crate(tcx: ty::ctxt,
trait_map: resolve::TraitMap,
- crate: &ast::crate)
+ crate: &ast::Crate)
-> (method_map, vtable_map) {
let time_passes = tcx.sess.time_passes();
let ccx = @mut CrateCtxt {
_indenter(())
}
-pub fn field_expr(f: ast::field) -> @ast::expr { return f.node.expr; }
+pub fn field_expr(f: ast::Field) -> @ast::expr { return f.expr; }
-pub fn field_exprs(fields: ~[ast::field]) -> ~[@ast::expr] {
- fields.map(|f| f.node.expr)
+pub fn field_exprs(fields: ~[ast::Field]) -> ~[@ast::expr] {
+ fields.map(|f| f.expr)
}
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn loop_query(b: &ast::blk, p: @fn(&ast::expr_) -> bool) -> bool {
+pub fn loop_query(b: &ast::Block, p: @fn(&ast::expr_) -> bool) -> bool {
let rs = @mut false;
let visit_expr: @fn(@ast::expr,
(@mut bool,
// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn block_query(b: &ast::blk, p: @fn(@ast::expr) -> bool) -> bool {
+pub fn block_query(b: &ast::Block, p: @fn(@ast::expr) -> bool) -> bool {
let rs = @mut false;
let visit_expr: @fn(@ast::expr,
(@mut bool,
return *rs;
}
-pub fn local_rhs_span(l: @ast::local, def: span) -> span {
- match l.node.init {
+pub fn local_rhs_span(l: @ast::Local, def: span) -> span {
+ match l.init {
Some(i) => return i.span,
_ => return def
}
use syntax;
pub struct Ctxt {
- ast: @ast::crate,
+ ast: @ast::Crate,
ast_map: ast_map::map
}
type SrvOwner<'self,T> = &'self fn(srv: Srv) -> T;
pub type CtxtHandler<T> = ~fn(ctxt: Ctxt) -> T;
-type Parser = ~fn(Session, s: @str) -> @ast::crate;
+type Parser = ~fn(Session, s: @str) -> @ast::Crate;
enum Msg {
HandleRequest(~fn(Ctxt)),
}
fn build_ctxt(sess: Session,
- ast: @ast::crate) -> Ctxt {
+ ast: @ast::Crate) -> Ctxt {
use rustc::front::config;
do from_str(source) |srv| {
do exec(srv) |ctxt| {
// one item: the __std_macros secret module
- assert_eq!(ctxt.ast.node.module.items.len(), 1);
+ assert_eq!(ctxt.ast.module.items.len(), 1);
}
}
}
let doc = fold::default_seq_fold_crate(fold, doc);
let attrs = do astsrv::exec(srv) |ctxt| {
- let attrs = ctxt.ast.node.attrs.clone();
+ let attrs = ctxt.ast.attrs.clone();
attr_parser::parse_crate(attrs)
};
let desc = if doc.id == ast::crate_node_id {
// This is the top-level mod, use the crate attributes
do astsrv::exec(srv) |ctxt| {
- attr_parser::parse_desc(ctxt.ast.node.attrs.clone())
+ attr_parser::parse_desc(ctxt.ast.attrs.clone())
}
} else {
parse_item_attrs(srv, doc.id, attr_parser::parse_desc)
}
pub fn extract(
- crate: @ast::crate,
+ crate: @ast::Crate,
default_name: ~str
) -> doc::Doc {
doc::Doc {
}
fn top_moddoc_from_crate(
- crate: @ast::crate,
+ crate: @ast::Crate,
default_name: ~str
) -> doc::ModDoc {
moddoc_from_mod(mk_itemdoc(ast::crate_node_id, default_name),
- crate.node.module.clone())
+ crate.module.clone())
}
fn mk_itemdoc(id: ast::node_id, name: ~str) -> doc::ItemDoc {
use syntax::ast;
use syntax::parse;
-pub fn from_file(file: &Path) -> @ast::crate {
+pub fn from_file(file: &Path) -> @ast::Crate {
parse::parse_crate_from_file(
file, ~[], parse::new_parse_sess(None))
}
-pub fn from_str(source: @str) -> @ast::crate {
+pub fn from_str(source: @str) -> @ast::Crate {
parse::parse_crate_from_source_str(
@"-", source, ~[], parse::new_parse_sess(None))
}
-pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::crate {
+pub fn from_file_sess(sess: session::Session, file: &Path) -> @ast::Crate {
parse::parse_crate_from_file(
file, cfg(sess, file_input((*file).clone())), sess.parse_sess)
}
-pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::crate {
+pub fn from_str_sess(sess: session::Session, source: @str) -> @ast::Crate {
parse::parse_crate_from_source_str(
@"-", source, cfg(sess, str_input(source)), sess.parse_sess)
}
-fn cfg(sess: session::Session, input: driver::input) -> ast::crate_cfg {
+fn cfg(sess: session::Session, input: driver::input) -> ast::CrateConfig {
driver::build_configuration(sess, @"rustdoc", &input)
}
///
/// Once the types are known, they are inserted into the local_vars map in
/// this Program (to be deserialized later on
- pub fn register_new_vars(&mut self, blk: &ast::blk, tcx: ty::ctxt) {
+ pub fn register_new_vars(&mut self, blk: &ast::Block, tcx: ty::ctxt) {
debug!("looking for new variables");
let newvars = @mut HashMap::new();
do each_user_local(blk) |local| {
- let mutable = local.node.is_mutbl;
+ let mutable = local.is_mutbl;
do each_binding(local) |path, id| {
let name = do with_pp(token::get_ident_interner()) |pp, _| {
pprust::print_path(pp, path, false);
}
// helper functions to perform ast iteration
- fn each_user_local(blk: &ast::blk, f: &fn(@ast::local)) {
+ fn each_user_local(blk: &ast::Block, f: &fn(@ast::Local)) {
do find_user_block(blk) |blk| {
for blk.stmts.iter().advance |stmt| {
match stmt.node {
}
}
- fn find_user_block(blk: &ast::blk, f: &fn(&ast::blk)) {
+ fn find_user_block(blk: &ast::Block, f: &fn(&ast::Block)) {
for blk.stmts.iter().advance |stmt| {
match stmt.node {
ast::stmt_semi(e, _) => {
// Local declarations must be specially dealt with,
// record all local declarations for use later on
ast::decl_local(l) => {
- let mutbl = l.node.is_mutbl;
+ let mutbl = l.is_mutbl;
do each_binding(l) |path, _| {
let s = do with_pp(intr) |pp, _| {
pprust::print_path(pp, path, false);
return (program, jit::consume_engine());
fn parse_input(sess: session::Session, binary: @str,
- input: &str) -> @ast::crate {
+ input: &str) -> @ast::Crate {
let code = fmt!("fn main() {\n %s \n}", input);
let input = driver::str_input(code.to_managed());
let cfg = driver::build_configuration(sess, binary, &input);
crate.expect("parsing should return a crate")
}
- fn find_main(crate: @ast::crate, sess: session::Session,
- f: &fn(&ast::blk)) {
- for crate.node.module.items.iter().advance |item| {
+ fn find_main(crate: @ast::Crate, sess: session::Session,
+ f: &fn(&ast::Block)) {
+ for crate.module.items.iter().advance |item| {
match item.node {
ast::item_fn(_, _, _, _, ref blk) => {
if item.ident == sess.ident_of("main") {
use syntax::print::pprust;
use syntax::parse::token;
-pub fn each_binding(l: @ast::local, f: @fn(&ast::Path, ast::node_id)) {
+pub fn each_binding(l: @ast::Local, f: @fn(&ast::Path, ast::node_id)) {
use syntax::visit;
let vt = visit::mk_simple_visitor(
.. *visit::default_simple_visitor()
}
);
- (vt.visit_pat)(l.node.pat, ((), vt));
+ (vt.visit_pat)(l.pat, ((), vt));
}
/// A utility function that hands off a pretty printer to a callback.
/// build script
sess: session::Session,
/// The config for compiling the custom build script
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
/// The crate for the custom build script
- crate: @ast::crate,
+ crate: @ast::Crate,
/// Directory in which to store build output
build_dir: Path
}
}
match maybe_p {
Some(p) => {
- let w = io::file_writer(*p, &[io::Append]);
+ let w = io::file_writer(p, &[io::Append]);
match w {
- Err(s) => { let _ = cond.raise(((**p).clone(), fmt!("Bad path: %s", s))); }
+ Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
Ok(w) => w.write_line("")
}
}
// Tests above should (maybe) be converted to shell out to rustpkg, too
-#[test] #[ignore(cfg(target_arch = "x86"))]
+// FIXME: #7956: temporarily disabled
+#[ignore(cfg(target_arch = "x86"))]
fn test_install_git() {
let sysroot = test_sysroot();
debug!("sysroot = %s", sysroot.to_str());
}
-#[test] #[ignore(cfg(target_arch = "x86"))]
+// FIXME: #7956: temporarily disabled
+#[ignore(cfg(target_arch = "x86"))]
fn test_package_version() {
let local_path = "mockgithub.com/catamorphism/test_pkg_version";
let repo = init_git_repo(&Path(local_path));
&temp_dir);
}
-#[test]
+// FIXME: #7956: temporarily disabled
fn rustpkg_library_target() {
let foo_repo = init_git_repo(&Path("foo"));
let package_dir = foo_repo.push("foo");
#[test]
fn rust_path_contents() {
+ use std::unstable::change_dir_locked;
+
let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed");
let abc = &dir.push("A").push("B").push("C");
assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX));
assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX));
assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX));
- assert!(do os::change_dir_locked(&dir.push("A").push("B").push("C")) {
+ assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) {
let p = rust_path();
let cwd = os::getcwd().push(".rust");
let parent = cwd.pop().pop().push(".rust");
struct ReadyCtx {
sess: session::Session,
- crate: @ast::crate,
+ crate: @ast::Crate,
ext_cx: @ExtCtxt,
path: ~[ast::ident],
fns: ~[ListenerFn]
/// Generate/filter main function, add the list of commands, etc.
pub fn ready_crate(sess: session::Session,
- crate: @ast::crate) -> @ast::crate {
+ crate: @ast::Crate) -> @ast::Crate {
let ctx = @mut ReadyCtx {
sess: sess,
crate: crate,
});
// Inject the link attributes so we get the right package name and version
- if attr::find_linkage_metas(crate.node.attrs).is_empty() {
+ if attr::find_linkage_metas(crate.attrs).is_empty() {
let short_name_to_use = match what {
Test => fmt!("%stest", pkg_id.short_name),
Bench => fmt!("%sbench", pkg_id.short_name),
~[attr::mk_name_value_item_str(@"name", short_name_to_use.to_managed()),
attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())];
- crate = @codemap::respan(crate.span, ast::crate_ {
+ crate = @ast::Crate {
attrs: ~[attr::mk_attr(attr::mk_list_item(@"link", link_options))],
- .. crate.node.clone()});
+ .. (*crate).clone()
+ };
}
debug!("calling compile_crate_from_input, out_dir = %s,
pub fn compile_crate_from_input(input: &driver::input,
build_dir: &Path,
sess: session::Session,
- crate: @ast::crate,
- cfg: ast::crate_cfg,
+ crate: @ast::Crate,
+ cfg: ast::CrateConfig,
compile_from: driver::compile_phase) {
debug!("Calling build_output_filenames with %s, building library? %?",
build_dir.to_str(), sess.building_library);
// bad copy
let outputs = driver::build_output_filenames(input, &Some((*build_dir).clone()), &None,
- crate.node.attrs, sess);
+ crate.attrs, sess);
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
debug!("additional libraries:");
pub fn find_and_install_dependencies(ctxt: &Ctx,
sess: session::Session,
workspace: &Path,
- c: &ast::crate,
+ c: &ast::Crate,
save: @fn(Path)
) {
// :-(
Similar to a mutable option type, but friendlier.
*/
-#[mutable] // XXX remove after snap
#[no_freeze]
#[deriving(Clone, DeepClone, Eq)]
#[allow(missing_doc)]
false
}
-#[inline]
-#[cfg(not(stage0))]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- // This function should be inlined when stage0 is gone
- ((*tydesc).drop_glue)(data);
-}
-
-#[inline]
-#[cfg(stage0)]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- ((*tydesc).drop_glue)(0 as **TyDesc, data);
-}
-
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
pub unsafe fn annihilate() {
use rt::local_heap::local_free;
if !uniq {
let tydesc: *TyDesc = transmute((*box).header.type_desc);
let data = transmute(&(*box).data);
- call_drop_glue(tydesc, data);
+ ((*tydesc).drop_glue)(data);
}
}
prev: Option<@Handler<T, U>>,
}
-#[cfg(stage0)]
-pub struct Condition<'self, T, U> {
- name: &'static str,
- key: local_data::Key<'self, @Handler<T, U>>
-}
-#[cfg(not(stage0))]
pub struct Condition<T, U> {
name: &'static str,
key: local_data::Key<@Handler<T, U>>
}
-#[cfg(not(stage0))]
impl<T, U> Condition<T, U> {
pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
unsafe {
}
}
}
-#[cfg(stage0)]
-impl<'self, T, U> Condition<'self, T, U> {
- pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
- unsafe {
- let p : *RustClosure = ::cast::transmute(&h);
- let prev = local_data::get(::cast::unsafe_copy(&self.key),
- |k| k.map(|&x| *x));
- let h = @Handler { handle: *p, prev: prev };
- Trap { cond: self, handler: h }
- }
- }
-
- pub fn raise(&self, t: T) -> U {
- let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
- self.raise_default(t, || fail!(msg.clone()))
- }
-
- pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
- unsafe {
- match local_data::pop(::cast::unsafe_copy(&self.key)) {
- None => {
- debug!("Condition.raise: found no handler");
- default()
- }
- Some(handler) => {
- debug!("Condition.raise: found handler");
- match handler.prev {
- None => {}
- Some(hp) => {
- local_data::set(::cast::unsafe_copy(&self.key),
- hp)
- }
- }
- let handle : &fn(T) -> U =
- ::cast::transmute(handler.handle);
- let u = handle(t);
- local_data::set(::cast::unsafe_copy(&self.key), handler);
- u
- }
- }
- }
- }
-}
-#[cfg(stage0)]
-struct Trap<'self, T, U> {
- cond: &'self Condition<'self, T, U>,
- handler: @Handler<T, U>
-}
-#[cfg(not(stage0))]
struct Trap<'self, T, U> {
cond: &'self Condition<T, U>,
handler: @Handler<T, U>
}
}
-#[cfg(stage0)]
-struct Guard<'self, T, U> {
- cond: &'self Condition<'self, T, U>
-}
-#[cfg(not(stage0))]
struct Guard<'self, T, U> {
cond: &'self Condition<T, U>
}
#[cfg(nogc)]
fn expect_sentinel() -> bool { false }
-#[inline]
-#[cfg(not(stage0))]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- // This function should be inlined when stage0 is gone
- ((*tydesc).drop_glue)(data);
-}
-
-#[inline]
-#[cfg(stage0)]
-unsafe fn call_drop_glue(tydesc: *TyDesc, data: *i8) {
- ((*tydesc).drop_glue)(0 as **TyDesc, data);
-}
-
// Entry point for GC-based cleanup. Walks stack looking for exchange
// heap and stack allocations requiring drop, and runs all
// destructors.
// FIXME #4420: Destroy this box
// FIXME #4330: Destroy this box
} else {
- call_drop_glue(tydesc, *root as *i8);
+ ((*tydesc).drop_glue)(*root as *i8);
}
}
}
#[allow(missing_doc)];
-#[cfg(stage0)]
-#[lang="copy"]
-pub trait Copy {
- // Empty.
-}
-
-#[cfg(stage0)]
-#[lang="owned"]
-pub trait Send {
- // empty.
-}
-
-#[cfg(not(stage0))]
#[lang="send"]
pub trait Send {
// empty.
}
-#[cfg(stage0)]
-#[lang="const"]
-pub trait Freeze {
- // empty.
-}
-
-#[cfg(not(stage0))]
#[lang="freeze"]
pub trait Freeze {
// empty.
* sections to ensure that each value of the `Key` type points to a unique
* location.
*/
-#[cfg(not(stage0))]
pub type Key<T> = &'static KeyValue<T>;
-#[cfg(stage0)]
-pub type Key<'self,T> = &'self fn(v: T);
pub enum KeyValue<T> { Key }
* Remove a task-local data value from the table, returning the
* reference that was originally created to insert it.
*/
-#[cfg(stage0)]
-pub fn pop<T: 'static>(key: Key<@T>) -> Option<@T> {
- unsafe { local_pop(Handle::new(), key) }
-}
-/**
- * Remove a task-local data value from the table, returning the
- * reference that was originally created to insert it.
- */
-#[cfg(not(stage0))]
pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
unsafe { local_pop(Handle::new(), key) }
}
+
/**
* Retrieve a task-local data value. It will also be kept alive in the
* table until explicitly removed.
*/
-#[cfg(stage0)]
-pub fn get<T: 'static, U>(key: Key<@T>, f: &fn(Option<&@T>) -> U) -> U {
- unsafe { local_get(Handle::new(), key, f) }
-}
-/**
- * Retrieve a task-local data value. It will also be kept alive in the
- * table until explicitly removed.
- */
-#[cfg(not(stage0))]
pub fn get<T: 'static, U>(key: Key<T>, f: &fn(Option<&T>) -> U) -> U {
unsafe { local_get(Handle::new(), key, f) }
}
+
/**
* Retrieve a mutable borrowed pointer to a task-local data value.
*/
-#[cfg(not(stage0))]
pub fn get_mut<T: 'static, U>(key: Key<T>, f: &fn(Option<&mut T>) -> U) -> U {
unsafe { local_get_mut(Handle::new(), key, f) }
}
+
/**
* Store a value in task-local data. If this key already has a value,
* that value is overwritten (and its destructor is run).
*/
-#[cfg(stage0)]
-pub fn set<T: 'static>(key: Key<@T>, data: @T) {
- unsafe { local_set(Handle::new(), key, data) }
-}
-/**
- * Store a value in task-local data. If this key already has a value,
- * that value is overwritten (and its destructor is run).
- */
-#[cfg(not(stage0))]
pub fn set<T: 'static>(key: Key<T>, data: T) {
unsafe { local_set(Handle::new(), key, data) }
}
+
/**
* Modify a task-local data value. If the function returns 'None', the
* data is removed (and its reference dropped).
*/
-#[cfg(stage0)]
-pub fn modify<T: 'static>(key: Key<@T>, f: &fn(Option<@T>) -> Option<@T>) {
- match f(pop(key)) {
- Some(next) => { set(key, next); }
- None => {}
- }
-}
-/**
- * Modify a task-local data value. If the function returns 'None', the
- * data is removed (and its reference dropped).
- */
-#[cfg(not(stage0))]
pub fn modify<T: 'static>(key: Key<T>, f: &fn(Option<T>) -> Option<T>) {
unsafe {
match f(pop(::cast::unsafe_copy(&key))) {
*
* This version prepends each entry with the directory.
*/
-pub fn list_dir_path(p: &Path) -> ~[~Path] {
- list_dir(p).map(|f| ~p.push(*f))
+pub fn list_dir_path(p: &Path) -> ~[Path] {
+ list_dir(p).map(|f| p.push(*f))
}
/// Removes a directory at the specified path, after removing
}
}
-/// Changes the current working directory to the specified
-/// path while acquiring a global lock, then calls `action`.
-/// If the change is successful, releases the lock and restores the
-/// CWD to what it was before, returning true.
-/// Returns false if the directory doesn't exist or if the directory change
-/// is otherwise unsuccessful.
-pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
- use unstable::global::global_data_clone_create;
- use unstable::sync::{Exclusive, exclusive};
-
- fn key(_: Exclusive<()>) { }
-
- unsafe {
- let result = global_data_clone_create(key, || { ~exclusive(()) });
-
- do result.with_imm() |_| {
- let old_dir = os::getcwd();
- if change_dir(p) {
- action();
- change_dir(&old_dir)
- }
- else {
- false
- }
- }
- }
-}
-
/// Copies a file from one location to another
pub fn copy_file(from: &Path, to: &Path) -> bool {
return do_copy_file(from, to);
val: ~[~str]
}
-#[cfg(stage0)]
-fn overridden_arg_key(_v: @OverriddenArgs) {}
-#[cfg(not(stage0))]
static overridden_arg_key: local_data::Key<@OverriddenArgs> = &local_data::Key;
/// Returns the arguments which this program was started with (normally passed
}
// used to make space in TLS for a random number generator
-#[cfg(stage0)]
-fn tls_rng_state(_v: @@mut IsaacRng) {}
-#[cfg(not(stage0))]
static tls_rng_state: local_data::Key<@@mut IsaacRng> = &local_data::Key;
/**
#[allow(missing_doc)];
-#[cfg(stage0)]
-use intrinsic::{Opaque, TyDesc, TyVisitor};
-#[cfg(not(stage0))]
use unstable::intrinsics::{Opaque, TyDesc, TyVisitor};
use libc::c_void;
use sys;
true
}
- #[cfg(stage0)]
- fn visit_str(&self) -> bool {
- self.align_to::<~str>();
- if ! self.inner.visit_str() { return false; }
- self.bump_past::<~str>();
- true
- }
-
fn visit_estr_box(&self) -> bool {
self.align_to::<@str>();
if ! self.inner.visit_estr_box() { return false; }
true
}
- #[cfg(not(stage0))]
fn visit_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
self.align_to::<~u8>();
if ! self.inner.visit_uniq_managed(mtbl, inner) { return false; }
true
}
- #[cfg(not(stage0))]
fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
self.align_to::<~[@u8]>();
if ! self.inner.visit_evec_uniq_managed(mtbl, inner) { return false; }
use vec::raw::{VecRepr, SliceRepr};
use vec;
use vec::{OwnedVector, UnboxedVecRepr};
-#[cfg(stage0)]
-use intrinsic::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
-#[cfg(not(stage0))]
use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
#[cfg(test)] use io;
}
}
- // Type no longer exists, vestigial function.
- #[cfg(stage0)]
- fn visit_str(&self) -> bool { fail!(); }
-
fn visit_estr_box(&self) -> bool {
do self.get::<@str> |s| {
self.writer.write_char('@');
}
}
- #[cfg(not(stage0))]
fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write_char('~');
do self.get::<&managed::raw::BoxRepr> |b| {
}
}
- #[cfg(stage0)]
- fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
- do self.get::<&VecRepr> |b| {
- self.writer.write_char('~');
- self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner);
- }
- }
-
- #[cfg(not(stage0))]
fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
do self.get::<&UnboxedVecRepr> |b| {
self.writer.write_char('~');
}
}
- #[cfg(not(stage0))]
fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool {
do self.get::<&VecRepr> |b| {
self.writer.write_char('~');
fn visit_self(&self) -> bool { true }
fn visit_type(&self) -> bool { true }
- #[cfg(not(stage0))]
fn visit_opaque_box(&self) -> bool {
self.writer.write_char('@');
do self.get::<&managed::raw::BoxRepr> |b| {
self.visit_ptr_inner(p, b.header.type_desc);
}
}
- #[cfg(stage0)]
- fn visit_opaque_box(&self) -> bool {
- self.writer.write_char('@');
- do self.get::<&managed::raw::BoxRepr> |b| {
- let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
- unsafe {
- self.visit_ptr_inner(p, transmute(b.header.type_desc));
- }
- }
- }
// Type no longer exists, vestigial function.
fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); }
p
}
-// FIXME #4942: Make these signatures agree with exchange_alloc's signatures
-#[cfg(stage0, not(test))]
-#[lang="exchange_malloc"]
-#[inline]
-pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
- let td = td as *TyDesc;
- let size = size as uint;
-
- assert!(td.is_not_null());
-
- let total_size = get_box_size(size, (*td).align);
- let p = malloc_raw(total_size as uint);
-
- let box: *mut BoxRepr = p as *mut BoxRepr;
- (*box).header.ref_count = -1;
- (*box).header.type_desc = td;
-
- box as *c_char
-}
-
/// The allocator for unique pointers without contained managed pointers.
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
#[lang="exchange_malloc"]
#[inline]
pub unsafe fn exchange_malloc(size: uintptr_t) -> *c_char {
pub use self::stdio::println;
pub use self::file::FileStream;
+pub use self::timer::Timer;
pub use self::net::ip::IpAddr;
pub use self::net::tcp::TcpListener;
pub use self::net::tcp::TcpStream;
/// Non-I/O things needed by the I/O module
mod support;
+/// Basic Timer
+pub mod timer;
+
/// Thread-blocking implementations
pub mod native {
/// Posix file I/O
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use option::{Option, Some, None};
+use result::{Ok, Err};
+use rt::io::{io_error};
+use rt::rtio::{IoFactory, IoFactoryObject,
+ RtioTimer, RtioTimerObject};
+use rt::local::Local;
+
+pub struct Timer(~RtioTimerObject);
+
+impl Timer {
+ fn new_on_rt(i: ~RtioTimerObject) -> Timer {
+ Timer(i)
+ }
+
+ pub fn new() -> Option<Timer> {
+ let timer = unsafe {
+ rtdebug!("Timer::init: borrowing io to init timer");
+ let io = Local::unsafe_borrow::<IoFactoryObject>();
+ rtdebug!("about to init timer");
+ (*io).timer_init()
+ };
+ match timer {
+ Ok(t) => Some(Timer::new_on_rt(t)),
+ Err(ioerr) => {
+ rtdebug!("Timer::init: failed to init: %?", ioerr);
+ io_error::cond.raise(ioerr);
+ None
+ }
+ }
+ }
+}
+
+impl RtioTimer for Timer {
+ fn sleep(&self, msecs: u64) {
+ (**self).sleep(msecs);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use rt::test::*;
+ use option::{Some, None};
+ #[test]
+ fn test_io_timer_sleep_simple() {
+ do run_in_newsched_task {
+ let timer = Timer::new();
+ match timer {
+ Some(t) => t.sleep(1),
+ None => assert!(false)
+ }
+ }
+ }
+}
\ No newline at end of file
pub type RtioTcpStreamObject = uvio::UvTcpStream;
pub type RtioTcpListenerObject = uvio::UvTcpListener;
pub type RtioUdpSocketObject = uvio::UvUdpSocket;
+pub type RtioTimerObject = uvio::UvTimer;
pub trait EventLoop {
fn run(&mut self);
fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError>;
fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError>;
fn udp_bind(&mut self, addr: IpAddr) -> Result<~RtioUdpSocketObject, IoError>;
+ fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>;
}
pub trait RtioTcpListener : RtioSocket {
fn hear_broadcasts(&mut self);
fn ignore_broadcasts(&mut self);
}
+
+pub trait RtioTimer {
+ fn sleep(&self, msecs: u64);
+}
}
}
}
+
+ fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError> {
+ Ok(~UvTimer(TimerWatcher::new(self.uv_loop())))
+ }
}
// FIXME #6090: Prefer newtype structs but Drop doesn't work
fn ignore_broadcasts(&mut self) { fail!(); }
}
+pub struct UvTimer(timer::TimerWatcher);
+
+impl UvTimer {
+ fn new(w: timer::TimerWatcher) -> UvTimer {
+ UvTimer(w)
+ }
+}
+
+impl Drop for UvTimer {
+ fn drop(&self) {
+ rtdebug!("closing UvTimer");
+ let scheduler = Local::take::<Scheduler>();
+ do scheduler.deschedule_running_task_and_then |_, task| {
+ let task_cell = Cell::new(task);
+ do self.close {
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ }
+}
+
+impl RtioTimer for UvTimer {
+ fn sleep(&self, msecs: u64) {
+ let scheduler = Local::take::<Scheduler>();
+ assert!(scheduler.in_task_context());
+ do scheduler.deschedule_running_task_and_then |sched, task| {
+ rtdebug!("sleep: entered scheduler context");
+ assert!(!sched.in_task_context());
+ let task_cell = Cell::new(task);
+ let mut watcher = **self;
+ do watcher.start(msecs, 0) |_, status| {
+ assert!(status.is_none());
+ let scheduler = Local::take::<Scheduler>();
+ scheduler.resume_blocked_task_immediately(task_cell.take());
+ }
+ }
+ let mut w = **self;
+ w.stop();
+ }
+}
+
#[test]
fn test_simple_io_no_connect() {
do run_in_newsched_task {
}
}
}
+
+fn test_timer_sleep_simple_impl() {
+ unsafe {
+ let io = Local::unsafe_borrow::<IoFactoryObject>();
+ let timer = (*io).timer_init();
+ match timer {
+ Ok(t) => t.sleep(1),
+ Err(_) => assert!(false)
+ }
+ }
+}
+#[test]
+fn test_timer_sleep_simple() {
+ do run_in_newsched_task {
+ test_timer_sleep_simple_impl();
+ }
+}
/// Sets the length of the string and adds the null terminator
#[inline]
- #[cfg(stage0)]
- pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
- let v: **mut vec::raw::VecRepr = cast::transmute(v);
- let repr: *mut vec::raw::VecRepr = *v;
- (*repr).unboxed.fill = new_len + 1u;
- let null = ptr::mut_offset(cast::transmute(&((*repr).unboxed.data)),
- new_len);
- *null = 0u8;
- }
-
- /// Sets the length of the string and adds the null terminator
- #[inline]
- #[cfg(not(stage0))]
pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
let v: **mut vec::UnboxedVecRepr = cast::transmute(v);
let repr: *mut vec::UnboxedVecRepr = *v;
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[allow(missing_doc)];
-
-use cast;
-use cmp::Eq;
-use libc;
-use local_data;
-use prelude::*;
-use sys;
-use task::rt;
-
-use super::rt::rust_task;
-use rt::task::{Task, LocalStorage};
-
-pub enum Handle {
- OldHandle(*rust_task),
- NewHandle(*mut LocalStorage)
-}
-
-impl Handle {
- pub fn new() -> Handle {
- use rt::{context, OldTaskContext};
- use rt::local::Local;
- unsafe {
- match context() {
- OldTaskContext => {
- OldHandle(rt::rust_get_task())
- }
- _ => {
- let task = Local::unsafe_borrow::<Task>();
- NewHandle(&mut (*task).storage)
- }
- }
- }
- }
-}
-
-pub trait LocalData { }
-impl<T: 'static> LocalData for @T { }
-
-impl Eq for @LocalData {
- fn eq(&self, other: &@LocalData) -> bool {
- unsafe {
- let ptr_a: &(uint, uint) = cast::transmute(self);
- let ptr_b: &(uint, uint) = cast::transmute(other);
- return ptr_a == ptr_b;
- }
- }
- fn ne(&self, other: &@LocalData) -> bool { !(*self).eq(other) }
-}
-
-// If TLS is used heavily in future, this could be made more efficient with a
-// proper map.
-type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData);
-// Has to be a pointer at outermost layer; the foreign call returns void *.
-type TaskLocalMap = ~[Option<TaskLocalElement>];
-
-fn cleanup_task_local_map(map_ptr: *libc::c_void) {
- unsafe {
- assert!(!map_ptr.is_null());
- // Get and keep the single reference that was created at the
- // beginning.
- let _map: TaskLocalMap = cast::transmute(map_ptr);
- // All local_data will be destroyed along with the map.
- }
-}
-
-// Gets the map from the runtime. Lazily initialises if not done so already.
-unsafe fn get_local_map(handle: Handle) -> &mut TaskLocalMap {
- match handle {
- OldHandle(task) => get_task_local_map(task),
- NewHandle(local_storage) => get_newsched_local_map(local_storage)
- }
-}
-
-unsafe fn get_task_local_map(task: *rust_task) -> &mut TaskLocalMap {
-
- extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) {
- cleanup_task_local_map(map_ptr);
- }
-
- // Relies on the runtime initialising the pointer to null.
- // Note: the map is an owned pointer and is "owned" by TLS. It is moved
- // into the tls slot for this task, and then mutable loans are taken from
- // this slot to modify the map.
- let map_ptr = rt::rust_get_task_local_data(task);
- if (*map_ptr).is_null() {
- // First time TLS is used, create a new map and set up the necessary
- // TLS information for its safe destruction
- let map: TaskLocalMap = ~[];
- *map_ptr = cast::transmute(map);
- rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb);
- }
- return cast::transmute(map_ptr);
-}
-
-unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> &mut TaskLocalMap {
- // This is based on the same idea as the oldsched code above.
- match &mut *local {
- // If the at_exit function is already set, then we just need to take a
- // loan out on the TLS map stored inside
- &LocalStorage(ref mut map_ptr, Some(_)) => {
- assert!(map_ptr.is_not_null());
- return cast::transmute(map_ptr);
- }
- // If this is the first time we've accessed TLS, perform similar
- // actions to the oldsched way of doing things.
- &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
- assert!(map_ptr.is_null());
- assert!(at_exit.is_none());
- let map: TaskLocalMap = ~[];
- *map_ptr = cast::transmute(map);
- *at_exit = Some(cleanup_task_local_map);
- return cast::transmute(map_ptr);
- }
- }
-}
-
-unsafe fn key_to_key_value<T: 'static>(key: local_data::Key<@T>) -> *libc::c_void {
- let pair: sys::Closure = cast::transmute(key);
- return pair.code as *libc::c_void;
-}
-
-// If returning Some(..), returns with @T with the map's reference. Careful!
-unsafe fn local_data_lookup<T: 'static>(
- map: &mut TaskLocalMap, key: local_data::Key<@T>)
- -> Option<(uint, *libc::c_void)> {
-
- let key_value = key_to_key_value(key);
- for map.iter().enumerate().advance |(i, entry)| {
- match *entry {
- Some((k, data, _)) if k == key_value => { return Some((i, data)); }
- _ => {}
- }
- }
- return None;
-}
-
-unsafe fn local_get_helper<T: 'static>(
- handle: Handle, key: local_data::Key<@T>,
- do_pop: bool) -> Option<@T> {
-
- let map = get_local_map(handle);
- // Interpreturn our findings from the map
- do local_data_lookup(map, key).map |result| {
- // A reference count magically appears on 'data' out of thin air. It
- // was referenced in the local_data box, though, not here, so before
- // overwriting the local_data_box we need to give an extra reference.
- // We must also give an extra reference when not removing.
- let (index, data_ptr) = *result;
- let data: @T = cast::transmute(data_ptr);
- cast::bump_box_refcount(data);
- if do_pop {
- map[index] = None;
- }
- data
- }
-}
-
-
-pub unsafe fn local_pop<T: 'static>(
- handle: Handle,
- key: local_data::Key<@T>) -> Option<@T> {
-
- local_get_helper(handle, key, true)
-}
-
-pub unsafe fn local_get<T: 'static, U>(
- handle: Handle,
- key: local_data::Key<@T>,
- f: &fn(Option<&@T>) -> U) -> U {
-
- match local_get_helper(handle, key, false) {
- Some(ref x) => f(Some(x)),
- None => f(None)
- }
-}
-
-pub unsafe fn local_set<T: 'static>(
- handle: Handle, key: local_data::Key<@T>, data: @T) {
-
- let map = get_local_map(handle);
- // Store key+data as *voids. Data is invisibly referenced once; key isn't.
- let keyval = key_to_key_value(key);
- // We keep the data in two forms: one as an unsafe pointer, so we can get
- // it back by casting; another in an existential box, so the reference we
- // own on it can be dropped when the box is destroyed. The unsafe pointer
- // does not have a reference associated with it, so it may become invalid
- // when the box is destroyed.
- let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data);
- let data_box = @data as @LocalData;
- // Construct new entry to store in the map.
- let new_entry = Some((keyval, data_ptr, data_box));
- // Find a place to put it.
- match local_data_lookup(map, key) {
- Some((index, _old_data_ptr)) => {
- // Key already had a value set, _old_data_ptr, whose reference
- // will get dropped when the local_data box is overwritten.
- map[index] = new_entry;
- }
- None => {
- // Find an empty slot. If not, grow the vector.
- match map.iter().position(|x| x.is_none()) {
- Some(empty_index) => { map[empty_index] = new_entry; }
- None => { map.push(new_entry); }
- }
- }
- }
-}
-
-pub unsafe fn local_modify<T: 'static>(
- handle: Handle, key: local_data::Key<@T>,
- modify_fn: &fn(Option<@T>) -> Option<@T>) {
-
- // Could be more efficient by doing the lookup work, but this is easy.
- let newdata = modify_fn(local_pop(handle, key));
- if newdata.is_some() {
- local_set(handle, key, newdata.unwrap());
- }
-}
#[cfg(test)] use ptr;
#[cfg(test)] use task;
-#[cfg(stage0)]
-#[path="local_data_priv_stage0.rs"]
-mod local_data_priv;
-#[cfg(not(stage0))]
mod local_data_priv;
pub mod rt;
pub mod spawn;
// FIXME (#2912): Work around core-vs-coretest function duplication. Can't use
// a proper closure because the #[test]s won't understand. Have to fake it.
-#[cfg(not(stage0))]
fn taskgroup_key() -> local_data::Key<@@mut Taskgroup> {
unsafe { cast::transmute(-2) }
}
-#[cfg(stage0)]
-fn taskgroup_key() -> local_data::Key<@@mut Taskgroup> {
- unsafe { cast::transmute((-2, 0)) }
-}
// Transitionary.
struct RuntimeGlue;
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use cast;
-use libc::size_t;
-use rand::RngUtil;
-use rand;
-use sys;
-use task;
-use vec;
-
-#[cfg(test)] use uint;
-
-/**
-Register a function to be run during runtime shutdown.
-
-After all non-weak tasks have exited, registered exit functions will
-execute, in random order, on the primary scheduler. Each function runs
-in its own unsupervised task.
-*/
-pub fn at_exit(f: ~fn()) {
- unsafe {
- let runner: &fn(*ExitFunctions) = exit_runner;
- let runner_pair: sys::Closure = cast::transmute(runner);
- let runner_ptr = runner_pair.code;
- let runner_ptr = cast::transmute(runner_ptr);
- rustrt::rust_register_exit_function(runner_ptr, ~f);
- }
-}
-
-// NB: The double pointer indirection here is because ~fn() is a fat
-// pointer and due to FFI problems I am more comfortable making the
-// interface use a normal pointer
-mod rustrt {
- use libc::c_void;
-
- extern {
- pub fn rust_register_exit_function(runner: *c_void, f: ~~fn());
- }
-}
-
-struct ExitFunctions {
- // The number of exit functions
- count: size_t,
- // The buffer of exit functions
- start: *~~fn()
-}
-
-fn exit_runner(exit_fns: *ExitFunctions) {
- let exit_fns = unsafe { &*exit_fns };
- let count = (*exit_fns).count;
- let start = (*exit_fns).start;
-
- // NB: from_buf memcpys from the source, which will
- // give us ownership of the array of functions
- let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) };
- // Let's not make any promises about execution order
- let mut rng = rand::rng();
- rng.shuffle_mut(exit_fns_vec);
-
- debug!("running %u exit functions", exit_fns_vec.len());
-
- while !exit_fns_vec.is_empty() {
- match exit_fns_vec.pop() {
- ~f => {
- let mut task = task::task();
- task.supervised();
- task.spawn(f);
- }
- }
- }
-}
-
-#[test]
-fn test_at_exit() {
- let i = 10;
- do at_exit {
- debug!("at_exit1");
- assert_eq!(i, 10);
- }
-}
-
-#[test]
-fn test_at_exit_many() {
- let i = 10;
- for uint::range(20, 100) |j| {
- do at_exit {
- debug!("at_exit2");
- assert_eq!(i, 10);
- assert!(j > i);
- }
- }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Global data
-
-An interface for creating and retrieving values with global
-(per-runtime) scope.
-
-Global values are stored in a map and protected by a single global
-mutex. Operations are provided for accessing and cloning the value
-under the mutex.
-
-Because all globals go through a single mutex, they should be used
-sparingly. The interface is intended to be used with clonable,
-atomically reference counted synchronization types, like ARCs, in
-which case the value should be cached locally whenever possible to
-avoid hitting the mutex.
-*/
-
-use cast::{transmute};
-use clone::Clone;
-use kinds::Send;
-use libc::{c_void, intptr_t};
-use option::{Option, Some, None};
-use ops::Drop;
-use unstable::sync::{Exclusive, exclusive};
-use unstable::at_exit::at_exit;
-use unstable::intrinsics::atomic_cxchg;
-use hashmap::HashMap;
-use sys::Closure;
-
-#[cfg(test)] use unstable::sync::{UnsafeAtomicRcBox};
-#[cfg(test)] use task::spawn;
-#[cfg(test)] use uint;
-
-pub type GlobalDataKey<'self,T> = &'self fn(v: T);
-
-pub unsafe fn global_data_clone_create<T:Send + Clone>(
- key: GlobalDataKey<T>, create: &fn() -> ~T) -> T {
- /*!
- * Clone a global value or, if it has not been created,
- * first construct the value then return a clone.
- *
- * # Safety note
- *
- * Both the clone operation and the constructor are
- * called while the global lock is held. Recursive
- * use of the global interface in either of these
- * operations will result in deadlock.
- */
- global_data_clone_create_(key_ptr(key), create)
-}
-
-unsafe fn global_data_clone_create_<T:Send + Clone>(
- key: uint, create: &fn() -> ~T) -> T {
-
- let mut clone_value: Option<T> = None;
- do global_data_modify_(key) |value: Option<~T>| {
- match value {
- None => {
- let value = create();
- clone_value = Some((*value).clone());
- Some(value)
- }
- Some(value) => {
- clone_value = Some((*value).clone());
- Some(value)
- }
- }
- }
- return clone_value.unwrap();
-}
-
-unsafe fn global_data_modify<T:Send>(
- key: GlobalDataKey<T>, op: &fn(Option<~T>) -> Option<~T>) {
-
- global_data_modify_(key_ptr(key), op)
-}
-
-unsafe fn global_data_modify_<T:Send>(
- key: uint, op: &fn(Option<~T>) -> Option<~T>) {
-
- let mut old_dtor = None;
- do get_global_state().with |gs| {
- let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) {
- Some((ptr, dtor)) => {
- let value: ~T = transmute(ptr);
- (op(Some(value)), Some(dtor))
- }
- None => {
- (op(None), None)
- }
- };
- match maybe_new_value {
- Some(value) => {
- let data: *c_void = transmute(value);
- let dtor: ~fn() = match maybe_dtor {
- Some(dtor) => dtor,
- None => {
- let dtor: ~fn() = || {
- let _destroy_value: ~T = transmute(data);
- };
- dtor
- }
- };
- let value = (data, dtor);
- gs.map.insert(key, value);
- }
- None => {
- match maybe_dtor {
- Some(dtor) => old_dtor = Some(dtor),
- None => ()
- }
- }
- }
- }
-}
-
-pub unsafe fn global_data_clone<T:Send + Clone>(
- key: GlobalDataKey<T>) -> Option<T> {
- let mut maybe_clone: Option<T> = None;
- do global_data_modify(key) |current| {
- match ¤t {
- &Some(~ref value) => {
- maybe_clone = Some(value.clone());
- }
- &None => ()
- }
- current
- }
- return maybe_clone;
-}
-
-// GlobalState is a map from keys to unique pointers and a
-// destructor. Keys are pointers derived from the type of the
-// global value. There is a single GlobalState instance per runtime.
-struct GlobalState {
- map: HashMap<uint, (*c_void, ~fn())>
-}
-
-impl Drop for GlobalState {
- fn drop(&self) {
- for self.map.each_value |v| {
- match v {
- &(_, ref dtor) => (*dtor)()
- }
- }
- }
-}
-
-fn get_global_state() -> Exclusive<GlobalState> {
-
- static POISON: int = -1;
-
- // FIXME #4728: Doing atomic_cxchg to initialize the global state
- // lazily, which wouldn't be necessary with a runtime written
- // in Rust
- let global_ptr = unsafe { rust_get_global_data_ptr() };
-
- if unsafe { *global_ptr } == 0 {
- // Global state doesn't exist yet, probably
-
- // The global state object
- let state = GlobalState {
- map: HashMap::new()
- };
-
- // It's under a reference-counted mutex
- let state = ~exclusive(state);
-
- // Convert it to an integer
- let state_i: int = unsafe {
- let state_ptr: &Exclusive<GlobalState> = state;
- transmute(state_ptr)
- };
-
- // Swap our structure into the global pointer
- let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) };
-
- // Sanity check that we're not trying to reinitialize after shutdown
- assert!(prev_i != POISON);
-
- if prev_i == 0 {
- // Successfully installed the global pointer
-
- // Take a handle to return
- let clone = (*state).clone();
-
- // Install a runtime exit function to destroy the global object
- do at_exit {
- // Poison the global pointer
- let prev_i = unsafe {
- atomic_cxchg(&mut *global_ptr, state_i, POISON)
- };
- assert_eq!(prev_i, state_i);
-
- // Capture the global state object in the at_exit closure
- // so that it is destroyed at the right time
- let _capture_global_state = &state;
- };
- return clone;
- } else {
- // Somebody else initialized the globals first
- let state: &Exclusive<GlobalState> = unsafe { transmute(prev_i) };
- return state.clone();
- }
- } else {
- let state: &Exclusive<GlobalState> = unsafe {
- transmute(*global_ptr)
- };
- return state.clone();
- }
-}
-
-fn key_ptr<T:Send>(key: GlobalDataKey<T>) -> uint {
- unsafe {
- let closure: Closure = transmute(key);
- return transmute(closure.code);
- }
-}
-
-extern {
- fn rust_get_global_data_ptr() -> *mut intptr_t;
-}
-
-#[test]
-fn test_clone_rc() {
- fn key(_v: UnsafeAtomicRcBox<int>) { }
-
- for uint::range(0, 100) |_| {
- do spawn {
- unsafe {
- let val = do global_data_clone_create(key) {
- ~UnsafeAtomicRcBox::new(10)
- };
-
- assert!(val.get() == &10);
- }
- }
- }
-}
-
-#[test]
-fn test_modify() {
- fn key(_v: UnsafeAtomicRcBox<int>) { }
-
- unsafe {
- do global_data_modify(key) |v| {
- match v {
- None => { Some(~UnsafeAtomicRcBox::new(10)) }
- _ => fail!()
- }
- }
-
- do global_data_modify(key) |v| {
- match v {
- Some(sms) => {
- let v = sms.get();
- assert!(*v == 10);
- None
- },
- _ => fail!()
- }
- }
-
- do global_data_modify(key) |v| {
- match v {
- None => { Some(~UnsafeAtomicRcBox::new(10)) }
- _ => fail!()
- }
- }
- }
-}
#[cfg(test)]
pub use realstd::unstable::intrinsics::{TyDesc, Opaque, TyVisitor};
-#[cfg(not(stage0))]
pub type GlueFn = extern "Rust" fn(*i8);
-#[cfg(stage0)]
-pub type GlueFn = extern "Rust" fn(**TyDesc, *i8);
-
// NB: this has to be kept in sync with the Rust ABI.
#[lang="ty_desc"]
#[cfg(not(test))]
pub fn pref_align_of<T>() -> uint;
/// Get a static pointer to a type descriptor.
- #[cfg(not(stage0))]
pub fn get_tydesc<T>() -> *TyDesc;
- #[cfg(stage0)]
- pub fn get_tydesc<T>() -> *();
/// Create a value initialized to zero.
///
pub fn needs_drop<T>() -> bool;
/// Returns `true` if a type is managed (will be allocated on the local heap)
- #[cfg(not(stage0))]
pub fn contains_managed<T>() -> bool;
- #[cfg(not(stage0))]
pub fn visit_tydesc(td: *TyDesc, tv: @TyVisitor);
pub fn frame_address(f: &once fn(*u8));
use prelude::*;
use task;
-pub mod at_exit;
-
pub mod dynamic_lib;
-pub mod global;
pub mod finally;
-pub mod weak_task;
pub mod intrinsics;
pub mod simd;
pub mod extfmt;
fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread;
fn rust_raw_thread_join_delete(thread: *raw_thread);
}
+
+
+/// Changes the current working directory to the specified
+/// path while acquiring a global lock, then calls `action`.
+/// If the change is successful, releases the lock and restores the
+/// CWD to what it was before, returning true.
+/// Returns false if the directory doesn't exist or if the directory change
+/// is otherwise unsuccessful.
+///
+/// This is used by test cases to avoid cwd races.
+///
+/// # Safety Note
+///
+/// This uses a pthread mutex so descheduling in the action callback
+/// can lead to deadlock. Calling change_dir_locked recursively will
+/// also deadlock.
+pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
+ use os;
+ use os::change_dir;
+ use task;
+ use unstable::finally::Finally;
+
+ unsafe {
+ // This is really sketchy. Using a pthread mutex so descheduling
+ // in the `action` callback can cause deadlock. Doing it in
+ // `task::atomically` to try to avoid that, but ... I don't know
+ // this is all bogus.
+ return do task::atomically {
+ rust_take_change_dir_lock();
+
+ do (||{
+ let old_dir = os::getcwd();
+ if change_dir(p) {
+ action();
+ change_dir(&old_dir)
+ }
+ else {
+ false
+ }
+ }).finally {
+ rust_drop_change_dir_lock();
+ }
+ }
+ }
+
+ extern {
+ fn rust_take_change_dir_lock();
+ fn rust_drop_change_dir_lock();
+ }
+}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-Weak tasks
-
-Weak tasks are a runtime feature for building global services that
-do not keep the runtime alive. Normally the runtime exits when all
-tasks exits, but if a task is weak then the runtime may exit while
-it is running, sending a notification to the task that the runtime
-is trying to shut down.
-*/
-
-use cell::Cell;
-use comm::{GenericSmartChan, stream};
-use comm::{Port, Chan, SharedChan, GenericChan, GenericPort};
-use hashmap::HashMap;
-use option::{Some, None};
-use unstable::at_exit::at_exit;
-use unstable::finally::Finally;
-use unstable::global::global_data_clone_create;
-use task::rt::{task_id, get_task_id};
-use task::task;
-
-#[cfg(test)] use task::spawn;
-
-type ShutdownMsg = ();
-
-// FIXME #4729: This could be a PortOne but I've experienced bugginess
-// with oneshot pipes and try_send
-pub unsafe fn weaken_task(f: &fn(Port<ShutdownMsg>)) {
- let service = global_data_clone_create(global_data_key,
- create_global_service);
- let (shutdown_port, shutdown_chan) = stream::<ShutdownMsg>();
- let shutdown_port = Cell::new(shutdown_port);
- let task = get_task_id();
- // Expect the weak task service to be alive
- assert!(service.try_send(RegisterWeakTask(task, shutdown_chan)));
- rust_dec_kernel_live_count();
- do (|| {
- f(shutdown_port.take())
- }).finally || {
- rust_inc_kernel_live_count();
- // Service my have already exited
- service.send(UnregisterWeakTask(task));
- }
-}
-
-type WeakTaskService = SharedChan<ServiceMsg>;
-type TaskHandle = task_id;
-
-fn global_data_key(_v: WeakTaskService) { }
-
-enum ServiceMsg {
- RegisterWeakTask(TaskHandle, Chan<ShutdownMsg>),
- UnregisterWeakTask(TaskHandle),
- Shutdown
-}
-
-fn create_global_service() -> ~WeakTaskService {
-
- debug!("creating global weak task service");
- let (port, chan) = stream::<ServiceMsg>();
- let port = Cell::new(port);
- let chan = SharedChan::new(chan);
- let chan_clone = chan.clone();
-
- let mut task = task();
- task.unlinked();
- do task.spawn {
- debug!("running global weak task service");
- let port = Cell::new(port.take());
- do (|| {
- let port = port.take();
- // The weak task service is itself a weak task
- debug!("weakening the weak service task");
- unsafe { rust_dec_kernel_live_count(); }
- run_weak_task_service(port);
- }).finally {
- debug!("unweakening the weak service task");
- unsafe { rust_inc_kernel_live_count(); }
- }
- }
-
- do at_exit {
- debug!("shutting down weak task service");
- chan.send(Shutdown);
- }
-
- return ~chan_clone;
-}
-
-fn run_weak_task_service(port: Port<ServiceMsg>) {
-
- let mut shutdown_map = HashMap::new();
-
- loop {
- match port.recv() {
- RegisterWeakTask(task, shutdown_chan) => {
- let previously_unregistered =
- shutdown_map.insert(task, shutdown_chan);
- assert!(previously_unregistered);
- }
- UnregisterWeakTask(task) => {
- match shutdown_map.pop(&task) {
- Some(shutdown_chan) => {
- // Oneshot pipes must send, even though
- // nobody will receive this
- shutdown_chan.send(());
- }
- None => fail!()
- }
- }
- Shutdown => break
- }
- }
-
- for shutdown_map.consume().advance |(_, shutdown_chan)| {
- // Weak task may have already exited
- shutdown_chan.send(());
- }
-}
-
-extern {
- unsafe fn rust_inc_kernel_live_count();
- unsafe fn rust_dec_kernel_live_count();
-}
-
-#[test]
-fn test_simple() {
- let (port, chan) = stream();
- do spawn {
- unsafe {
- do weaken_task |_signal| {
- }
- }
- chan.send(());
- }
- port.recv();
-}
-
-#[test]
-fn test_weak_weak() {
- let (port, chan) = stream();
- do spawn {
- unsafe {
- do weaken_task |_signal| {
- }
- do weaken_task |_signal| {
- }
- }
- chan.send(());
- }
- port.recv();
-}
-
-#[test]
-fn test_wait_for_signal() {
- do spawn {
- unsafe {
- do weaken_task |signal| {
- signal.recv();
- }
- }
- }
-}
-
-#[test]
-fn test_wait_for_signal_many() {
- use uint;
- for uint::range(0, 100) |_| {
- do spawn {
- unsafe {
- do weaken_task |signal| {
- signal.recv();
- }
- }
- }
- }
-}
-
-#[test]
-fn test_select_stream_and_oneshot() {
- use comm::select2i;
- use either::{Left, Right};
-
- let (port, chan) = stream();
- let port = Cell::new(port);
- let (waitport, waitchan) = stream();
- do spawn {
- unsafe {
- do weaken_task |mut signal| {
- let mut port = port.take();
- match select2i(&mut port, &mut signal) {
- Left(*) => (),
- Right(*) => fail!()
- }
- }
- }
- waitchan.send(());
- }
- chan.send(());
- waitport.recv();
-}
// verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct
- // NOTE: uncomment after snapshot, will not parse yet
- //static mut did_run: bool = false;
+ static mut did_run: bool = false;
struct Foo { five: int }
impl Drop for Foo {
fn drop(&self) {
assert_eq!(self.five, 5);
- // NOTE: uncomment after snapshot, will not parse yet
- //unsafe {
- //did_run = true;
- //}
+ unsafe {
+ did_run = true;
+ }
}
}
let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
}
- // NOTE: uncomment after snapshot, will not parse yet
- //unsafe { assert_eq!(did_run, true); }
+ unsafe { assert_eq!(did_run, true); }
}
}
use ptr::to_unsafe_ptr;
use ptr;
use ptr::RawPtr;
-#[cfg(not(stage0))]
use rt::global_heap::malloc_raw;
use rt::global_heap::realloc_raw;
use sys;
use sys::size_of;
use uint;
use unstable::intrinsics;
-#[cfg(stage0)]
-use intrinsic::{get_tydesc};
-#[cfg(not(stage0))]
use unstable::intrinsics::{get_tydesc, contains_managed};
use vec;
use util;
}
/// Creates a new vector with a capacity of `capacity`
-#[cfg(stage0)]
-pub fn with_capacity<T>(capacity: uint) -> ~[T] {
- let mut vec = ~[];
- vec.reserve(capacity);
- vec
-}
-
-/// Creates a new vector with a capacity of `capacity`
-#[cfg(not(stage0))]
pub fn with_capacity<T>(capacity: uint) -> ~[T] {
unsafe {
if contains_managed::<T>() {
#[allow(missing_doc)]
pub trait ImmutableVector<'self, T> {
fn slice(&self, start: uint, end: uint) -> &'self [T];
+ fn slice_from(&self, start: uint) -> &'self [T];
+ fn slice_to(&self, end: uint) -> &'self [T];
fn iter(self) -> VecIterator<'self, T>;
fn rev_iter(self) -> VecRevIterator<'self, T>;
fn split_iter(self, pred: &'self fn(&T) -> bool) -> VecSplitIterator<'self, T>;
/// Extension methods for vectors
impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
- /// Return a slice that points into another slice.
+
+ /**
+ * Returns a slice of self between `start` and `end`.
+ *
+ * Fails when `start` or `end` point outside the bounds of self,
+ * or when `start` > `end`.
+ */
#[inline]
fn slice(&self, start: uint, end: uint) -> &'self [T] {
- assert!(start <= end);
- assert!(end <= self.len());
+ assert!(start <= end);
+ assert!(end <= self.len());
do self.as_imm_buf |p, _len| {
unsafe {
transmute((ptr::offset(p, start),
}
}
+ /**
+ * Returns a slice of self from `start` to the end of the vec.
+ *
+ * Fails when `start` points outside the bounds of self.
+ */
+ #[inline]
+ fn slice_from(&self, start: uint) -> &'self [T] {
+ self.slice(start, self.len())
+ }
+
+ /**
+ * Returns a slice of self from the start of the vec to `end`.
+ *
+ * Fails when `end` points outside the bounds of self.
+ */
+ #[inline]
+ fn slice_to(&self, end: uint) -> &'self [T] {
+ self.slice(0, end)
+ }
+
#[inline]
fn iter(self) -> VecIterator<'self, T> {
unsafe {
*
* * n - The number of elements to reserve space for
*/
- #[cfg(stage0)]
- fn reserve(&mut self, n: uint) {
- // Only make the (slow) call into the runtime if we have to
- use managed;
- if self.capacity() < n {
- unsafe {
- let ptr: *mut *mut raw::VecRepr = cast::transmute(self);
- let td = get_tydesc::<T>();
- if ((**ptr).box_header.ref_count ==
- managed::raw::RC_MANAGED_UNIQUE) {
- // XXX transmute shouldn't be necessary
- let td = cast::transmute(td);
- ::at_vec::raw::reserve_raw(td, ptr, n);
- } else {
- let alloc = n * sys::nonzero_size_of::<T>();
- *ptr = realloc_raw(*ptr as *mut c_void, alloc + size_of::<raw::VecRepr>())
- as *mut raw::VecRepr;
- (**ptr).unboxed.alloc = alloc;
- }
- }
- }
- }
-
- /**
- * Reserves capacity for exactly `n` elements in the given vector.
- *
- * If the capacity for `self` is already equal to or greater than the requested
- * capacity, then no action is taken.
- *
- * # Arguments
- *
- * * n - The number of elements to reserve space for
- */
- #[cfg(not(stage0))]
fn reserve(&mut self, n: uint) {
// Only make the (slow) call into the runtime if we have to
if self.capacity() < n {
/// Returns the number of elements the vector can hold without reallocating.
#[inline]
- #[cfg(stage0)]
- fn capacity(&self) -> uint {
- unsafe {
- let repr: **raw::VecRepr = transmute(self);
- (**repr).unboxed.alloc / sys::nonzero_size_of::<T>()
- }
- }
-
- /// Returns the number of elements the vector can hold without reallocating.
- #[inline]
- #[cfg(not(stage0))]
fn capacity(&self) -> uint {
unsafe {
if contains_managed::<T>() {
/// Append an element to a vector
#[inline]
- #[cfg(stage0)]
- fn push(&mut self, t: T) {
- unsafe {
- let repr: **raw::VecRepr = transmute(&mut *self);
- let fill = (**repr).unboxed.fill;
- if (**repr).unboxed.alloc <= fill {
- let new_len = self.len() + 1;
- self.reserve_at_least(new_len);
- }
-
- self.push_fast(t);
- }
- }
-
- /// Append an element to a vector
- #[inline]
- #[cfg(not(stage0))]
fn push(&mut self, t: T) {
unsafe {
if contains_managed::<T>() {
// This doesn't bother to make sure we have space.
#[inline] // really pretty please
- #[cfg(stage0)]
- unsafe fn push_fast(&mut self, t: T) {
- let repr: **mut raw::VecRepr = transmute(self);
- let fill = (**repr).unboxed.fill;
- (**repr).unboxed.fill += sys::nonzero_size_of::<T>();
- let p = to_unsafe_ptr(&((**repr).unboxed.data));
- let p = ptr::offset(p, fill) as *mut T;
- intrinsics::move_val_init(&mut(*p), t);
- }
-
- // This doesn't bother to make sure we have space.
- #[inline] // really pretty please
- #[cfg(not(stage0))]
unsafe fn push_fast(&mut self, t: T) {
if contains_managed::<T>() {
let repr: **mut raw::VecRepr = transmute(self);
use sys;
use unstable::intrinsics;
use vec::{UnboxedVecRepr, with_capacity, ImmutableVector, MutableVector};
- #[cfg(not(stage0))]
use unstable::intrinsics::contains_managed;
/// The internal representation of a (boxed) vector
* the vector is actually the specified size.
*/
#[inline]
- #[cfg(stage0)]
- pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) {
- let repr: **mut VecRepr = transmute(v);
- (**repr).unboxed.fill = new_len * sys::nonzero_size_of::<T>();
- }
-
- /**
- * Sets the length of a vector
- *
- * This will explicitly set the size of the vector, without actually
- * modifing its buffers, so it is up to the caller to ensure that
- * the vector is actually the specified size.
- */
- #[inline]
- #[cfg(not(stage0))]
pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) {
if contains_managed::<T>() {
let repr: **mut VecRepr = transmute(v);
}
}
-#[cfg(stage0)]
-impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
- pub fn from_iterator(iterator: &mut T) -> ~[A] {
- let mut xs = ~[];
- for iterator.advance |x| {
- xs.push(x);
- }
- xs
- }
-}
-
-
-#[cfg(not(stage0))]
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
pub fn from_iterator(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
assert_eq!(v_d[4], 6);
}
+ #[test]
+ fn test_slice_from() {
+ let vec = &[1, 2, 3, 4];
+ assert_eq!(vec.slice_from(0), vec);
+ assert_eq!(vec.slice_from(2), &[3, 4]);
+ assert_eq!(vec.slice_from(4), &[]);
+ }
+
+ #[test]
+ fn test_slice_to() {
+ let vec = &[1, 2, 3, 4];
+ assert_eq!(vec.slice_to(4), vec);
+ assert_eq!(vec.slice_to(2), &[1, 2]);
+ assert_eq!(vec.slice_to(0), &[]);
+ }
+
#[test]
fn test_pop() {
// Test on-heap pop.
/// Construct an identifier with the given name and an empty context:
pub fn new_ident(name: Name) -> ident { ident {name: name, ctxt: empty_ctxt}}
-// a SyntaxContext represents a chain of macro-expandings
-// and renamings. Each macro expansion corresponds to
-// a fresh uint
+/// A SyntaxContext represents a chain of macro-expandings
+/// and renamings. Each macro expansion corresponds to
+/// a fresh uint
// I'm representing this syntax context as an index into
// a table, in order to work around a compiler bug
IllegalCtxt()
}
-// a name is a part of an identifier, representing a string
-// or gensym. It's the result of interning.
+/// A name is a part of an identifier, representing a string or gensym. It's
+/// the result of interning.
pub type Name = uint;
-// a mark represents a unique id associated
-// with a macro expansion
+/// A mark represents a unique id associated with a macro expansion
pub type Mrk = uint;
impl<S:Encoder> Encodable<S> for ident {
}
}
-// Functions may or may not have names.
+/// Function name (not all functions have names)
pub type fn_ident = Option<ident>;
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct Path {
span: span,
+ /// A `::foo` path, is relative to the crate root rather than current
+ /// module (like paths in an import).
global: bool,
+ /// The segments in the path (the things separated by ::)
idents: ~[ident],
+ /// "Region parameter", currently only one lifetime is allowed in a path.
rp: Option<Lifetime>,
+ /// These are the type parameters, ie, the `a, b` in `foo::bar::<a, b>`
types: ~[Ty],
}
-pub type crate_num = int;
+pub type CrateNum = int;
pub type node_id = int;
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct def_id {
- crate: crate_num,
+ crate: CrateNum,
node: node_id,
}
-pub static local_crate: crate_num = 0;
+pub static local_crate: CrateNum = 0;
pub static crate_node_id: node_id = 0;
// The AST represents all type param bounds as types.
// The set of MetaItems that define the compilation environment of the crate,
// used to drive conditional compilation
-pub type crate_cfg = ~[@MetaItem];
-
-pub type crate = spanned<crate_>;
+pub type CrateConfig = ~[@MetaItem];
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub struct crate_ {
+pub struct Crate {
module: _mod,
attrs: ~[Attribute],
- config: crate_cfg,
+ config: CrateConfig,
+ span: span,
}
pub type MetaItem = spanned<MetaItem_>;
}
}
-//pub type blk = spanned<blk_>;
-
#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-pub struct blk {
+pub struct Block {
view_items: ~[view_item],
stmts: ~[@stmt],
expr: Option<@expr>,
// FIXME (pending discussion of #1697, #2178...): local should really be
// a refinement on pat.
#[deriving(Eq, Encodable, Decodable,IterBytes)]
-pub struct local_ {
+pub struct Local {
is_mutbl: bool,
ty: Ty,
pat: @pat,
init: Option<@expr>,
id: node_id,
+ span: span,
}
-pub type local = spanned<local_>;
-
pub type decl = spanned<decl_>;
#[deriving(Eq, Encodable, Decodable,IterBytes)]
pub enum decl_ {
// a local (let) binding:
- decl_local(@local),
+ decl_local(@Local),
// an item binding:
decl_item(@item),
}
pub struct arm {
pats: ~[@pat],
guard: Option<@expr>,
- body: blk,
+ body: Block,
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
-pub struct field_ {
+pub struct Field {
ident: ident,
expr: @expr,
+ span: span,
}
-pub type field = spanned<field_>;
-
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum blk_check_mode {
default_blk,
expr_unary(node_id, unop, @expr),
expr_lit(@lit),
expr_cast(@expr, Ty),
- expr_if(@expr, blk, Option<@expr>),
- expr_while(@expr, blk),
+ expr_if(@expr, Block, Option<@expr>),
+ expr_while(@expr, Block),
/* Conditionless loop (can be exited with break, cont, or ret)
Same semantics as while(true) { body }, but typestate knows that the
(implicit) condition is always true. */
- expr_loop(blk, Option<ident>),
+ expr_loop(Block, Option<ident>),
expr_match(@expr, ~[arm]),
- expr_fn_block(fn_decl, blk),
+ expr_fn_block(fn_decl, Block),
// Inner expr is always an expr_fn_block. We need the wrapping node to
// easily type this (a function returning nil on the inside but bool on
// the outside).
expr_loop_body(@expr),
// Like expr_loop_body but for 'do' blocks
expr_do_body(@expr),
- expr_block(blk),
+ expr_block(Block),
expr_assign(@expr, @expr),
expr_assign_op(node_id, binop, @expr, @expr),
expr_mac(mac),
// A struct literal expression.
- expr_struct(Path, ~[field], Option<@expr>),
+ expr_struct(Path, ~[Field], Option<@expr>),
// A vector literal constructed from one repeated element.
expr_repeat(@expr /* element */, @expr /* count */, mutability),
explicit_self: explicit_self,
purity: purity,
decl: fn_decl,
- body: blk,
+ body: Block,
id: node_id,
span: span,
self_id: node_id,
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum item_ {
item_static(Ty, mutability, @expr),
- item_fn(fn_decl, purity, AbiSet, Generics, blk),
+ item_fn(fn_decl, purity, AbiSet, Generics, Block),
item_mod(_mod),
item_foreign_mod(foreign_mod),
item_ty(Ty, Generics),
node_stmt(@stmt),
node_arg,
node_local(ident),
- node_block(blk),
+ node_block(Block),
node_struct_ctor(@struct_def, @item, @path),
node_callee_scope(@expr)
}
});
}
-pub fn map_crate(diag: @span_handler, c: &crate) -> map {
+pub fn map_crate(diag: @span_handler, c: &Crate) -> map {
let cx = @mut Ctx {
map: @mut HashMap::new(),
path: ~[],
pub fn map_fn(
fk: &visit::fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: codemap::span,
id: node_id,
(cx,v): (@mut Ctx,
visit::visit_fn(fk, decl, body, sp, id, (cx, v));
}
-pub fn map_block(b: &blk, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
+pub fn map_block(b: &Block, (cx,v): (@mut Ctx, visit::vt<@mut Ctx>)) {
cx.map.insert(b.id, node_block(/* FIXME (#2543) */ (*b).clone()));
visit::visit_block(b, (cx, v));
}
match e.node { expr_call(*) => true, _ => false }
}
-pub fn block_from_expr(e: @expr) -> blk {
+pub fn block_from_expr(e: @expr) -> Block {
let mut blk = default_block(~[], option::Some::<@expr>(e), e.id);
blk.span = e.span;
return blk;
stmts1: ~[@stmt],
expr1: Option<@expr>,
id1: node_id
-) -> blk {
- ast::blk {
+) -> Block {
+ ast::Block {
view_items: ~[],
stmts: stmts1,
expr: expr1,
},
visit_local: |l, (t, vt)| {
- vfn(l.node.id, t.clone());
+ vfn(l.id, t.clone());
visit::visit_local(l, (t, vt));
},
visit_block: |b, (t, vt)| {
pub fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool;
}
-impl EachViewItem for ast::crate {
+impl EachViewItem for ast::Crate {
fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool {
let broke = @mut false;
let vtor: visit::vt<()> = visit::mk_simple_visitor(@visit::SimpleVisitor {
// fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn get_sctable() -> @mut SCTable {
- #[cfg(not(stage0))]
static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
- #[cfg(stage0)]
- fn sctable_key(_: @@mut SCTable) {}
match local_data::get(sctable_key, |k| k.map(|&k| *k)) {
None => {
let new_table = @@mut new_sctable_internal();
}
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
- #[cfg(not(stage0))]
static tls_terminal: local_data::Key<@Option<term::Terminal>> = &local_data::Key;
- #[cfg(stage0)]
- fn tls_terminal(_: @Option<term::Terminal>) {}
let stderr = io::stderr();
// -> expn_info of their expansion context stored into their span.
pub struct ExtCtxt {
parse_sess: @mut parse::ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
backtrace: @mut Option<@ExpnInfo>,
// These two @mut's should really not be here,
}
impl ExtCtxt {
- pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg)
+ pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::CrateConfig)
-> @ExtCtxt {
@ExtCtxt {
parse_sess: parse_sess,
pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
pub fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess }
- pub fn cfg(&self) -> ast::crate_cfg { self.cfg.clone() }
+ pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
pub fn call_site(&self) -> span {
match *self.backtrace {
Some(@ExpnInfo {call_site: cs, _}) => cs,
fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt;
// blocks
- fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::blk;
- fn blk_expr(&self, expr: @ast::expr) -> ast::blk;
+ fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::Block;
+ fn blk_expr(&self, expr: @ast::expr) -> ast::Block;
fn blk_all(&self, span: span,
view_items: ~[ast::view_item],
stmts: ~[@ast::stmt],
- expr: Option<@ast::expr>) -> ast::blk;
+ expr: Option<@ast::expr>) -> ast::Block;
// expressions
fn expr(&self, span: span, node: ast::expr_) -> @ast::expr;
fn expr_method_call(&self, span: span,
expr: @ast::expr, ident: ast::ident,
args: ~[@ast::expr]) -> @ast::expr;
- fn expr_blk(&self, b: ast::blk) -> @ast::expr;
+ fn expr_blk(&self, b: ast::Block) -> @ast::expr;
- fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::field;
- fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::field]) -> @ast::expr;
- fn expr_struct_ident(&self, span: span, id: ast::ident, fields: ~[ast::field]) -> @ast::expr;
+ fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::Field;
+ fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::Field]) -> @ast::expr;
+ fn expr_struct_ident(&self, span: span, id: ast::ident, fields: ~[ast::Field]) -> @ast::expr;
fn expr_lit(&self, sp: span, lit: ast::lit_) -> @ast::expr;
fn expr_if(&self, span: span,
cond: @ast::expr, then: @ast::expr, els: Option<@ast::expr>) -> @ast::expr;
- fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::blk) -> @ast::expr;
+ fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::Block) -> @ast::expr;
- fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::blk) -> @ast::expr;
- fn lambda0(&self, span: span, blk: ast::blk) -> @ast::expr;
- fn lambda1(&self, span: span, blk: ast::blk, ident: ast::ident) -> @ast::expr;
+ fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::Block) -> @ast::expr;
+ fn lambda0(&self, span: span, blk: ast::Block) -> @ast::expr;
+ fn lambda1(&self, span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr;
fn lambda_expr(&self, span: span, ids: ~[ast::ident], blk: @ast::expr) -> @ast::expr;
fn lambda_expr_0(&self, span: span, expr: @ast::expr) -> @ast::expr;
inputs: ~[ast::arg],
output: ast::Ty,
generics: Generics,
- body: ast::blk) -> @ast::item;
+ body: ast::Block) -> @ast::item;
fn item_fn(&self,
span: span,
name: ident,
inputs: ~[ast::arg],
output: ast::Ty,
- body: ast::blk) -> @ast::item;
+ body: ast::Block) -> @ast::item;
fn variant(&self, span: span, name: ident, tys: ~[ast::Ty]) -> ast::variant;
fn item_enum_poly(&self,
fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt {
let pat = self.pat_ident(sp, ident);
- let local = @respan(sp,
- ast::local_ {
- is_mutbl: mutbl,
- ty: self.ty_infer(sp),
- pat: pat,
- init: Some(ex),
- id: self.next_id(),
- });
+ let local = @ast::Local {
+ is_mutbl: mutbl,
+ ty: self.ty_infer(sp),
+ pat: pat,
+ init: Some(ex),
+ id: self.next_id(),
+ span: sp,
+ };
let decl = respan(sp, ast::decl_local(local));
@respan(sp, ast::stmt_decl(@decl, self.next_id()))
}
- fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::blk {
+ fn blk(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::Block {
self.blk_all(span, ~[], stmts, expr)
}
- fn blk_expr(&self, expr: @ast::expr) -> ast::blk {
+ fn blk_expr(&self, expr: @ast::expr) -> ast::Block {
self.blk_all(expr.span, ~[], ~[], Some(expr))
}
fn blk_all(&self,
span: span,
view_items: ~[ast::view_item],
stmts: ~[@ast::stmt],
- expr: Option<@ast::expr>) -> ast::blk {
- ast::blk {
+ expr: Option<@ast::expr>) -> ast::Block {
+ ast::Block {
view_items: view_items,
stmts: stmts,
expr: expr,
self.expr(span,
ast::expr_method_call(self.next_id(), expr, ident, ~[], args, ast::NoSugar))
}
- fn expr_blk(&self, b: ast::blk) -> @ast::expr {
+ fn expr_blk(&self, b: ast::Block) -> @ast::expr {
self.expr(b.span, ast::expr_block(b))
}
- fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::field {
- respan(span, ast::field_ { ident: name, expr: e })
+ fn field_imm(&self, span: span, name: ident, e: @ast::expr) -> ast::Field {
+ ast::Field { ident: name, expr: e, span: span }
}
- fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::field]) -> @ast::expr {
+ fn expr_struct(&self, span: span, path: ast::Path, fields: ~[ast::Field]) -> @ast::expr {
self.expr(span, ast::expr_struct(path, fields, None))
}
fn expr_struct_ident(&self, span: span,
- id: ast::ident, fields: ~[ast::field]) -> @ast::expr {
+ id: ast::ident, fields: ~[ast::Field]) -> @ast::expr {
self.expr_struct(span, self.path_ident(span, id), fields)
}
self.expr(span, ast::expr_if(cond, self.blk_expr(then), els))
}
- fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::blk) -> @ast::expr {
+ fn lambda_fn_decl(&self, span: span, fn_decl: ast::fn_decl, blk: ast::Block) -> @ast::expr {
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
- fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::blk) -> @ast::expr {
+ fn lambda(&self, span: span, ids: ~[ast::ident], blk: ast::Block) -> @ast::expr {
let fn_decl = self.fn_decl(
ids.map(|id| self.arg(span, *id, self.ty_infer(span))),
self.ty_infer(span));
self.expr(span, ast::expr_fn_block(fn_decl, blk))
}
- fn lambda0(&self, _span: span, blk: ast::blk) -> @ast::expr {
+ fn lambda0(&self, _span: span, blk: ast::Block) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|| $blk_e )
}
- fn lambda1(&self, _span: span, blk: ast::blk, ident: ast::ident) -> @ast::expr {
+ fn lambda1(&self, _span: span, blk: ast::Block, ident: ast::ident) -> @ast::expr {
let ext_cx = *self;
let blk_e = self.expr(blk.span, ast::expr_block(blk.clone()));
quote_expr!(|$ident| $blk_e )
inputs: ~[ast::arg],
output: ast::Ty,
generics: Generics,
- body: ast::blk) -> @ast::item {
+ body: ast::Block) -> @ast::item {
self.item(span,
name,
~[],
name: ident,
inputs: ~[ast::arg],
output: ast::Ty,
- body: ast::blk
+ body: ast::Block
) -> @ast::item {
self.item_fn_poly(
span,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{blk, crate, expr_, expr_mac, mac_invoc_tt};
+use ast::{Block, Crate, expr_, expr_mac, mac_invoc_tt};
use ast::{item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi};
use ast::{illegal_ctxt};
use ast;
pub fn expand_block(extsbox: @mut SyntaxEnv,
_cx: @ExtCtxt,
- blk: &blk,
+ blk: &Block,
fld: @ast_fold,
- orig: @fn(&blk, @ast_fold) -> blk)
- -> blk {
+ orig: @fn(&Block, @ast_fold) -> Block)
+ -> Block {
// see note below about treatment of exts table
with_exts_frame!(extsbox,false,orig(blk,fld))
}
// add a bunch of macros as though they were placed at the head of the
// program (ick). This should run before cfg stripping.
pub fn inject_std_macros(parse_sess: @mut parse::ParseSess,
- cfg: ast::crate_cfg, c: &crate) -> @crate {
+ cfg: ast::CrateConfig, c: &Crate) -> @Crate {
let sm = match parse_item_from_source_str(@"<std-macros>",
std_macros(),
cfg.clone(),
}
pub fn expand_crate(parse_sess: @mut parse::ParseSess,
- cfg: ast::crate_cfg, c: &crate) -> @crate {
+ cfg: ast::CrateConfig, c: &Crate) -> @Crate {
// adding *another* layer of indirection here so that the block
// visitor can swap out one exts table for another for the duration
// of the block. The cleaner alternative would be to thread the
}
}
- impl ToSource for ast::blk {
+ impl ToSource for ast::Block {
fn to_source(&self) -> @str {
pprust::block_to_str(self, get_ident_interner()).to_managed()
}
}
}
- impl ToTokens for ast::blk {
+ impl ToTokens for ast::Block {
fn to_tokens(&self, cx: @ExtCtxt) -> ~[token_tree] {
cx.parse_tts(self.to_source())
}
pub fn parse_or_else(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
rdr: @reader,
ms: ~[matcher]
) -> HashMap<ident, @named_match> {
pub fn parse(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
rdr: @reader,
ms: &[matcher]
) -> parse_result {
use opt_vec::OptVec;
pub trait ast_fold {
- fn fold_crate(@self, &crate) -> crate;
+ fn fold_crate(@self, &Crate) -> Crate;
fn fold_view_item(@self, &view_item) -> view_item;
fn fold_foreign_item(@self, @foreign_item) -> @foreign_item;
fn fold_item(@self, @item) -> Option<@item>;
fn fold_struct_field(@self, @struct_field) -> @struct_field;
fn fold_item_underscore(@self, &item_) -> item_;
fn fold_method(@self, @method) -> @method;
- fn fold_block(@self, &blk) -> blk;
+ fn fold_block(@self, &Block) -> Block;
fn fold_stmt(@self, &stmt) -> Option<@stmt>;
fn fold_arm(@self, &arm) -> arm;
fn fold_pat(@self, @pat) -> @pat;
fn fold_variant(@self, &variant) -> variant;
fn fold_ident(@self, ident) -> ident;
fn fold_path(@self, &Path) -> Path;
- fn fold_local(@self, @local) -> @local;
+ fn fold_local(@self, @Local) -> @Local;
fn map_exprs(@self, @fn(@expr) -> @expr, &[@expr]) -> ~[@expr];
fn new_id(@self, node_id) -> node_id;
fn new_span(@self, span) -> span;
pub struct AstFoldFns {
//unlike the others, item_ is non-trivial
- fold_crate: @fn(&crate_, span, @ast_fold) -> (crate_, span),
+ fold_crate: @fn(&Crate, @ast_fold) -> Crate,
fold_view_item: @fn(&view_item_, @ast_fold) -> view_item_,
fold_foreign_item: @fn(@foreign_item, @ast_fold) -> @foreign_item,
fold_item: @fn(@item, @ast_fold) -> Option<@item>,
fold_struct_field: @fn(@struct_field, @ast_fold) -> @struct_field,
fold_item_underscore: @fn(&item_, @ast_fold) -> item_,
fold_method: @fn(@method, @ast_fold) -> @method,
- fold_block: @fn(&blk, @ast_fold) -> blk,
+ fold_block: @fn(&Block, @ast_fold) -> Block,
fold_stmt: @fn(&stmt_, span, @ast_fold) -> (Option<stmt_>, span),
fold_arm: @fn(&arm, @ast_fold) -> arm,
fold_pat: @fn(&pat_, span, @ast_fold) -> (pat_, span),
fold_variant: @fn(&variant_, span, @ast_fold) -> (variant_, span),
fold_ident: @fn(ident, @ast_fold) -> ident,
fold_path: @fn(&Path, @ast_fold) -> Path,
- fold_local: @fn(&local_, span, @ast_fold) -> (local_, span),
+ fold_local: @fn(@Local, @ast_fold) -> @Local,
map_exprs: @fn(@fn(@expr) -> @expr, &[@expr]) -> ~[@expr],
new_id: @fn(node_id) -> node_id,
new_span: @fn(span) -> span
lifetimes: fold_lifetimes(&generics.lifetimes, fld)}
}
-pub fn noop_fold_crate(c: &crate_, fld: @ast_fold) -> crate_ {
+pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
let fold_meta_item = |x| fold_meta_item_(x, fld);
let fold_attribute = |x| fold_attribute_(x, fld);
- crate_ {
+ Crate {
module: fld.fold_mod(&c.module),
attrs: c.attrs.map(|x| fold_attribute(*x)),
config: c.config.map(|x| fold_meta_item(*x)),
+ span: fld.new_span(c.span),
}
}
}
-pub fn noop_fold_block(b: &blk, fld: @ast_fold) -> blk {
+pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
let view_items = b.view_items.map(|x| fld.fold_view_item(x));
let mut stmts = ~[];
for b.stmts.iter().advance |stmt| {
Some(stmt) => stmts.push(stmt)
}
}
- ast::blk {
+ ast::Block {
view_items: view_items,
stmts: stmts,
expr: b.expr.map(|x| fld.fold_expr(*x)),
}
pub fn noop_fold_expr(e: &expr_, fld: @ast_fold) -> expr_ {
- fn fold_field_(field: field, fld: @ast_fold) -> field {
- spanned {
- node: ast::field_ {
- ident: fld.fold_ident(field.node.ident),
- expr: fld.fold_expr(field.node.expr),
- },
+ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
+ ast::Field {
+ ident: fld.fold_ident(field.ident),
+ expr: fld.fold_expr(field.expr),
span: fld.new_span(field.span),
}
}
}
}
-fn noop_fold_local(l: &local_, fld: @ast_fold) -> local_ {
- local_ {
+fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local {
+ @Local {
is_mutbl: l.is_mutbl,
ty: fld.fold_ty(&l.ty),
pat: fld.fold_pat(l.pat),
init: l.init.map(|e| fld.fold_expr(*e)),
id: fld.new_id(l.id),
+ span: fld.new_span(l.span),
}
}
pub fn default_ast_fold() -> ast_fold_fns {
@AstFoldFns {
- fold_crate: wrap(noop_fold_crate),
+ fold_crate: noop_fold_crate,
fold_view_item: noop_fold_view_item,
fold_foreign_item: noop_fold_foreign_item,
fold_item: noop_fold_item,
fold_variant: wrap(noop_fold_variant),
fold_ident: noop_fold_ident,
fold_path: noop_fold_path,
- fold_local: wrap(noop_fold_local),
+ fold_local: noop_fold_local,
map_exprs: noop_map_exprs,
new_id: noop_id,
new_span: noop_span,
impl ast_fold for AstFoldFns {
/* naturally, a macro to write these would be nice */
- fn fold_crate(@self, c: &crate) -> crate {
- let (n, s) = (self.fold_crate)(&c.node, c.span, self as @ast_fold);
- spanned { node: n, span: (self.new_span)(s) }
+ fn fold_crate(@self, c: &Crate) -> Crate {
+ (self.fold_crate)(c, self as @ast_fold)
}
fn fold_view_item(@self, x: &view_item) -> view_item {
ast::view_item {
fn fold_method(@self, x: @method) -> @method {
(self.fold_method)(x, self as @ast_fold)
}
- fn fold_block(@self, x: &blk) -> blk {
+ fn fold_block(@self, x: &Block) -> Block {
(self.fold_block)(x, self as @ast_fold)
}
fn fold_stmt(@self, x: &stmt) -> Option<@stmt> {
fn fold_path(@self, x: &Path) -> Path {
(self.fold_path)(x, self as @ast_fold)
}
- fn fold_local(@self, x: @local) -> @local {
- let (n, s) = (self.fold_local)(&x.node, x.span, self as @ast_fold);
- @spanned { node: n, span: (self.new_span)(s) }
+ fn fold_local(@self, x: @Local) -> @Local {
+ (self.fold_local)(x, self as @ast_fold)
}
fn map_exprs(@self,
f: @fn(@expr) -> @expr,
}
// this version doesn't care about getting comments or docstrings in.
- fn fake_print_crate(s: @pprust::ps, crate: &ast::crate) {
- pprust::print_mod(s, &crate.node.module, crate.node.attrs);
+ fn fake_print_crate(s: @pprust::ps, crate: &ast::Crate) {
+ pprust::print_mod(s, &crate.module, crate.attrs);
}
// change every identifier to "zz"
pub fn expr_is_simple_block(e: @ast::expr) -> bool {
match e.node {
ast::expr_block(
- ast::blk { rules: ast::default_blk, _ }
+ ast::Block { rules: ast::default_blk, _ }
) => true,
_ => false
}
pub fn parse_crate_from_file(
input: &Path,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
-) -> @ast::crate {
+) -> @ast::Crate {
new_parser_from_file(sess, /*bad*/ cfg.clone(), input).parse_crate_mod()
// why is there no p.abort_if_errors here?
}
pub fn parse_crate_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
-) -> @ast::crate {
+) -> @ast::Crate {
let p = new_parser_from_source_str(sess,
/*bad*/ cfg.clone(),
name,
pub fn parse_expr_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> @ast::expr {
let p = new_parser_from_source_str(
pub fn parse_item_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
attrs: ~[ast::Attribute],
sess: @mut ParseSess
) -> Option<@ast::item> {
pub fn parse_meta_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> @ast::MetaItem {
let p = new_parser_from_source_str(
pub fn parse_stmt_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
attrs: ~[ast::Attribute],
sess: @mut ParseSess
) -> @ast::stmt {
pub fn parse_tts_from_source_str(
name: @str,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> ~[ast::token_tree] {
let p = new_parser_from_source_str(
f: &fn(&Parser) -> T,
name: @str, ss: codemap::FileSubstr,
source: @str,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
sess: @mut ParseSess
) -> T {
let p = new_parser_from_source_substr(
// Create a new parser from a source string
pub fn new_parser_from_source_str(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
name: @str,
source: @str)
-> Parser {
// Create a new parser from a source string where the origin
// is specified as a substring of another file.
pub fn new_parser_from_source_substr(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
name: @str,
ss: codemap::FileSubstr,
source: @str)
/// if the file doesn't exist
pub fn new_parser_from_file(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
path: &Path
) -> Parser {
filemap_to_parser(sess,file_to_filemap(sess,path,None),cfg)
/// On an error, use the given span as the source of the problem.
pub fn new_sub_parser_from_file(
sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
path: &Path,
sp: span
) -> Parser {
/// Given a filemap and config, return a parser
pub fn filemap_to_parser(sess: @mut ParseSess,
filemap: @FileMap,
- cfg: ast::crate_cfg) -> Parser {
+ cfg: ast::CrateConfig) -> Parser {
tts_to_parser(sess,filemap_to_tts(sess,filemap),cfg)
}
// must preserve old name for now, because quote! from the *existing*
// compiler expands into it
pub fn new_parser_from_tts(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
tts: ~[ast::token_tree]) -> Parser {
tts_to_parser(sess,tts,cfg)
}
// given tts and cfg, produce a parser
pub fn tts_to_parser(sess: @mut ParseSess,
tts: ~[ast::token_tree],
- cfg: ast::crate_cfg) -> Parser {
+ cfg: ast::CrateConfig) -> Parser {
let trdr = lexer::new_tt_reader(sess.span_diagnostic, None, tts);
Parser(sess, cfg, trdr as @reader)
}
lifetimes: opt_vec::Empty,
ty_params: opt_vec::Empty,
},
- ast::blk {
+ ast::Block {
view_items: ~[],
stmts: ~[@spanned{
node: ast::stmt_semi(@ast::expr{
use ast::{RegionTyParamBound, TraitTyParamBound};
use ast::{provided, public, purity};
use ast::{_mod, add, arg, arm, Attribute, bind_by_ref, bind_infer};
-use ast::{bitand, bitor, bitxor, blk};
+use ast::{bitand, bitor, bitxor, Block};
use ast::{blk_check_mode, box};
-use ast::{crate, crate_cfg, decl, decl_item};
+use ast::{Crate, CrateConfig, decl, decl_item};
use ast::{decl_local, default_blk, deref, div, enum_def, explicit_self};
use ast::{expr, expr_, expr_addr_of, expr_match, expr_again};
use ast::{expr_assign, expr_assign_op, expr_binary, expr_block};
use ast::{expr_ret, expr_self, expr_struct, expr_tup, expr_unary};
use ast::{expr_vec, expr_vstore, expr_vstore_mut_box};
use ast::{expr_vstore_slice, expr_vstore_box};
-use ast::{expr_vstore_mut_slice, expr_while, extern_fn, field, fn_decl};
+use ast::{expr_vstore_mut_slice, expr_while, extern_fn, Field, fn_decl};
use ast::{expr_vstore_uniq, Onceness, Once, Many};
use ast::{foreign_item, foreign_item_static, foreign_item_fn, foreign_mod};
use ast::{ident, impure_fn, inherited, item, item_, item_static};
use ast::{item_enum, item_fn, item_foreign_mod, item_impl};
use ast::{item_mac, item_mod, item_struct, item_trait, item_ty, lit, lit_};
use ast::{lit_bool, lit_float, lit_float_unsuffixed, lit_int};
-use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const};
+use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, Local, m_const};
use ast::{m_imm, m_mutbl, mac_, mac_invoc_tt, matcher, match_nonterminal};
use ast::{match_seq, match_tok, method, mt, mul, mutability};
use ast::{named_field, neg, node_id, noreturn, not, pat, pat_box, pat_enum};
/* ident is handled by common.rs */
pub fn Parser(sess: @mut ParseSess,
- cfg: ast::crate_cfg,
+ cfg: ast::CrateConfig,
rdr: @reader)
-> Parser {
let tok0 = rdr.next_token();
// ooh, nasty mutable fields everywhere....
pub struct Parser {
sess: @mut ParseSess,
- cfg: crate_cfg,
+ cfg: CrateConfig,
// the current token:
token: @mut token::Token,
// the span of the current token:
}
// parse ident COLON expr
- pub fn parse_field(&self) -> field {
+ pub fn parse_field(&self) -> Field {
let lo = self.span.lo;
let i = self.parse_ident();
self.expect(&token::COLON);
let e = self.parse_expr();
- spanned(lo, e.span.hi, ast::field_ {
+ ast::Field {
ident: i,
- expr: e
- })
+ expr: e,
+ span: mk_sp(lo, e.span.hi),
+ }
}
pub fn mk_expr(&self, lo: BytePos, hi: BytePos, node: expr_) -> @expr {
let lo = self.last_span.lo;
let decl = parse_decl();
let body = parse_body();
- let fakeblock = ast::blk {
+ let fakeblock = ast::Block {
view_items: ~[],
stmts: ~[],
expr: Some(body),
self.eat(&token::COMMA);
}
- let blk = ast::blk {
+ let blk = ast::Block {
view_items: ~[],
stmts: ~[],
expr: Some(expr),
}
// parse a local variable declaration
- fn parse_local(&self, is_mutbl: bool) -> @local {
+ fn parse_local(&self, is_mutbl: bool) -> @Local {
let lo = self.span.lo;
let pat = self.parse_pat();
};
if self.eat(&token::COLON) { ty = self.parse_ty(false); }
let init = self.parse_initializer();
- @spanned(
- lo,
- self.last_span.hi,
- ast::local_ {
- is_mutbl: is_mutbl,
- ty: ty,
- pat: pat,
- init: init,
- id: self.get_id(),
- }
- )
+ @ast::Local {
+ is_mutbl: is_mutbl,
+ ty: ty,
+ pat: pat,
+ init: init,
+ id: self.get_id(),
+ span: mk_sp(lo, self.last_span.hi),
+ }
}
// parse a "let" stmt
}
// parse a block. No inner attrs are allowed.
- pub fn parse_block(&self) -> blk {
+ pub fn parse_block(&self) -> Block {
maybe_whole!(self, nt_block);
let lo = self.span.lo;
// parse a block. Inner attrs are allowed.
fn parse_inner_attrs_and_block(&self)
- -> (~[Attribute], blk) {
+ -> (~[Attribute], Block) {
maybe_whole!(pair_empty self, nt_block);
// I guess that also means "already parsed the 'impure'" if
// necessary, and this should take a qualifier.
// some blocks start with "#{"...
- fn parse_block_tail(&self, lo: BytePos, s: blk_check_mode) -> blk {
+ fn parse_block_tail(&self, lo: BytePos, s: blk_check_mode) -> Block {
self.parse_block_tail_(lo, s, ~[])
}
// parse the rest of a block expression or function body
fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode,
- first_item_attrs: ~[Attribute]) -> blk {
+ first_item_attrs: ~[Attribute]) -> Block {
let mut stmts = ~[];
let mut expr = None;
let hi = self.span.hi;
self.bump();
- ast::blk {
+ ast::Block {
view_items: view_items,
stmts: stmts,
expr: expr,
let prefix = prefix.dir_path();
let mod_path_stack = &*self.mod_path_stack;
let mod_path = Path(".").push_many(*mod_path_stack);
+ let dir_path = prefix.push_many(mod_path.components);
let file_path = match ::attr::first_attr_value_str_by_name(
outer_attrs, "path") {
Some(d) => {
let path = Path(d);
if !path.is_absolute {
- mod_path.push(d)
+ dir_path.push(d)
} else {
path
}
}
- None => mod_path.push(token::interner_get(id.name) + ".rs") // default
+ None => {
+ let mod_name = token::interner_get(id.name).to_owned();
+ let default_path_str = mod_name + ".rs";
+ let secondary_path_str = mod_name + "/mod.rs";
+ let default_path = dir_path.push(default_path_str);
+ let secondary_path = dir_path.push(secondary_path_str);
+ let default_exists = default_path.exists();
+ let secondary_exists = secondary_path.exists();
+ match (default_exists, secondary_exists) {
+ (true, false) => default_path,
+ (false, true) => secondary_path,
+ (false, false) => {
+ self.span_fatal(id_sp, fmt!("file not found for module `%s`", mod_name));
+ }
+ (true, true) => {
+ self.span_fatal(id_sp,
+ fmt!("file for module `%s` found at both %s and %s",
+ mod_name, default_path_str, secondary_path_str));
+ }
+ }
+ }
};
- self.eval_src_mod_from_path(prefix,
- file_path,
+ self.eval_src_mod_from_path(file_path,
outer_attrs.to_owned(),
id_sp)
}
fn eval_src_mod_from_path(&self,
- prefix: Path,
path: Path,
outer_attrs: ~[ast::Attribute],
id_sp: span) -> (ast::item_, ~[ast::Attribute]) {
-
- let full_path = if path.is_absolute {
- path
- } else {
- prefix.push_many(path.components)
- };
- let full_path = full_path.normalize();
+ let full_path = path.normalize();
let maybe_i = do self.sess.included_mod_stack.iter().position |p| { *p == full_path };
match maybe_i {
// Parses a source module as a crate. This is the main
// entry point for the parser.
- pub fn parse_crate_mod(&self) -> @crate {
+ pub fn parse_crate_mod(&self) -> @Crate {
let lo = self.span.lo;
// parse the crate's inner attrs, maybe (oops) one
// of the attrs of an item:
let first_item_outer_attrs = next;
// parse the items inside the crate:
let m = self.parse_mod_items(token::EOF, first_item_outer_attrs);
- @spanned(lo, self.span.lo,
- ast::crate_ { module: m,
- attrs: inner,
- config: self.cfg.clone() })
+
+ @ast::Crate {
+ module: m,
+ attrs: inner,
+ config: self.cfg.clone(),
+ span: mk_sp(lo, self.span.lo)
+ }
}
pub fn parse_str(&self) -> @str {
/// For interpolation during macro expansion.
pub enum nonterminal {
nt_item(@ast::item),
- nt_block(ast::blk),
+ nt_block(ast::Block),
nt_stmt(@ast::stmt),
nt_pat( @ast::pat),
nt_expr(@ast::expr),
// if an interner exists in TLS, return it. Otherwise, prepare a
// fresh one.
pub fn get_ident_interner() -> @ident_interner {
- #[cfg(not(stage0))]
static key: local_data::Key<@@::parse::token::ident_interner> =
&local_data::Key;
- #[cfg(stage0)]
- fn key(_: @@::parse::token::ident_interner) {}
match local_data::get(key, |k| k.map(|&k| *k)) {
Some(interner) => *interner,
None => {
// The @ps is stored here to prevent recursive type.
pub enum ann_node<'self> {
- node_block(@ps, &'self ast::blk),
+ node_block(@ps, &'self ast::Block),
node_item(@ps, &'self ast::item),
node_expr(@ps, &'self ast::expr),
node_pat(@ps, &'self ast::pat),
pub fn print_crate(cm: @CodeMap,
intr: @ident_interner,
span_diagnostic: @diagnostic::span_handler,
- crate: &ast::crate,
+ crate: &ast::Crate,
filename: @str,
in: @io::Reader,
out: @io::Writer,
print_crate_(s, crate);
}
-pub fn print_crate_(s: @ps, crate: &ast::crate) {
- print_mod(s, &crate.node.module, crate.node.attrs);
+pub fn print_crate_(s: @ps, crate: &ast::Crate) {
+ print_mod(s, &crate.module, crate.attrs);
print_remaining_comments(s);
eof(s.s);
}
}
}
-pub fn block_to_str(blk: &ast::blk, intr: @ident_interner) -> ~str {
+pub fn block_to_str(blk: &ast::Block, intr: @ident_interner) -> ~str {
do io::with_str_writer |wr| {
let s = rust_printer(wr, intr);
// containing cbox, will be closed by print-block at }
match item.node {
ast::foreign_item_fn(ref decl, purity, ref generics) => {
print_fn(s, decl, Some(purity), AbiSet::Rust(), item.ident, generics, None,
- ast::inherited);
+ item.vis);
end(s); // end head-ibox
word(s.s, ";");
end(s); // end the outer fn box
}
ast::foreign_item_static(ref t, m) => {
- head(s, "static");
+ head(s, visibility_qualified(item.vis, "static"));
if m {
word_space(s, "mut");
}
maybe_print_trailing_comment(s, st.span, None);
}
-pub fn print_block(s: @ps, blk: &ast::blk) {
+pub fn print_block(s: @ps, blk: &ast::Block) {
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
}
-pub fn print_block_unclosed(s: @ps, blk: &ast::blk) {
+pub fn print_block_unclosed(s: @ps, blk: &ast::Block) {
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, &[],
false);
}
-pub fn print_block_unclosed_indent(s: @ps, blk: &ast::blk, indented: uint) {
+pub fn print_block_unclosed_indent(s: @ps, blk: &ast::Block, indented: uint) {
print_possibly_embedded_block_(s, blk, block_normal, indented, &[],
false);
}
pub fn print_block_with_attrs(s: @ps,
- blk: &ast::blk,
+ blk: &ast::Block,
attrs: &[ast::Attribute]) {
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs,
true);
pub enum embed_type { block_block_fn, block_normal, }
pub fn print_possibly_embedded_block(s: @ps,
- blk: &ast::blk,
+ blk: &ast::Block,
embedded: embed_type,
indented: uint) {
print_possibly_embedded_block_(
}
pub fn print_possibly_embedded_block_(s: @ps,
- blk: &ast::blk,
+ blk: &ast::Block,
embedded: embed_type,
indented: uint,
attrs: &[ast::Attribute],
(s.ann.post)(ann_node);
}
-pub fn print_if(s: @ps, test: &ast::expr, blk: &ast::blk,
+pub fn print_if(s: @ps, test: &ast::expr, blk: &ast::Block,
elseopt: Option<@ast::expr>, chk: bool) {
head(s, "if");
if chk { word_nbsp(s, "check"); }
}
pub fn print_expr(s: @ps, expr: &ast::expr) {
- fn print_field(s: @ps, field: &ast::field) {
+ fn print_field(s: @ps, field: &ast::Field) {
ibox(s, indent_unit);
- print_ident(s, field.node.ident);
+ print_ident(s, field.ident);
word_space(s, ":");
- print_expr(s, field.node.expr);
+ print_expr(s, field.expr);
end(s);
}
- fn get_span(field: &ast::field) -> codemap::span { return field.span; }
+ fn get_span(field: &ast::Field) -> codemap::span { return field.span; }
maybe_print_comment(s, expr.span.lo);
ibox(s, indent_unit);
end(s);
}
-pub fn print_local_decl(s: @ps, loc: &ast::local) {
- print_pat(s, loc.node.pat);
- match loc.node.ty.node {
+pub fn print_local_decl(s: @ps, loc: &ast::Local) {
+ print_pat(s, loc.pat);
+ match loc.ty.node {
ast::ty_infer => (),
- _ => { word_space(s, ":"); print_type(s, &loc.node.ty); }
+ _ => { word_space(s, ":"); print_type(s, &loc.ty); }
}
}
ibox(s, indent_unit);
word_nbsp(s, "let");
- if loc.node.is_mutbl {
+ if loc.is_mutbl {
word_nbsp(s, "mut");
}
- fn print_local(s: @ps, loc: &ast::local) {
+ fn print_local(s: @ps, loc: &ast::Local) {
ibox(s, indent_unit);
print_local_decl(s, loc);
end(s);
- match loc.node.init {
+ match loc.init {
Some(init) => {
nbsp(s);
word_space(s, "=");
word(s.s, ident_to_str(&ident));
}
-pub fn print_for_decl(s: @ps, loc: &ast::local, coll: &ast::expr) {
+pub fn print_for_decl(s: @ps, loc: &ast::Local, coll: &ast::expr) {
print_local_decl(s, loc);
space(s.s);
word_space(s, "in");
p
}
-pub fn string_to_crate (source_str : @str) -> @ast::crate {
+pub fn string_to_crate (source_str : @str) -> @ast::Crate {
string_to_parser(source_str).parse_crate_mod()
}
visit_view_item: @fn(&view_item, (E, vt<E>)),
visit_foreign_item: @fn(@foreign_item, (E, vt<E>)),
visit_item: @fn(@item, (E, vt<E>)),
- visit_local: @fn(@local, (E, vt<E>)),
- visit_block: @fn(&blk, (E, vt<E>)),
+ visit_local: @fn(@Local, (E, vt<E>)),
+ visit_block: @fn(&Block, (E, vt<E>)),
visit_stmt: @fn(@stmt, (E, vt<E>)),
visit_arm: @fn(&arm, (E, vt<E>)),
visit_pat: @fn(@pat, (E, vt<E>)),
visit_expr_post: @fn(@expr, (E, vt<E>)),
visit_ty: @fn(&Ty, (E, vt<E>)),
visit_generics: @fn(&Generics, (E, vt<E>)),
- visit_fn: @fn(&fn_kind, &fn_decl, &blk, span, node_id, (E, vt<E>)),
+ visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, node_id, (E, vt<E>)),
visit_ty_method: @fn(&ty_method, (E, vt<E>)),
visit_trait_method: @fn(&trait_method, (E, vt<E>)),
visit_struct_def: @fn(@struct_def, ident, &Generics, node_id, (E, vt<E>)),
};
}
-pub fn visit_crate<E:Clone>(c: &crate, (e, v): (E, vt<E>)) {
- (v.visit_mod)(&c.node.module, c.span, crate_node_id, (e, v));
+pub fn visit_crate<E:Clone>(c: &Crate, (e, v): (E, vt<E>)) {
+ (v.visit_mod)(&c.module, c.span, crate_node_id, (e, v));
}
pub fn visit_mod<E:Clone>(m: &_mod,
pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { }
-pub fn visit_local<E:Clone>(loc: &local, (e, v): (E, vt<E>)) {
- (v.visit_pat)(loc.node.pat, (e.clone(), v));
- (v.visit_ty)(&loc.node.ty, (e.clone(), v));
- match loc.node.init {
+pub fn visit_local<E:Clone>(loc: &Local, (e, v): (E, vt<E>)) {
+ (v.visit_pat)(loc.pat, (e.clone(), v));
+ (v.visit_ty)(&loc.ty, (e.clone(), v));
+ match loc.init {
None => (),
Some(ex) => (v.visit_expr)(ex, (e, v))
}
(e, v));
}
-pub fn visit_fn<E:Clone>(fk: &fn_kind, decl: &fn_decl, body: &blk, _sp: span,
+pub fn visit_fn<E:Clone>(fk: &fn_kind, decl: &fn_decl, body: &Block, _sp: span,
_id: node_id, (e, v): (E, vt<E>)) {
visit_fn_decl(decl, (e.clone(), v));
let generics = generics_of_fn(fk);
(v.visit_ty)(&sf.node.ty, (e, v));
}
-pub fn visit_block<E:Clone>(b: &blk, (e, v): (E, vt<E>)) {
+pub fn visit_block<E:Clone>(b: &Block, (e, v): (E, vt<E>)) {
for b.view_items.iter().advance |vi| {
(v.visit_view_item)(vi, (e.clone(), v));
}
expr_struct(ref p, ref flds, base) => {
visit_path(p, (e.clone(), v));
for flds.iter().advance |f| {
- (v.visit_expr)(f.node.expr, (e.clone(), v));
+ (v.visit_expr)(f.expr, (e.clone(), v));
}
visit_expr_opt(base, (e.clone(), v));
}
visit_view_item: @fn(&view_item),
visit_foreign_item: @fn(@foreign_item),
visit_item: @fn(@item),
- visit_local: @fn(@local),
- visit_block: @fn(&blk),
+ visit_local: @fn(@Local),
+ visit_block: @fn(&Block),
visit_stmt: @fn(@stmt),
visit_arm: @fn(&arm),
visit_pat: @fn(@pat),
visit_expr_post: @fn(@expr),
visit_ty: @fn(&Ty),
visit_generics: @fn(&Generics),
- visit_fn: @fn(&fn_kind, &fn_decl, &blk, span, node_id),
+ visit_fn: @fn(&fn_kind, &fn_decl, &Block, span, node_id),
visit_ty_method: @fn(&ty_method),
visit_trait_method: @fn(&trait_method),
visit_struct_def: @fn(@struct_def, ident, &Generics, node_id),
f(i);
visit_item(i, (e, v));
}
- fn v_local(f: @fn(@local), l: @local, (e, v): ((), vt<()>)) {
+ fn v_local(f: @fn(@Local), l: @Local, (e, v): ((), vt<()>)) {
f(l);
visit_local(l, (e, v));
}
- fn v_block(f: @fn(&ast::blk), bl: &ast::blk, (e, v): ((), vt<()>)) {
+ fn v_block(f: @fn(&ast::Block), bl: &ast::Block, (e, v): ((), vt<()>)) {
f(bl);
visit_block(bl, (e, v));
}
visit_generics(ps, (e, v));
}
fn v_fn(
- f: @fn(&fn_kind, &fn_decl, &blk, span, node_id),
+ f: @fn(&fn_kind, &fn_decl, &Block, span, node_id),
fk: &fn_kind,
decl: &fn_decl,
- body: &blk,
+ body: &Block,
sp: span,
id: node_id,
(e, v): ((), vt<()>)
delete thread;
}
-extern "C" void
-rust_register_exit_function(spawn_fn runner, fn_env_pair *f) {
- rust_task *task = rust_get_current_task();
- task->kernel->register_exit_function(runner, f);
-}
-
-extern "C" intptr_t*
-rust_get_global_data_ptr() {
- rust_task *task = rust_get_current_task();
- return &task->kernel->global_data;
-}
-
-extern "C" void
-rust_inc_kernel_live_count() {
- rust_task *task = rust_get_current_task();
- task->kernel->inc_live_count();
-}
-
-extern "C" void
-rust_dec_kernel_live_count() {
- rust_task *task = rust_get_current_task();
- task->kernel->dec_live_count();
-}
-
#ifndef _WIN32
#include <sys/types.h>
#include <dirent.h>
return exit_status;
}
+static lock_and_signal change_dir_lock;
+
+extern "C" CDECL void
+rust_take_change_dir_lock() {
+ global_args_lock.lock();
+}
+
+extern "C" CDECL void
+rust_drop_change_dir_lock() {
+ global_args_lock.unlock();
+}
+
//
// Local Variables:
// mode: C++
sched_reaper(this),
osmain_driver(NULL),
non_weak_tasks(0),
- at_exit_runner(NULL),
- at_exit_started(false),
- env(env),
- global_data(0)
+ env(env)
{
// Create the single threaded scheduler that will run on the platform's
// main thread
}
}
- run_exit_functions();
allow_scheduler_exit();
}
-void
-rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) {
- scoped_lock with(at_exit_lock);
-
- assert(!at_exit_started && "registering at_exit function after exit");
-
- if (at_exit_runner) {
- // FIXME #2912 Would be very nice to assert this but we can't because
- // of the way coretest works (the test case ends up using its own
- // function)
- //assert(runner == at_exit_runner
- // && "there can be only one at_exit_runner");
- }
-
- at_exit_runner = runner;
- at_exit_fns.push_back(f);
-}
-
-void
-rust_kernel::run_exit_functions() {
- rust_task *task;
-
- {
- scoped_lock with(at_exit_lock);
-
- assert(!at_exit_started && "running exit functions twice?");
-
- at_exit_started = true;
-
- if (at_exit_runner == NULL) {
- return;
- }
-
- rust_scheduler *sched = get_scheduler_by_id(main_sched_id());
- assert(sched);
- task = sched->create_task(NULL, "at_exit");
-
- final_exit_fns.count = at_exit_fns.size();
- final_exit_fns.start = at_exit_fns.data();
- }
-
- task->start(at_exit_runner, NULL, &final_exit_fns);
-}
-
//
// Local Variables:
// mode: C++
typedef std::map<rust_sched_id, rust_scheduler*> sched_map;
-// This is defined as a struct only because we need a single pointer to pass
-// to the Rust function that runs the at_exit functions
-struct exit_functions {
- size_t count;
- fn_env_pair **start;
-};
-
class rust_kernel {
rust_exchange_alloc exchange_alloc;
rust_log _log;
void allow_scheduler_exit();
void begin_shutdown();
- lock_and_signal at_exit_lock;
- spawn_fn at_exit_runner;
- bool at_exit_started;
- std::vector<fn_env_pair*> at_exit_fns;
- exit_functions final_exit_fns;
-
- void run_exit_functions();
-
public:
struct rust_env *env;
- intptr_t global_data;
rust_kernel(rust_env *env);
void inc_live_count();
void dec_live_count();
- void register_exit_function(spawn_fn runner, fn_env_pair *f);
};
template <typename T> struct kernel_owned {
// free the environment (which should be a unique closure).
const type_desc *td = env->td;
td->drop_glue(NULL,
-#ifdef _RUST_STAGE0
- NULL,
-#endif
box_body(env));
task->kernel->region()->free(env);
}
struct type_desc;
typedef void CDECL (glue_fn)(void *,
-#ifdef _RUST_STAGE0
- const type_desc **,
-#endif
void *);
// Corresponds to the boxed data in the @ region. The body follows the
linenoiseHistoryLoad
rust_raw_thread_start
rust_raw_thread_join_delete
-rust_register_exit_function
-rust_get_global_data_ptr
-rust_inc_kernel_live_count
-rust_dec_kernel_live_count
rust_get_rt_tls_key
swap_registers
rust_readdir
rust_drop_global_args_lock
rust_set_exit_status_newrt
rust_get_exit_status_newrt
+rust_take_change_dir_lock
+rust_drop_change_dir_lock
\ No newline at end of file
LLVMInsertBasicBlockInContext
LLVMInsertIntoBuilder
LLVMInsertIntoBuilderWithName
+LLVMInstructionEraseFromParent
LLVMInt16Type
LLVMInt16TypeInContext
LLVMInt1Type
+S 2013-07-21 e336cbf
+ macos-i386 d9666dccc1040ebe298a54acb378902a7472ad0f
+ macos-x86_64 808f68916444e3857ef2aab20f8db9db8f4b0b4a
+ winnt-i386 f9a5f891fd24e9446acb2a1b5d697461665c4388
+ freebsd-x86_64 8e79f6e970bc33ea6a3b9329bc4526d89ca63d47
+ linux-i386 054a0229b9cbdadf013868ba01a8277883f83a6d
+ linux-x86_64 2c53a72e9c9bb547df248a2d4b857d480ce0b910
+
S 2013-06-23 f827561
macos-i386 63ffbcf99b6853d7840bdfe01380068518d0e466
macos-x86_64 b34fdf3845f8ef4760817007d8ef820cd32f2e07
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// error-pattern:error opening
-
-mod doesnotexist;
\ No newline at end of file
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` found at both
+
+fn main() {
+ assert_eq!(mod_file_aux::bar(), 10);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-test not a test. aux file
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-test not a test. aux file
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-mod not_a_real_file; //~ ERROR not_a_real_file.rs
+mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file`
fn main() {
assert_eq!(mod_file_aux::bar(), 10);
trait fake_ext_ctxt {
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parse::parse_sess;
fn call_site() -> span;
fn ident_of(st: &str) -> ast::ident;
type fake_session = parse::parse_sess;
impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::crate_cfg { ~[] }
+ fn cfg() -> ast::Crate_cfg { ~[] }
fn parse_sess() -> parse::parse_sess { self }
fn call_site() -> span {
codemap::span {
use syntax::print::*;
trait fake_ext_ctxt {
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parse::parse_sess;
fn call_site() -> span;
fn ident_of(st: &str) -> ast::ident;
type fake_session = parse::parse_sess;
impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::crate_cfg { ~[] }
+ fn cfg() -> ast::Crate_cfg { ~[] }
fn parse_sess() -> parse::parse_sess { self }
fn call_site() -> span {
codemap::span {
trait fake_ext_ctxt {
fn session() -> fake_session;
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parser::parse_sess;
}
-type fake_options = {cfg: ast::crate_cfg};
+type fake_options = {cfg: ast::Crate_cfg};
type fake_session = {opts: @fake_options,
parse_sess: parser::parse_sess};
impl of fake_ext_ctxt for fake_session {
fn session() -> fake_session {self}
- fn cfg() -> ast::crate_cfg { self.opts.cfg }
+ fn cfg() -> ast::Crate_cfg { self.opts.cfg }
fn parse_sess() -> parser::parse_sess { self.parse_sess }
}
trait fake_ext_ctxt {
- fn cfg() -> ast::crate_cfg;
+ fn cfg() -> ast::Crate_cfg;
fn parse_sess() -> parse::parse_sess;
fn call_site() -> span;
fn ident_of(st: &str) -> ast::ident;
type fake_session = parse::parse_sess;
impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::crate_cfg { ~[] }
+ fn cfg() -> ast::Crate_cfg { ~[] }
fn parse_sess() -> parse::parse_sess { self }
fn call_site() -> span {
codemap::span {
// except according to those terms.
// xfail-fast
+// xfail-test needs networking
extern mod extra;
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-pretty
+// xfail-fast
+
+mod mod_dir_implicit_aux;
+
+pub fn main() {
+ assert_eq!(mod_dir_implicit_aux::foo(), 10);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn foo() -> int { 10 }
// Make sure that we can detect when one end of the pipe is closed.
// xfail-win32
+// xfail-test needs sleep
extern mod extra;
use extra::timer::sleep;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-extern mod extra;
-use extra::timer::sleep;
-use extra::uv;
use std::pipes;
proto! oneshot (
// xfail-pretty
// xfail-win32
+// xfail-test needs sleep
extern mod extra;
use extra::timer::sleep;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test needs sleep
+
extern mod extra;
use extra::timer::sleep;