diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index b35904dbdae..57d6c46d9f3 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -54,18 +54,6 @@ pub fn each_lang_item(cstore: @mut cstore::CStore, } /// Iterates over all the paths in the given crate. -#[cfg(stage0)] -pub fn each_path(cstore: @mut cstore::CStore, - cnum: ast::crate_num, - f: &fn(&str, decoder::def_like, ast::visibility) -> bool) { - let crate_data = cstore::get_crate_data(cstore, cnum); - let get_crate_data: decoder::GetCrateDataCb = |cnum| { - cstore::get_crate_data(cstore, cnum) - }; - decoder::each_path(cstore.intr, crate_data, get_crate_data, f) -} -/// Iterates over all the paths in the given crate. -#[cfg(not(stage0))] pub fn each_path(cstore: @mut cstore::CStore, cnum: ast::crate_num, f: &fn(&str, decoder::def_like, ast::visibility) -> bool) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index de44b74528d..2cc0382269e 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -566,14 +566,6 @@ pub fn _each_path(intr: @ident_interner, return broken; } -#[cfg(stage0)] -pub fn each_path(intr: @ident_interner, - cdata: cmd, - get_crate_data: GetCrateDataCb, - f: &fn(&str, def_like, ast::visibility) -> bool) { - _each_path(intr, cdata, get_crate_data, f); -} -#[cfg(not(stage0))] pub fn each_path(intr: @ident_interner, cdata: cmd, get_crate_data: GetCrateDataCb, diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index f91fdfe232c..f7b30e22f01 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -11,6 +11,8 @@ //! This module implements the check that the lifetime of a borrow //! does not exceed the lifetime of the value being borrowed. +use core::prelude::*; + use middle::borrowck::*; use mc = middle::mem_categorization; use middle::ty; diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 3d2c318a87e..a422d99b6f5 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -16,6 +16,8 @@ // their associated scopes. In phase two, checking loans, we will then make // sure that all of these loans are honored. +use core::prelude::*; + use middle::borrowck::*; use mc = middle::mem_categorization; use middle::pat_util; diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index ff6ad87846c..42b1c40a4b3 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -10,6 +10,8 @@ //! Computes the restrictions that result from a borrow. +use core::prelude::*; + use middle::borrowck::*; use mc = middle::mem_categorization; use middle::ty; diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index bc3db4602b0..39479e726f8 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -10,6 +10,8 @@ /*! See doc.rs for a thorough explanation of the borrow checker */ +use core::prelude::*; + use mc = middle::mem_categorization; use middle::ty; use middle::typeck; diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index b2ef0c46afb..6a6746ab20b 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -22,6 +22,7 @@ use middle::lint::unused_imports; use middle::pat_util::pat_bindings; use syntax::ast::*; +use syntax::ast; use syntax::ast_util::{def_id_of_def, local_def}; use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; use syntax::ast_util::{Privacy, Public, Private}; diff --git a/src/libcore/rt/comm.rs b/src/libstd/rt/comm.rs similarity index 100% rename from src/libcore/rt/comm.rs rename to src/libstd/rt/comm.rs diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs new file mode 100644 index 00000000000..ce7ff87b445 --- /dev/null +++ b/src/libstd/rt/global_heap.rs @@ -0,0 +1,87 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys::{TypeDesc, size_of}; +use libc::{c_void, size_t, uintptr_t}; +use c_malloc = libc::malloc; +use c_free = libc::free; +use managed::raw::{BoxHeaderRepr, BoxRepr}; +use cast::transmute; +use unstable::intrinsics::{atomic_xadd,atomic_xsub}; +use ptr::null; +use intrinsic::TyDesc; + +pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { + assert!(td.is_not_null()); + + let total_size = get_box_size(size, (*td).align); + let p = c_malloc(total_size as size_t); + assert!(p.is_not_null()); + + // FIXME #3475: Converting between our two different tydesc types + let td: *TyDesc = transmute(td); + + let box: &mut BoxRepr = transmute(p); + box.header.ref_count = -1; // Exchange values not ref counted + box.header.type_desc = td; + box.header.prev = null(); + box.header.next = null(); + + let exchange_count = &mut *exchange_count_ptr(); + atomic_xadd(exchange_count, 1); + + return transmute(box); +} +/** +Thin wrapper around libc::malloc, none of the box header +stuff in exchange_alloc::malloc +*/ +pub unsafe fn malloc_raw(size: uint) -> *c_void { + let p = c_malloc(size as size_t); + if p.is_null() { + fail!("Failure in malloc_raw: result ptr is null"); + } + p +} + +pub unsafe fn free(ptr: *c_void) { + let exchange_count = &mut *exchange_count_ptr(); + atomic_xsub(exchange_count, 1); + + assert!(ptr.is_not_null()); + c_free(ptr); +} +///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw +pub unsafe fn free_raw(ptr: *c_void) { + c_free(ptr); +} + +fn get_box_size(body_size: uint, body_align: uint) -> uint { + let header_size = size_of::(); + // FIXME (#2699): This alignment calculation is suspicious. Is it right? + let total_size = align_to(header_size, body_align) + body_size; + return total_size; +} + +// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power +// of two. +fn align_to(size: uint, align: uint) -> uint { + assert!(align != 0); + (size + align - 1) & !(align - 1) +} + +fn exchange_count_ptr() -> *mut int { + // XXX: Need mutable globals + unsafe { transmute(&rust_exchange_count) } +} + +extern { + static rust_exchange_count: uintptr_t; +} diff --git a/src/libcore/rt/io/mock.rs b/src/libstd/rt/io/mock.rs similarity index 100% rename from src/libcore/rt/io/mock.rs rename to src/libstd/rt/io/mock.rs diff --git a/src/libcore/rt/local.rs b/src/libstd/rt/local.rs similarity index 100% rename from src/libcore/rt/local.rs rename to src/libstd/rt/local.rs diff --git a/src/libcore/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs similarity index 100% rename from src/libcore/rt/local_ptr.rs rename to src/libstd/rt/local_ptr.rs diff --git a/src/libcore/rt/logging.rs b/src/libstd/rt/logging.rs similarity index 100% rename from src/libcore/rt/logging.rs rename to src/libstd/rt/logging.rs diff --git a/src/libcore/rt/message_queue.rs b/src/libstd/rt/message_queue.rs similarity index 100% rename from src/libcore/rt/message_queue.rs rename to src/libstd/rt/message_queue.rs diff --git a/src/libcore/rt/rc.rs b/src/libstd/rt/rc.rs similarity index 100% rename from src/libcore/rt/rc.rs rename to src/libstd/rt/rc.rs diff --git a/src/libcore/rt/sched.rs b/src/libstd/rt/sched.rs similarity index 100% rename from src/libcore/rt/sched.rs rename to src/libstd/rt/sched.rs diff --git a/src/libcore/rt/tube.rs b/src/libstd/rt/tube.rs similarity index 100% rename from src/libcore/rt/tube.rs rename to src/libstd/rt/tube.rs diff --git a/src/libcore/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs similarity index 100% rename from src/libcore/rt/uv/idle.rs rename to src/libstd/rt/uv/idle.rs diff --git a/src/libcore/rt/uv/timer.rs b/src/libstd/rt/uv/timer.rs similarity index 100% rename from src/libcore/rt/uv/timer.rs rename to src/libstd/rt/uv/timer.rs diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs new file mode 100644 index 00000000000..cacd67314eb --- /dev/null +++ b/src/libstd/rt/uv/uvio.rs @@ -0,0 +1,492 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use option::*; +use result::*; +use ops::Drop; +use cell::{Cell, empty_cell}; +use cast::transmute; +use clone::Clone; +use rt::io::IoError; +use rt::io::net::ip::IpAddr; +use rt::uv::*; +use rt::uv::idle::IdleWatcher; +use rt::rtio::*; +use rt::sched::Scheduler; +use rt::io::{standard_error, OtherIoError}; +use rt::tube::Tube; +use rt::local::Local; + +#[cfg(test)] use container::Container; +#[cfg(test)] use uint; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use rt::test::*; + +pub struct UvEventLoop { + uvio: UvIoFactory +} + +pub impl UvEventLoop { + fn new() -> UvEventLoop { + UvEventLoop { + uvio: UvIoFactory(Loop::new()) + } + } + + /// A convenience constructor + fn new_scheduler() -> Scheduler { + Scheduler::new(~UvEventLoop::new()) + } +} + +impl Drop for UvEventLoop { + fn finalize(&self) { + // XXX: Need mutable finalizer + let this = unsafe { + transmute::<&UvEventLoop, &mut UvEventLoop>(self) + }; + this.uvio.uv_loop().close(); + } +} + +impl EventLoop for UvEventLoop { + + fn run(&mut self) { + self.uvio.uv_loop().run(); + } + + fn callback(&mut self, f: ~fn()) { + let mut idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); + do idle_watcher.start |idle_watcher, status| { + assert!(status.is_none()); + let mut idle_watcher = idle_watcher; + idle_watcher.stop(); + idle_watcher.close(||()); + f(); + } + } + + fn callback_ms(&mut self, ms: u64, f: ~fn()) { + let mut timer = TimerWatcher::new(self.uvio.uv_loop()); + do timer.start(ms, 0) |timer, status| { + assert!(status.is_none()); + timer.close(||()); + f(); + } + } + + fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { + Some(&mut self.uvio) + } +} + +#[test] +fn test_callback_run_once() { + do run_in_bare_thread { + let mut event_loop = UvEventLoop::new(); + let mut count = 0; + let count_ptr: *mut int = &mut count; + do event_loop.callback { + unsafe { *count_ptr += 1 } + } + event_loop.run(); + assert_eq!(count, 1); + } +} + +pub struct UvIoFactory(Loop); + +pub impl UvIoFactory { + fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { + match self { &UvIoFactory(ref mut ptr) => ptr } + } +} + +impl IoFactory for UvIoFactory { + // Connect to an address and return a new stream + // NB: This blocks the task waiting on the connection. + // It would probably be better to return a future + fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError> { + // Create a cell in the task to hold the result. We will fill + // the cell before resuming the task. + let result_cell = empty_cell(); + let result_cell_ptr: *Cell> = &result_cell; + + let scheduler = Local::take::(); + assert!(scheduler.in_task_context()); + + // Block this task and take ownership, switch to scheduler context + do scheduler.deschedule_running_task_and_then |task| { + + rtdebug!("connect: entered scheduler context"); + do Local::borrow:: |scheduler| { + assert!(!scheduler.in_task_context()); + } + let mut tcp_watcher = TcpWatcher::new(self.uv_loop()); + let task_cell = Cell(task); + + // Wait for a connection + do tcp_watcher.connect(addr) |stream_watcher, status| { + rtdebug!("connect: in connect callback"); + if status.is_none() { + rtdebug!("status is none"); + let res = Ok(~UvTcpStream { watcher: stream_watcher }); + + // Store the stream in the task's stack + unsafe { (*result_cell_ptr).put_back(res); } + + // Context switch + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } else { + rtdebug!("status is some"); + let task_cell = Cell(task_cell.take()); + do stream_watcher.close { + let res = Err(uv_error_to_io_error(status.get())); + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + }; + } + } + + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + + fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError> { + let mut watcher = TcpWatcher::new(self.uv_loop()); + match watcher.bind(addr) { + Ok(_) => Ok(~UvTcpListener::new(watcher)), + Err(uverr) => { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |task| { + let task_cell = Cell(task); + do watcher.as_stream().close { + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + Err(uv_error_to_io_error(uverr)) + } + } + } +} + +// FIXME #6090: Prefer newtype structs but Drop doesn't work +pub struct UvTcpListener { + watcher: TcpWatcher, + listening: bool, + incoming_streams: Tube> +} + +impl UvTcpListener { + fn new(watcher: TcpWatcher) -> UvTcpListener { + UvTcpListener { + watcher: watcher, + listening: false, + incoming_streams: Tube::new() + } + } + + fn watcher(&self) -> TcpWatcher { self.watcher } +} + +impl Drop for UvTcpListener { + fn finalize(&self) { + let watcher = self.watcher(); + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |task| { + let task_cell = Cell(task); + do watcher.as_stream().close { + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + } +} + +impl RtioTcpListener for UvTcpListener { + + fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { + rtdebug!("entering listen"); + + if self.listening { + return self.incoming_streams.recv(); + } + + self.listening = true; + + let server_tcp_watcher = self.watcher(); + let incoming_streams_cell = Cell(self.incoming_streams.clone()); + + let incoming_streams_cell = Cell(incoming_streams_cell.take()); + let mut server_tcp_watcher = server_tcp_watcher; + do server_tcp_watcher.listen |server_stream_watcher, status| { + let maybe_stream = if status.is_none() { + let mut server_stream_watcher = server_stream_watcher; + let mut loop_ = server_stream_watcher.event_loop(); + let client_tcp_watcher = TcpWatcher::new(&mut loop_); + let client_tcp_watcher = client_tcp_watcher.as_stream(); + // XXX: Need's to be surfaced in interface + server_stream_watcher.accept(client_tcp_watcher); + Ok(~UvTcpStream { watcher: client_tcp_watcher }) + } else { + Err(standard_error(OtherIoError)) + }; + + let mut incoming_streams = incoming_streams_cell.take(); + incoming_streams.send(maybe_stream); + incoming_streams_cell.put_back(incoming_streams); + } + + return self.incoming_streams.recv(); + } +} + +// FIXME #6090: Prefer newtype structs but Drop doesn't work +pub struct UvTcpStream { + watcher: StreamWatcher +} + +impl UvTcpStream { + fn watcher(&self) -> StreamWatcher { self.watcher } +} + +impl Drop for UvTcpStream { + fn finalize(&self) { + rtdebug!("closing tcp stream"); + let watcher = self.watcher(); + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |task| { + let task_cell = Cell(task); + do watcher.close { + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + } +} + +impl RtioTcpStream for UvTcpStream { + fn read(&mut self, buf: &mut [u8]) -> Result { + let result_cell = empty_cell(); + let result_cell_ptr: *Cell> = &result_cell; + + let scheduler = Local::take::(); + assert!(scheduler.in_task_context()); + let watcher = self.watcher(); + let buf_ptr: *&mut [u8] = &buf; + do scheduler.deschedule_running_task_and_then |task| { + rtdebug!("read: entered scheduler context"); + do Local::borrow:: |scheduler| { + assert!(!scheduler.in_task_context()); + } + let mut watcher = watcher; + let task_cell = Cell(task); + // XXX: We shouldn't reallocate these callbacks every + // call to read + let alloc: AllocCallback = |_| unsafe { + slice_to_uv_buf(*buf_ptr) + }; + do watcher.read_start(alloc) |watcher, nread, _buf, status| { + + // Stop reading so that no read callbacks are + // triggered before the user calls `read` again. + // XXX: Is there a performance impact to calling + // stop here? + let mut watcher = watcher; + watcher.read_stop(); + + let result = if status.is_none() { + assert!(nread >= 0); + Ok(nread as uint) + } else { + Err(uv_error_to_io_error(status.unwrap())) + }; + + unsafe { (*result_cell_ptr).put_back(result); } + + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + + fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + let result_cell = empty_cell(); + let result_cell_ptr: *Cell> = &result_cell; + let scheduler = Local::take::(); + assert!(scheduler.in_task_context()); + let watcher = self.watcher(); + let buf_ptr: *&[u8] = &buf; + do scheduler.deschedule_running_task_and_then |task| { + let mut watcher = watcher; + let task_cell = Cell(task); + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + do watcher.write(buf) |_watcher, status| { + let result = if status.is_none() { + Ok(()) + } else { + Err(uv_error_to_io_error(status.unwrap())) + }; + + unsafe { (*result_cell_ptr).put_back(result); } + + let scheduler = Local::take::(); + scheduler.resume_task_immediately(task_cell.take()); + } + } + + assert!(!result_cell.is_empty()); + return result_cell.take(); + } +} + +#[test] +fn test_simple_io_no_connect() { + do run_in_newsched_task { + unsafe { + let io = Local::unsafe_borrow::(); + let addr = next_test_ip4(); + let maybe_chan = (*io).tcp_connect(addr); + assert!(maybe_chan.is_err()); + } + } +} + +#[test] +fn test_simple_tcp_server_and_client() { + do run_in_newsched_task { + let addr = next_test_ip4(); + + // Start the server first so it's listening when we connect + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let mut listener = (*io).tcp_bind(addr).unwrap(); + let mut stream = listener.accept().unwrap(); + let mut buf = [0, .. 2048]; + let nread = stream.read(buf).unwrap(); + assert_eq!(nread, 8); + for uint::range(0, nread) |i| { + rtdebug!("%u", buf[i] as uint); + assert_eq!(buf[i], i as u8); + } + } + } + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let mut stream = (*io).tcp_connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + } + } + } +} + +#[test] #[ignore(reason = "busted")] +fn test_read_and_block() { + do run_in_newsched_task { + let addr = next_test_ip4(); + + do spawntask_immediately { + let io = unsafe { Local::unsafe_borrow::() }; + let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() }; + let mut stream = listener.accept().unwrap(); + let mut buf = [0, .. 2048]; + + let expected = 32; + let mut current = 0; + let mut reads = 0; + + while current < expected { + let nread = stream.read(buf).unwrap(); + for uint::range(0, nread) |i| { + let val = buf[i] as uint; + assert_eq!(val, current % 8); + current += 1; + } + reads += 1; + + let scheduler = Local::take::(); + // Yield to the other task in hopes that it + // will trigger a read callback while we are + // not ready for it + do scheduler.deschedule_running_task_and_then |task| { + let task = Cell(task); + do Local::borrow:: |scheduler| { + scheduler.enqueue_task(task.take()); + } + } + } + + // Make sure we had multiple reads + assert!(reads > 1); + } + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let mut stream = (*io).tcp_connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + } + } + + } +} + +#[test] +fn test_read_read_read() { + do run_in_newsched_task { + let addr = next_test_ip4(); + static MAX: uint = 500000; + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let mut listener = (*io).tcp_bind(addr).unwrap(); + let mut stream = listener.accept().unwrap(); + let buf = [1, .. 2048]; + let mut total_bytes_written = 0; + while total_bytes_written < MAX { + stream.write(buf); + total_bytes_written += buf.len(); + } + } + } + + do spawntask_immediately { + unsafe { + let io = Local::unsafe_borrow::(); + let mut stream = (*io).tcp_connect(addr).unwrap(); + let mut buf = [0, .. 2048]; + let mut total_bytes_read = 0; + while total_bytes_read < MAX { + let nread = stream.read(buf).unwrap(); + rtdebug!("read %u bytes", nread as uint); + total_bytes_read += nread; + for uint::range(0, nread) |i| { + assert_eq!(buf[i], 1); + } + } + rtdebug!("read %u bytes total", total_bytes_read as uint); + } + } + } +} diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs new file mode 100644 index 00000000000..ddc9040d730 --- /dev/null +++ b/src/libstd/rt/uv/uvll.rs @@ -0,0 +1,452 @@ +// 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 or the MIT license +// , 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. + * + * We're not bothering yet to redefine uv's structs as Rust structs + * because they are quite large and change often between versions. + * The maintenance burden is just too high. Instead we use the uv's + * `uv_handle_size` and `uv_req_size` to find the correct size of the + * structs and allocate them on the heap. This can be revisited later. + * + * There are also a collection of helper functions to ease interacting + * with the low-level API. + * + * As new functionality, existant in uv.h, is added to the rust stdlib, + * the mappings should be added in this module. + */ + +#[allow(non_camel_case_types)]; // C types + +use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t}; +use libc::{malloc, free}; +use prelude::*; + +pub static UNKNOWN: c_int = -1; +pub static OK: c_int = 0; +pub static EOF: c_int = 1; +pub static EADDRINFO: c_int = 2; +pub static EACCES: c_int = 3; +pub static ECONNREFUSED: c_int = 12; +pub static ECONNRESET: c_int = 13; +pub static EPIPE: c_int = 36; + +pub struct uv_err_t { + code: c_int, + sys_errno_: c_int +} + +pub struct uv_buf_t { + base: *u8, + len: libc::size_t, +} + +pub type uv_handle_t = c_void; +pub type uv_loop_t = c_void; +pub type uv_idle_t = c_void; +pub type uv_tcp_t = c_void; +pub type uv_connect_t = c_void; +pub type uv_write_t = c_void; +pub type uv_async_t = c_void; +pub type uv_timer_t = c_void; +pub type uv_stream_t = c_void; +pub type uv_fs_t = c_void; + +pub type uv_idle_cb = *u8; + +pub type sockaddr_in = c_void; +pub type sockaddr_in6 = c_void; + +#[deriving(Eq)] +pub enum uv_handle_type { + UV_UNKNOWN_HANDLE, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX +} + +#[deriving(Eq)] +pub enum uv_req_type { + UV_UNKNOWN_REQ, + UV_REQ, + UV_CONNECT, + UV_WRITE, + UV_SHUTDOWN, + UV_UDP_SEND, + UV_FS, + UV_WORK, + UV_GETADDRINFO, + UV_REQ_TYPE_MAX +} + +pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void { + assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX); + let size = rust_uv_handle_size(handle as uint); + let p = malloc(size); + assert!(p.is_not_null()); + return p; +} + +pub unsafe fn free_handle(v: *c_void) { + free(v) +} + +pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { + assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX); + let size = rust_uv_req_size(req as uint); + let p = malloc(size); + assert!(p.is_not_null()); + return p; +} + +pub unsafe fn free_req(v: *c_void) { + free(v) +} + +#[test] +fn handle_sanity_check() { + unsafe { + assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max()); + } +} + +#[test] +fn request_sanity_check() { + unsafe { + assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max()); + } +} + +pub unsafe fn loop_new() -> *c_void { + return rust_uv_loop_new(); +} + +pub unsafe fn loop_delete(loop_handle: *c_void) { + rust_uv_loop_delete(loop_handle); +} + +pub unsafe fn run(loop_handle: *c_void) { + rust_uv_run(loop_handle); +} + +pub unsafe fn close(handle: *T, cb: *u8) { + rust_uv_close(handle as *c_void, cb); +} + +pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *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) -> c_int { + rust_uv_idle_init(loop_handle, handle) +} + +pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int { + rust_uv_idle_start(handle, cb) +} + +pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int { + rust_uv_idle_stop(handle) +} + +pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) ->c_int { + return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); +} + +pub unsafe fn listen(stream: *T, backlog: c_int, cb: *u8) -> c_int { + return rust_uv_listen(stream as *c_void, backlog, cb); +} + +pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { + return rust_uv_accept(server as *c_void, client as *c_void); +} + +pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> 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 *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); +} +pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { + return rust_uv_read_start(stream as *c_void, on_alloc, on_read); +} + +pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int { + return rust_uv_read_stop(stream as *c_void); +} + +pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t { + return rust_uv_last_error(loop_handle); +} + +pub unsafe fn strerror(err: *uv_err_t) -> *c_char { + return rust_uv_strerror(err); +} +pub unsafe fn err_name(err: *uv_err_t) -> *c_char { + return rust_uv_err_name(err); +} + +pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> 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 size_t }; + let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf); + rust_uv_buf_init(out_buf_ptr, input, len as size_t); + return out_buf; +} + +pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int { + return rust_uv_timer_init(loop_ptr, timer_ptr); +} +pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64, + repeat: u64) -> c_int { + return rust_uv_timer_start(timer_ptr, cb, timeout, repeat); +} +pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int { + return rust_uv_timer_stop(timer_ptr); +} + +pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in { + do str::as_c_str(ip) |ip_buf| { + rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) + } +} +pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 { + do str::as_c_str(ip) |ip_buf| { + rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int) + } +} + +pub unsafe fn free_ip4_addr(addr: *sockaddr_in) { + rust_uv_free_ip4_addr(addr); +} + +pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) { + rust_uv_free_ip6_addr(addr); +} + +// data access helpers +pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *c_void { + return rust_uv_get_loop_for_uv_handle(handle as *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: *c_void) -> *c_void { + rust_uv_get_data_for_uv_loop(loop_ptr) +} +pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) { + rust_uv_set_data_for_uv_loop(loop_ptr, data); +} +pub unsafe fn get_data_for_uv_handle(handle: *T) -> *c_void { + return rust_uv_get_data_for_uv_handle(handle as *c_void); +} +pub unsafe fn set_data_for_uv_handle(handle: *T, data: *U) { + rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void); +} +pub unsafe fn get_data_for_req(req: *T) -> *c_void { + return rust_uv_get_data_for_req(req as *c_void); +} +pub unsafe fn set_data_for_req(req: *T, data: *U) { + rust_uv_set_data_for_req(req as *c_void, data as *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) -> size_t { + return rust_uv_get_len_from_buf(buf); +} +pub unsafe fn malloc_buf_base_of(suggested_size: 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: *c_void) -> ~str { + let err = last_error(uv_loop); + let err_ptr = ptr::to_unsafe_ptr(&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: *c_void) -> uv_err_data { + let err = last_error(uv_loop); + let err_ptr = ptr::to_unsafe_ptr(&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, +} + +extern { + + fn rust_uv_handle_size(type_: uintptr_t) -> size_t; + fn rust_uv_req_size(type_: uintptr_t) -> size_t; + fn rust_uv_handle_type_max() -> uintptr_t; + fn rust_uv_req_type_max() -> uintptr_t; + + // libuv public API + fn rust_uv_loop_new() -> *c_void; + fn rust_uv_loop_delete(lp: *c_void); + fn rust_uv_run(loop_handle: *c_void); + fn rust_uv_close(handle: *c_void, cb: *u8); + fn rust_uv_walk(loop_handle: *c_void, cb: *u8, arg: *c_void); + + fn rust_uv_idle_new() -> *uv_idle_t; + fn rust_uv_idle_delete(handle: *uv_idle_t); + fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; + fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; + fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; + + fn rust_uv_async_send(handle: *uv_async_t); + fn rust_uv_async_init(loop_handle: *c_void, + async_handle: *uv_async_t, + cb: *u8) -> c_int; + fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int; + // FIXME ref #2604 .. ? + fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t); + fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t; + // FIXME ref #2064 + fn rust_uv_strerror(err: *uv_err_t) -> *c_char; + // FIXME ref #2064 + fn rust_uv_err_name(err: *uv_err_t) -> *c_char; + fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in; + fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6; + fn rust_uv_free_ip4_addr(addr: *sockaddr_in); + fn rust_uv_free_ip6_addr(addr: *sockaddr_in6); + fn rust_uv_ip4_name(src: *sockaddr_in, dst: *u8, size: size_t) -> c_int; + fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int; + fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint; + fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint; + // FIXME ref #2064 + fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, + tcp_handle_ptr: *uv_tcp_t, + after_cb: *u8, + addr: *sockaddr_in) -> c_int; + // FIXME ref #2064 + fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; + // FIXME ref #2064 + fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, + tcp_handle_ptr: *uv_tcp_t, + after_cb: *u8, + addr: *sockaddr_in6) -> c_int; + // FIXME ref #2064 + fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int; + fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, + name: *sockaddr_in) -> c_int; + fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, + name: *sockaddr_in6) ->c_int; + fn rust_uv_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; + fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; + fn rust_uv_write(req: *c_void, + stream: *c_void, + buf_in: *uv_buf_t, + buf_cnt: c_int, + cb: *u8) -> c_int; + fn rust_uv_read_start(stream: *c_void, + on_alloc: *u8, + on_read: *u8) -> c_int; + fn rust_uv_read_stop(stream: *c_void) -> c_int; + fn rust_uv_timer_init(loop_handle: *c_void, + timer_handle: *uv_timer_t) -> c_int; + fn rust_uv_timer_start(timer_handle: *uv_timer_t, + cb: *u8, + timeout: libc::uint64_t, + repeat: libc::uint64_t) -> c_int; + fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; + + fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8; + fn rust_uv_free_base_of_buf(buf: uv_buf_t); + fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; + fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; + fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void; + fn rust_uv_get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void; + fn rust_uv_set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void); + fn rust_uv_get_data_for_uv_handle(handle: *c_void) -> *c_void; + fn rust_uv_set_data_for_uv_handle(handle: *c_void, data: *c_void); + fn rust_uv_get_data_for_req(req: *c_void) -> *c_void; + fn rust_uv_set_data_for_req(req: *c_void, data: *c_void); + fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; + fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t; +} diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index e3f1e9e1328..791f7444b62 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -16,6 +16,8 @@ * other useful things like `push()` and `len()`. */ +use core::prelude::*; + use core::old_iter; use core::old_iter::BaseIter;