<commit_before>use sync::{Arc, Mutex};
use super::super::error::{MyDriverError, InvalidPoolConstraints};
use super::{MyConn, MyOpts, Stmt, QueryResult};
use super::super::error::{MyResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyConn>,
    min: uint,
    max: uint,
    count: uint
}

impl MyInnerPool {
    fn new(min: uint, max: uint, opts: MyOpts) -> MyResult<MyInnerPool> {
        if min > max || max == 0 {
            return Err(MyDriverError(InvalidPoolConstraints));
        }
        let mut pool = MyInnerPool {
            opts: opts,
            pool: Vec::with_capacity(max),
            max: max,
            min: min,
            count: 0
        };
        for _ in range(0, min) {
            try!(pool.new_conn());
        }
        Ok(pool)
    }
    fn new_conn(&mut self) -> MyResult<()> {
        match MyConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

/// Pool which is holding mysql connections.
///
/// It will hold at least ```min``` connections and will create as many as
/// ```max``` connections.
///
/// ```
/// use mysql::conn::{MyOpts};
/// use std::default::{Default};
/// use mysql::conn::pool::{MyPool};
/// use mysql::value::{ToValue};
///
/// fn main() {
///     let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
///                                   ..Default::default()});
///     assert!(pool.is_ok());
///     let pool = pool.unwrap();
///     for _ in range(0u, 100) {
///         let pool = pool.clone();
///         spawn(proc() {
///             let conn = pool.get_conn();
///             assert!(conn.is_ok());
///             let mut conn = conn.unwrap();
///             let result = conn.query("SELECT 1");
///             assert!(result.is_ok());
///             let mut result = result.unwrap();
///             assert_eq!(result.next(), Some(Ok(vec!["1".to_value()])));
///         });
///     }
/// }
/// ```
#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    /// Creates new pool with ```min = 10``` and ```max = 100```
    pub fn new(opts: MyOpts) -> MyResult<MyPool> {
        MyPool::new_manual(10, 100, opts)
    }

    /// Same as ```new``` but you can set ```min``` and ```max```
    pub fn new_manual(min: uint, max: uint, opts: MyOpts) -> MyResult<MyPool> {
        let pool = try!(MyInnerPool::new(min, max, opts));
        Ok(MyPool{ pool: Arc::new(Mutex::new(pool)) })
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.count < pool.max {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        let mut conn = pool.pool.pop().unwrap();

        if !conn.ping() {
            try!(conn.reset());
        }

        Ok(MyPooledConn {pool: self.clone(), conn: Some(conn)})
    }

    /// You can call ```query``` and ```prepare``` directly on a pool but be
    /// aware of the fact that you can't guarantee that query will be called
    /// at concrete connection.
    ///
    /// For example:
    ///
    /// ```ignore
    /// let opts = MyOpts{user: Some("root".to_string()), ..Default::default()};
    /// let pool = MyPool::new(opts).unwrap();
    ///
    /// pool.query("USE some_database");
    /// let result = pool.query("INSERT INTO users (name) VALUES ('Steven')");
    /// let result = pool.query("SELECT * FROM users"); // Error! `no database selected`
    ///                                                 // because PooledConn on which
    ///                                                 // you have executed USE was
    ///                                                 // borrowed by result shadowed
    ///                                                 // on previous line and will not
    ///                                                 // be available until the end of
    ///                                                 // its scope.
    /// ```
    pub fn query<'a>(&'a self, query: &'a str) -> MyResult<QueryResult<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_query(query)
    }

    /// See docs on ```Pool#query```
    pub fn prepare<'a>(&'a self, query: &'a str) -> MyResult<Stmt<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_prepare(query)
    }
}

/// Pooled mysql connection which will return to the pool at the end of its
/// scope.
pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyConn>
}

impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        if pool.count > pool.min || self.conn.is_none() {
            pool.count -= 1;
        } else {
            pool.pool.push(self.conn.take_unwrap());
        }
        pool.cond.signal();
    }
}

impl MyPooledConn {
    /// Redirects to ```MyConn#query```.
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }

    /// Redirects to ```MyConn#prepare```.
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }

    /// Gives mutable reference to the wrapped ```MyConn```.
    pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut MyConn {
        self.conn.get_mut_ref()
    }

    /// Gives reference to the wrapped ```MyConn```.
    pub fn get_ref<'a>(&'a self) -> &'a MyConn {
        self.conn.get_ref()
    }

    /// Unwraps wrapped ```MyConn```.
    pub fn unwrap(mut self) -> MyConn {
        self.conn.take_unwrap()
    }

    fn pooled_query(mut self, query: &str) -> MyResult<QueryResult> {
        match self.get_mut_ref()._query(query) {
            Ok((columns, ok_packet)) => Ok(QueryResult::new_pooled(self,
                                                                   columns,
                                                                   ok_packet,
                                                                   false)),
            Err(err) => Err(err)
        }
    }

    fn pooled_prepare(mut self, query: &str) -> MyResult<Stmt> {
        match self.get_mut_ref()._prepare(query) {
            Ok(stmt) => Ok(Stmt::new_pooled(stmt, self)),
            Err(err) => Err(err)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};
    use super::super::super::value::{Bytes, Int};

    #[test]
    fn test_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let result = pool.query("SELECT 1");
                assert!(result.is_ok());
                let mut result = result.unwrap();
                assert_eq!(result.next(), Some(Ok(vec![Bytes(vec![0x31u8])])));
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let stmt = pool.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                for _ in range(0u, 5u) {
                    let result = stmt.execute([]);
                    assert!(result.is_ok());
                    let mut result = result.unwrap();
                    assert_eq!(result.next(), Some(Ok(vec![Int(1)])));
                    assert_eq!(result.next(), None);
                }
            });
        }
    }
}
<commit_msg>Add docs to MyPool#get_conn<commit_after>use sync::{Arc, Mutex};
use super::super::error::{MyDriverError, InvalidPoolConstraints};
use super::{MyConn, MyOpts, Stmt, QueryResult};
use super::super::error::{MyResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyConn>,
    min: uint,
    max: uint,
    count: uint
}

impl MyInnerPool {
    fn new(min: uint, max: uint, opts: MyOpts) -> MyResult<MyInnerPool> {
        if min > max || max == 0 {
            return Err(MyDriverError(InvalidPoolConstraints));
        }
        let mut pool = MyInnerPool {
            opts: opts,
            pool: Vec::with_capacity(max),
            max: max,
            min: min,
            count: 0
        };
        for _ in range(0, min) {
            try!(pool.new_conn());
        }
        Ok(pool)
    }
    fn new_conn(&mut self) -> MyResult<()> {
        match MyConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

/// Pool which is holding mysql connections.
///
/// It will hold at least ```min``` connections and will create as many as
/// ```max``` connections.
///
/// ```
/// use mysql::conn::{MyOpts};
/// use std::default::{Default};
/// use mysql::conn::pool::{MyPool};
/// use mysql::value::{ToValue};
///
/// fn main() {
///     let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
///                                   ..Default::default()});
///     assert!(pool.is_ok());
///     let pool = pool.unwrap();
///     for _ in range(0u, 100) {
///         let pool = pool.clone();
///         spawn(proc() {
///             let conn = pool.get_conn();
///             assert!(conn.is_ok());
///             let mut conn = conn.unwrap();
///             let result = conn.query("SELECT 1");
///             assert!(result.is_ok());
///             let mut result = result.unwrap();
///             assert_eq!(result.next(), Some(Ok(vec!["1".to_value()])));
///         });
///     }
/// }
/// ```
#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    /// Creates new pool with ```min = 10``` and ```max = 100```
    pub fn new(opts: MyOpts) -> MyResult<MyPool> {
        MyPool::new_manual(10, 100, opts)
    }

    /// Same as ```new``` but you can set ```min``` and ```max```
    pub fn new_manual(min: uint, max: uint, opts: MyOpts) -> MyResult<MyPool> {
        let pool = try!(MyInnerPool::new(min, max, opts));
        Ok(MyPool{ pool: Arc::new(Mutex::new(pool)) })
    }

    /// Gives you a ```MyPooledConn```.
    ///
    /// ```MyPool``` will check that connection is alive via ```MyConn#ping```
    // and will call ```MyConn#reset``` if necessary.
    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.count < pool.max {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        let mut conn = pool.pool.pop().unwrap();

        if !conn.ping() {
            try!(conn.reset());
        }

        Ok(MyPooledConn {pool: self.clone(), conn: Some(conn)})
    }

    /// You can call ```query``` and ```prepare``` directly on a pool but be
    /// aware of the fact that you can't guarantee that query will be called
    /// at concrete connection.
    ///
    /// For example:
    ///
    /// ```ignore
    /// let opts = MyOpts{user: Some("root".to_string()), ..Default::default()};
    /// let pool = MyPool::new(opts).unwrap();
    ///
    /// pool.query("USE some_database");
    /// let result = pool.query("INSERT INTO users (name) VALUES ('Steven')");
    /// let result = pool.query("SELECT * FROM users"); // Error! `no database selected`
    ///                                                 // because PooledConn on which
    ///                                                 // you have executed USE was
    ///                                                 // borrowed by result shadowed
    ///                                                 // on previous line and will not
    ///                                                 // be available until the end of
    ///                                                 // its scope.
    /// ```
    pub fn query<'a>(&'a self, query: &'a str) -> MyResult<QueryResult<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_query(query)
    }

    /// See docs on ```Pool#query```
    pub fn prepare<'a>(&'a self, query: &'a str) -> MyResult<Stmt<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_prepare(query)
    }
}

/// Pooled mysql connection which will return to the pool at the end of its
/// scope.
pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyConn>
}

impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        if pool.count > pool.min || self.conn.is_none() {
            pool.count -= 1;
        } else {
            pool.pool.push(self.conn.take_unwrap());
        }
        pool.cond.signal();
    }
}

impl MyPooledConn {
    /// Redirects to ```MyConn#query```.
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }

    /// Redirects to ```MyConn#prepare```.
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }

    /// Gives mutable reference to the wrapped ```MyConn```.
    pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut MyConn {
        self.conn.get_mut_ref()
    }

    /// Gives reference to the wrapped ```MyConn```.
    pub fn get_ref<'a>(&'a self) -> &'a MyConn {
        self.conn.get_ref()
    }

    /// Unwraps wrapped ```MyConn```.
    pub fn unwrap(mut self) -> MyConn {
        self.conn.take_unwrap()
    }

    fn pooled_query(mut self, query: &str) -> MyResult<QueryResult> {
        match self.get_mut_ref()._query(query) {
            Ok((columns, ok_packet)) => Ok(QueryResult::new_pooled(self,
                                                                   columns,
                                                                   ok_packet,
                                                                   false)),
            Err(err) => Err(err)
        }
    }

    fn pooled_prepare(mut self, query: &str) -> MyResult<Stmt> {
        match self.get_mut_ref()._prepare(query) {
            Ok(stmt) => Ok(Stmt::new_pooled(stmt, self)),
            Err(err) => Err(err)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};
    use super::super::super::value::{Bytes, Int};

    #[test]
    fn test_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let result = pool.query("SELECT 1");
                assert!(result.is_ok());
                let mut result = result.unwrap();
                assert_eq!(result.next(), Some(Ok(vec![Bytes(vec![0x31u8])])));
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let stmt = pool.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                for _ in range(0u, 5u) {
                    let result = stmt.execute([]);
                    assert!(result.is_ok());
                    let mut result = result.unwrap();
                    assert_eq!(result.next(), Some(Ok(vec![Int(1)])));
                    assert_eq!(result.next(), None);
                }
            });
        }
    }
}
<|endoftext|>


<commit_before>
extern crate gitlab_api as gitlab;

use std::env;
#[macro_use]
extern crate log;
extern crate env_logger;

use gitlab::GitLab;
// use gitlab::Pagination;
use gitlab::projects;

fn main() {
    env_logger::init().unwrap();
    info!("starting up");

    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

    let gl = GitLab::new(&hostname, &token);
    // for i in 1..82 {
    //     gl.set_pagination(Pagination{page: i, per_page: 1});
    //     println!("projects: {:?}", gl.projects().unwrap());
    // }
    // gl.set_pagination(Pagination {
    //     page: 1,
    //     per_page: 100,
    // });
    let projects = gl.projects(projects::Listing::new()).unwrap();
    println!("projects: {:?}", projects);
    // FIXME: Project's members are private
    // for project in projects {
    //     println!("{:?}", project.path_with_namespace);
    // }

    let projects = gl.projects_all(projects::all::Listing::new()).unwrap();
    println!("projects: {:?}", projects);

    let listing = projects::id::Listing::new(projects::id::ListingId::Id(10));
    let projects = gl.project_id(listing).unwrap();
    println!("projects: {:?}", projects);
}
<commit_msg>Disable projects listing for now.<commit_after>
extern crate gitlab_api as gitlab;

use std::env;
#[macro_use]
extern crate log;
extern crate env_logger;

use gitlab::GitLab;
// use gitlab::Pagination;
use gitlab::projects;

fn main() {
    env_logger::init().unwrap();
    info!("starting up");

    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

// // Projects
// // List projects
// let projects = gl.projects().list()
// let projects = gl.projects().archived(...).visibility(...).order_by(...).sort(...).search(...).simple(...).list()
// // List all projects (admin)
// let projects = gl.projects().all().list()
// let projects = gl.projects().all().archived(...).visibility(...).order_by(...).sort(...).search(...).list()
// // Single project
// let project = gl.projects().id(142).list()
// // Search
// let projects = gl.projects().search(...).list()
// // Owned
// let projects = gl.projects().owned().archived(...).visibility(...).order_by(...).sort(...).search(...).list()

    let gl = GitLab::new_insecure(&hostname, &token);

    let projects = gl.projects().list();

    // // for i in 1..82 {
    // //     gl.set_pagination(Pagination{page: i, per_page: 1});
    // //     println!("projects: {:?}", gl.projects_list().unwrap());
    // // }
    // // gl.set_pagination(Pagination {
    // //     page: 1,
    // //     per_page: 100,
    // // });
    // let projects = gl.projects_list(projects::Listing::new()).unwrap();
    // println!("projects: {:?}", projects);
    // // FIXME: Project's members are private
    // // for project in projects {
    // //     println!("{:?}", project.path_with_namespace);
    // // }
    //
    // let projects = gl.projects_all(projects::all::Listing::new()).unwrap();
    // println!("projects: {:?}", projects);
    //
    // let listing = projects::id::Listing::new(projects::id::ListingId::Id(10));
    // let projects = gl.project_id(listing).unwrap();
    // println!("projects: {:?}", projects);
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;
use collections::vec_deque::VecDeque;

use core::ops::DerefMut;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use core::usize;

use common::elf::Elf;
use common::event::Event;
use common::get_slice::GetSlice;
use common::memory;

use scheduler::context::{context_switch, Context, ContextMemory};

use schemes::{Result, KScheme, Resource, ResourceSeek, Url};

use sync::Intex;

use syscall::SysError;
use syscall::handle::*;

pub enum Msg {
    Start,
    Stop,
    Open(*const u8, usize),
    Close(usize),
    Dup(usize),
    Path(usize, *mut u8, usize),
    Read(usize, *mut u8, usize),
    Write(usize, *const u8, usize),
    Seek(usize, isize, isize),
    Sync(usize),
    Truncate(usize, usize),
    Event(*const Event),
}

pub struct Response {
    msg: Msg,
    result: AtomicUsize,
    ready: AtomicBool,
}

impl Response {
    pub fn new(msg: Msg) -> Box<Response> {
        box Response {
            msg: msg,
            result: AtomicUsize::new(0),
            ready: AtomicBool::new(false),
        }
    }

    pub fn set(&mut self, result: usize) {
        self.result.store(result, Ordering::SeqCst);
        self.ready.store(true, Ordering::SeqCst);
    }

    pub fn get(&self) -> usize {
        while !self.ready.load(Ordering::SeqCst) {
            unsafe { context_switch(false) };
        }

        return self.result.load(Ordering::SeqCst);
    }
}

impl Drop for Response {
    fn drop(&mut self) {
        while !self.ready.load(Ordering::SeqCst) {
            unsafe { context_switch(false) };
        }
    }
}

/// A scheme resource
pub struct SchemeResource {
    /// Pointer to parent
    pub parent: *mut SchemeItem,
    /// File handle
    pub handle: usize,
}

impl SchemeResource {
    pub fn send(&self, msg: Msg) -> Result<usize> {
        unsafe { (*self.parent).send(msg) }
    }
}

impl Resource for SchemeResource {
    /// Duplicate the resource
    fn dup(&self) -> Result<Box<Resource>> {
        match self.send(Msg::Dup(self.handle)) {
            Ok(fd) => Ok(box SchemeResource {
                parent: self.parent,
                handle: fd,
            }),
            Err(err) => Err(err)
        }
    }

    /// Return the url of this resource
    fn url(&self) -> Url {
        let mut buf: [u8; 4096] = [0; 4096];
        match self.send(Msg::Path(self.handle, buf.as_mut_ptr(), buf.len())) {
            Ok(result) => Url::from_string(unsafe {
                String::from_utf8_unchecked(Vec::from(buf.get_slice(None, Some(result))))
            }),
            Err(err) => Url::new()
        }
    }

    /// Read data to buffer
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut ptr = buf.as_mut_ptr();

        let contexts = ::env().contexts.lock();
        if let Some(current) = contexts.current() {
            if let Some(translated) = unsafe { current.translate(ptr as usize) } {
                ptr = translated as *mut u8;
            }
        }

        self.send(Msg::Read(self.handle, ptr, buf.len()))
    }

    /// Write to resource
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut ptr = buf.as_ptr();

        let contexts = ::env().contexts.lock();
        if let Some(current) = contexts.current() {
            if let Some(translated) = unsafe { current.translate(ptr as usize) } {
                ptr = translated as *const u8;
            }
        }

        self.send(Msg::Write(self.handle, ptr, buf.len()))
    }

    /// Seek
    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
        let offset;
        let whence;
        match pos {
            ResourceSeek::Start(off) => {
                whence = 0;
                offset = off as isize;
            }
            ResourceSeek::Current(off) => {
                whence = 1;
                offset = off;
            }
            ResourceSeek::End(off) => {
                whence = 2;
                offset = off;
            }
        }

        self.send(Msg::Seek(self.handle, offset, whence))
    }

    /// Sync the resource
    fn sync(&mut self) -> Result<()> {
        match self.send(Msg::Sync(self.handle)) {
            Ok(_) => Ok(()),
            Err(err) => Err(err)
        }
    }

    fn truncate(&mut self, len: usize) -> Result<()> {
        match self.send(Msg::Truncate(self.handle, len)) {
            Ok(_) => Ok(()),
            Err(err) => Err(err)
        }
    }
}

impl Drop for SchemeResource {
    fn drop(&mut self) {
        self.send(Msg::Close(self.handle));
    }
}

/// A scheme item
pub struct SchemeItem {
    /// The URL
    url: Url,
    /// The scheme
    scheme: String,
    /// The binary for the scheme
    binary: Url,
    /// Messages to be responded to
    responses: Intex<VecDeque<*mut Response>>,
    /// The handle
    handle: usize,
    _start: usize,
    _stop: usize,
    _open: usize,
    _dup: usize,
    _fpath: usize,
    _read: usize,
    _write: usize,
    _lseek: usize,
    _fsync: usize,
    _ftruncate: usize,
    _close: usize,
    _event: usize,
}

impl SchemeItem {
    /// Load scheme item from URL
    pub fn from_url(url: &Url) -> Box<SchemeItem> {
        let mut scheme_item = box SchemeItem {
            url: url.clone(),
            scheme: String::new(),
            binary: Url::from_string(url.to_string() + "main.bin"),
            responses: Intex::new(VecDeque::new()),
            handle: 0,
            _start: 0,
            _stop: 0,
            _open: 0,
            _dup: 0,
            _fpath: 0,
            _read: 0,
            _write: 0,
            _lseek: 0,
            _fsync: 0,
            _ftruncate: 0,
            _close: 0,
            _event: 0,
        };

        for part in url.reference().rsplit('/') {
            if !part.is_empty() {
                scheme_item.scheme = part.to_string();
                break;
            }
        }

        let mut memory = Vec::new();
        if let Ok(mut resource) = scheme_item.binary.open() {
            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            unsafe {
                let executable = Elf::from_data(vec.as_ptr() as usize);

                scheme_item._start = executable.symbol("_start");
                scheme_item._stop = executable.symbol("_stop");
                scheme_item._open = executable.symbol("_open");
                scheme_item._dup = executable.symbol("_dup");
                scheme_item._fpath = executable.symbol("_fpath");
                scheme_item._read = executable.symbol("_read");
                scheme_item._write = executable.symbol("_write");
                scheme_item._lseek = executable.symbol("_lseek");
                scheme_item._fsync = executable.symbol("_fsync");
                scheme_item._ftruncate = executable.symbol("_ftruncate");
                scheme_item._close = executable.symbol("_close");
                scheme_item._event = executable.symbol("_event");

                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;
                    let physical_address = memory::alloc(virtual_size);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy(physical_address as *mut u8,
                                 (executable.data + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        ::memset((physical_address + segment.file_len as usize) as *mut u8,
                                 0,
                                 segment.mem_len as usize - segment.file_len as usize);

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address,
                            virtual_size: virtual_size,
                            writeable: segment.flags & 2 == 2,
                        });
                    }
                }
            }
        }

        let wd = url.to_string();
        let scheme_item_ptr: *mut SchemeItem = scheme_item.deref_mut();
        Context::spawn(scheme_item.binary.to_string(),
                       box move || {
                           unsafe {
                               {
                                   let wd_c = wd + "\0";
                                   do_sys_chdir(wd_c.as_ptr());

                                   let stdio_c = "debug:\0";
                                   do_sys_open(stdio_c.as_ptr(), 0);
                                   do_sys_open(stdio_c.as_ptr(), 0);
                                   do_sys_open(stdio_c.as_ptr(), 0);

                                   let mut contexts = ::env().contexts.lock();
                                   if let Some(mut current) = contexts.current_mut() {
                                       current.unmap();
                                       (*current.memory.get()) = memory;
                                       current.map();
                                   }
                               }

                               (*scheme_item_ptr).run();
                           }
                       });

        scheme_item.handle = match scheme_item.send(Msg::Start) {
            Ok(handle) => handle,
            Err(_) => 0
        };

        scheme_item
    }
}

impl KScheme for SchemeItem {
    fn scheme(&self) -> &str {
        return &self.scheme;
    }

    // TODO: Hack for orbital
    fn event(&mut self, event: &Event) {
        self.send(Msg::Event(event));
    }

    fn open(&mut self, url: &Url, flags: usize) -> Result<Box<Resource>> {
        let c_str = url.to_string() + "\0";
        match self.send(Msg::Open(c_str.as_ptr(), flags)) {
            Ok(fd) => Ok(box SchemeResource {
                parent: self,
                handle: fd,
            }),
            Err(err) => Err(err)
        }
    }
}

impl Drop for SchemeItem {
    fn drop(&mut self) {
        self.send(Msg::Stop);
    }
}

impl SchemeItem {
    pub fn send(&mut self, msg: Msg) -> Result<usize> {
        let mut response = Response::new(msg);

        self.responses.lock().push_back(response.deref_mut());

        SysError::demux(response.get())
    }

    // TODO: More advanced check
    pub fn valid(&self, call: usize) -> bool {
        call > 0
    }

    pub unsafe fn run(&mut self) {
        let mut running = true;
        while running {
            let response_option = self.responses.lock().pop_front();

            if let Some(response_ptr) = response_option {
                let ret = match (*response_ptr).msg {
                    Msg::Start => if self.valid(self._start) {
                        let fn_ptr: *const usize = &self._start;
                        (*(fn_ptr as *const extern "C" fn() -> usize))()
                    } else {
                        0
                    },
                    Msg::Stop => if self.valid(self._stop) {
                        running = false;
                        let fn_ptr: *const usize = &self._stop;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(self.handle)
                    } else {
                        usize::MAX
                    },
                    Msg::Open(path, flags) => if self.valid(self._open) {
                        let fn_ptr: *const usize = &self._open;
                        (*(fn_ptr as *const extern "C" fn(usize, *const u8, usize) -> usize))(self.handle, path, flags)
                    } else {
                        usize::MAX
                    },
                    Msg::Event(event_ptr) => if self.valid(self._event) {
                        let fn_ptr: *const usize = &self._event;
                        (*(fn_ptr as *const extern "C" fn(usize, usize) -> usize))(self.handle, event_ptr as usize)
                    } else {
                        usize::MAX
                    },
                    Msg::Dup(fd) => if self.valid(self._dup) {
                        let fn_ptr: *const usize = &self._dup;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(fd)
                    } else {
                        usize::MAX
                    },
                    Msg::Path(fd, ptr, len) => if self.valid(self._fpath) {
                        let fn_ptr: *const usize = &self._fpath;
                        (*(fn_ptr as *const extern "C" fn(usize, *mut u8, usize) -> usize))(fd,
                                                                                ptr,
                                                                                len)
                    } else {
                        usize::MAX
                    },
                    Msg::Read(fd, ptr, len) => if self.valid(self._read) {
                        let fn_ptr: *const usize = &self._read;
                        (*(fn_ptr as *const extern "C" fn(usize, *mut u8, usize) -> usize))(fd,
                                                                                ptr,
                                                                                len)
                    } else {
                        usize::MAX
                    },
                    Msg::Write(fd, ptr, len) =>
                        if self.valid(self._write) {
                            let fn_ptr: *const usize = &self._write;
                            (*(fn_ptr as *const extern "C" fn(usize, *const u8, usize) -> usize))(fd, ptr, len)
                        } else {
                            usize::MAX
                        },
                    Msg::Seek(fd, offset, whence) =>
                        if self.valid(self._lseek) {
                            let fn_ptr: *const usize = &self._lseek;
                            (*(fn_ptr as *const extern "C" fn(usize, isize, isize) -> usize))(fd, offset, whence)
                        } else {
                            usize::MAX
                        },
                    Msg::Sync(fd) => if self.valid(self._fsync) {
                        let fn_ptr: *const usize = &self._fsync;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(fd)
                    } else {
                        usize::MAX
                    },
                    Msg::Truncate(fd, len) => if self.valid(self._ftruncate) {
                        let fn_ptr: *const usize = &self._ftruncate;
                        (*(fn_ptr as *const extern "C" fn(usize, usize) -> usize))(fd, len)
                    } else {
                        usize::MAX
                    },
                    Msg::Close(fd) => if self.valid(self._close) {
                        let fn_ptr: *const usize = &self._close;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(fd)
                    } else {
                        usize::MAX
                    },
                };

                (*response_ptr).set(ret);
            } else {
                context_switch(false);
            }
        }
    }
}
<commit_msg>Modify scheme loader as well<commit_after>use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;
use collections::vec_deque::VecDeque;

use core::ops::DerefMut;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use core::usize;

use common::elf::Elf;
use common::event::Event;
use common::get_slice::GetSlice;
use common::memory;

use scheduler::context::{context_switch, Context, ContextMemory};

use schemes::{Result, KScheme, Resource, ResourceSeek, Url};

use sync::Intex;

use syscall::SysError;
use syscall::handle::*;

pub enum Msg {
    Start,
    Stop,
    Open(*const u8, usize),
    Close(usize),
    Dup(usize),
    Path(usize, *mut u8, usize),
    Read(usize, *mut u8, usize),
    Write(usize, *const u8, usize),
    Seek(usize, isize, isize),
    Sync(usize),
    Truncate(usize, usize),
    Event(*const Event),
}

pub struct Response {
    msg: Msg,
    result: AtomicUsize,
    ready: AtomicBool,
}

impl Response {
    pub fn new(msg: Msg) -> Box<Response> {
        box Response {
            msg: msg,
            result: AtomicUsize::new(0),
            ready: AtomicBool::new(false),
        }
    }

    pub fn set(&mut self, result: usize) {
        self.result.store(result, Ordering::SeqCst);
        self.ready.store(true, Ordering::SeqCst);
    }

    pub fn get(&self) -> usize {
        while !self.ready.load(Ordering::SeqCst) {
            unsafe { context_switch(false) };
        }

        return self.result.load(Ordering::SeqCst);
    }
}

impl Drop for Response {
    fn drop(&mut self) {
        while !self.ready.load(Ordering::SeqCst) {
            unsafe { context_switch(false) };
        }
    }
}

/// A scheme resource
pub struct SchemeResource {
    /// Pointer to parent
    pub parent: *mut SchemeItem,
    /// File handle
    pub handle: usize,
}

impl SchemeResource {
    pub fn send(&self, msg: Msg) -> Result<usize> {
        unsafe { (*self.parent).send(msg) }
    }
}

impl Resource for SchemeResource {
    /// Duplicate the resource
    fn dup(&self) -> Result<Box<Resource>> {
        match self.send(Msg::Dup(self.handle)) {
            Ok(fd) => Ok(box SchemeResource {
                parent: self.parent,
                handle: fd,
            }),
            Err(err) => Err(err)
        }
    }

    /// Return the url of this resource
    fn url(&self) -> Url {
        let mut buf: [u8; 4096] = [0; 4096];
        match self.send(Msg::Path(self.handle, buf.as_mut_ptr(), buf.len())) {
            Ok(result) => Url::from_string(unsafe {
                String::from_utf8_unchecked(Vec::from(buf.get_slice(None, Some(result))))
            }),
            Err(err) => Url::new()
        }
    }

    /// Read data to buffer
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut ptr = buf.as_mut_ptr();

        let contexts = ::env().contexts.lock();
        if let Some(current) = contexts.current() {
            if let Some(translated) = unsafe { current.translate(ptr as usize) } {
                ptr = translated as *mut u8;
            }
        }

        self.send(Msg::Read(self.handle, ptr, buf.len()))
    }

    /// Write to resource
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut ptr = buf.as_ptr();

        let contexts = ::env().contexts.lock();
        if let Some(current) = contexts.current() {
            if let Some(translated) = unsafe { current.translate(ptr as usize) } {
                ptr = translated as *const u8;
            }
        }

        self.send(Msg::Write(self.handle, ptr, buf.len()))
    }

    /// Seek
    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
        let offset;
        let whence;
        match pos {
            ResourceSeek::Start(off) => {
                whence = 0;
                offset = off as isize;
            }
            ResourceSeek::Current(off) => {
                whence = 1;
                offset = off;
            }
            ResourceSeek::End(off) => {
                whence = 2;
                offset = off;
            }
        }

        self.send(Msg::Seek(self.handle, offset, whence))
    }

    /// Sync the resource
    fn sync(&mut self) -> Result<()> {
        match self.send(Msg::Sync(self.handle)) {
            Ok(_) => Ok(()),
            Err(err) => Err(err)
        }
    }

    fn truncate(&mut self, len: usize) -> Result<()> {
        match self.send(Msg::Truncate(self.handle, len)) {
            Ok(_) => Ok(()),
            Err(err) => Err(err)
        }
    }
}

impl Drop for SchemeResource {
    fn drop(&mut self) {
        self.send(Msg::Close(self.handle));
    }
}

/// A scheme item
pub struct SchemeItem {
    /// The URL
    url: Url,
    /// The scheme
    scheme: String,
    /// The binary for the scheme
    binary: Url,
    /// Messages to be responded to
    responses: Intex<VecDeque<*mut Response>>,
    /// The handle
    handle: usize,
    _start: usize,
    _stop: usize,
    _open: usize,
    _dup: usize,
    _fpath: usize,
    _read: usize,
    _write: usize,
    _lseek: usize,
    _fsync: usize,
    _ftruncate: usize,
    _close: usize,
    _event: usize,
}

impl SchemeItem {
    /// Load scheme item from URL
    pub fn from_url(url: &Url) -> Box<SchemeItem> {
        let mut scheme_item = box SchemeItem {
            url: url.clone(),
            scheme: String::new(),
            binary: Url::from_string(url.to_string() + "main.bin"),
            responses: Intex::new(VecDeque::new()),
            handle: 0,
            _start: 0,
            _stop: 0,
            _open: 0,
            _dup: 0,
            _fpath: 0,
            _read: 0,
            _write: 0,
            _lseek: 0,
            _fsync: 0,
            _ftruncate: 0,
            _close: 0,
            _event: 0,
        };

        for part in url.reference().rsplit('/') {
            if !part.is_empty() {
                scheme_item.scheme = part.to_string();
                break;
            }
        }

        let mut memory = Vec::new();
        if let Ok(mut resource) = scheme_item.binary.open() {
            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            unsafe {
                let executable = Elf::from_data(vec.as_ptr() as usize);

                scheme_item._start = executable.symbol("_start");
                scheme_item._stop = executable.symbol("_stop");
                scheme_item._open = executable.symbol("_open");
                scheme_item._dup = executable.symbol("_dup");
                scheme_item._fpath = executable.symbol("_fpath");
                scheme_item._read = executable.symbol("_read");
                scheme_item._write = executable.symbol("_write");
                scheme_item._lseek = executable.symbol("_lseek");
                scheme_item._fsync = executable.symbol("_fsync");
                scheme_item._ftruncate = executable.symbol("_ftruncate");
                scheme_item._close = executable.symbol("_close");
                scheme_item._event = executable.symbol("_event");

                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    //TODO: Warning: Investigate this hack!
                    let hack = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + hack);

                    if physical_address > 0 {
                        debugln!("VADDR: {:X} OFF: {:X} FLG: {:X} HACK: {:X}", segment.vaddr, segment.off, segment.flags, hack);

                        // Copy progbits
                        ::memcpy((physical_address + hack) as *mut u8,
                                 (executable.data + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            debugln!("BSS: {:X} {}", segment.vaddr + segment.file_len, segment.mem_len - segment.file_len);
                            ::memset((physical_address + hack + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - hack,
                            virtual_size: virtual_size + hack,
                            writeable: segment.flags & 2 == 2
                        });
                    }
                }
            }
        }

        let wd = url.to_string();
        let scheme_item_ptr: *mut SchemeItem = scheme_item.deref_mut();
        Context::spawn(scheme_item.binary.to_string(),
                       box move || {
                           unsafe {
                               {
                                   let wd_c = wd + "\0";
                                   do_sys_chdir(wd_c.as_ptr());

                                   let stdio_c = "debug:\0";
                                   do_sys_open(stdio_c.as_ptr(), 0);
                                   do_sys_open(stdio_c.as_ptr(), 0);
                                   do_sys_open(stdio_c.as_ptr(), 0);

                                   let mut contexts = ::env().contexts.lock();
                                   if let Some(mut current) = contexts.current_mut() {
                                       current.unmap();
                                       (*current.memory.get()) = memory;
                                       current.map();
                                   }
                               }

                               (*scheme_item_ptr).run();
                           }
                       });

        scheme_item.handle = match scheme_item.send(Msg::Start) {
            Ok(handle) => handle,
            Err(_) => 0
        };

        scheme_item
    }
}

impl KScheme for SchemeItem {
    fn scheme(&self) -> &str {
        return &self.scheme;
    }

    // TODO: Hack for orbital
    fn event(&mut self, event: &Event) {
        self.send(Msg::Event(event));
    }

    fn open(&mut self, url: &Url, flags: usize) -> Result<Box<Resource>> {
        let c_str = url.to_string() + "\0";
        match self.send(Msg::Open(c_str.as_ptr(), flags)) {
            Ok(fd) => Ok(box SchemeResource {
                parent: self,
                handle: fd,
            }),
            Err(err) => Err(err)
        }
    }
}

impl Drop for SchemeItem {
    fn drop(&mut self) {
        self.send(Msg::Stop);
    }
}

impl SchemeItem {
    pub fn send(&mut self, msg: Msg) -> Result<usize> {
        let mut response = Response::new(msg);

        self.responses.lock().push_back(response.deref_mut());

        SysError::demux(response.get())
    }

    // TODO: More advanced check
    pub fn valid(&self, call: usize) -> bool {
        call > 0
    }

    pub unsafe fn run(&mut self) {
        let mut running = true;
        while running {
            let response_option = self.responses.lock().pop_front();

            if let Some(response_ptr) = response_option {
                let ret = match (*response_ptr).msg {
                    Msg::Start => if self.valid(self._start) {
                        let fn_ptr: *const usize = &self._start;
                        (*(fn_ptr as *const extern "C" fn() -> usize))()
                    } else {
                        0
                    },
                    Msg::Stop => if self.valid(self._stop) {
                        running = false;
                        let fn_ptr: *const usize = &self._stop;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(self.handle)
                    } else {
                        usize::MAX
                    },
                    Msg::Open(path, flags) => if self.valid(self._open) {
                        let fn_ptr: *const usize = &self._open;
                        (*(fn_ptr as *const extern "C" fn(usize, *const u8, usize) -> usize))(self.handle, path, flags)
                    } else {
                        usize::MAX
                    },
                    Msg::Event(event_ptr) => if self.valid(self._event) {
                        let fn_ptr: *const usize = &self._event;
                        (*(fn_ptr as *const extern "C" fn(usize, usize) -> usize))(self.handle, event_ptr as usize)
                    } else {
                        usize::MAX
                    },
                    Msg::Dup(fd) => if self.valid(self._dup) {
                        let fn_ptr: *const usize = &self._dup;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(fd)
                    } else {
                        usize::MAX
                    },
                    Msg::Path(fd, ptr, len) => if self.valid(self._fpath) {
                        let fn_ptr: *const usize = &self._fpath;
                        (*(fn_ptr as *const extern "C" fn(usize, *mut u8, usize) -> usize))(fd,
                                                                                ptr,
                                                                                len)
                    } else {
                        usize::MAX
                    },
                    Msg::Read(fd, ptr, len) => if self.valid(self._read) {
                        let fn_ptr: *const usize = &self._read;
                        (*(fn_ptr as *const extern "C" fn(usize, *mut u8, usize) -> usize))(fd,
                                                                                ptr,
                                                                                len)
                    } else {
                        usize::MAX
                    },
                    Msg::Write(fd, ptr, len) =>
                        if self.valid(self._write) {
                            let fn_ptr: *const usize = &self._write;
                            (*(fn_ptr as *const extern "C" fn(usize, *const u8, usize) -> usize))(fd, ptr, len)
                        } else {
                            usize::MAX
                        },
                    Msg::Seek(fd, offset, whence) =>
                        if self.valid(self._lseek) {
                            let fn_ptr: *const usize = &self._lseek;
                            (*(fn_ptr as *const extern "C" fn(usize, isize, isize) -> usize))(fd, offset, whence)
                        } else {
                            usize::MAX
                        },
                    Msg::Sync(fd) => if self.valid(self._fsync) {
                        let fn_ptr: *const usize = &self._fsync;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(fd)
                    } else {
                        usize::MAX
                    },
                    Msg::Truncate(fd, len) => if self.valid(self._ftruncate) {
                        let fn_ptr: *const usize = &self._ftruncate;
                        (*(fn_ptr as *const extern "C" fn(usize, usize) -> usize))(fd, len)
                    } else {
                        usize::MAX
                    },
                    Msg::Close(fd) => if self.valid(self._close) {
                        let fn_ptr: *const usize = &self._close;
                        (*(fn_ptr as *const extern "C" fn(usize) -> usize))(fd)
                    } else {
                        usize::MAX
                    },
                };

                (*response_ptr).set(ret);
            } else {
                context_switch(false);
            }
        }
    }
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;

use arch::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, Context, ContextMemory};
use arch::elf::Elf;
use arch::memory;
use arch::regs::Regs;

use collections::string::{String, ToString};
use collections::vec::Vec;

use common::slice::GetSlice;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use fs::Url;

use system::error::{Error, Result, ENOEXEC};

fn execute_inner(url: Url) -> Result<(*mut Context, usize)> {
    let mut vec: Vec<u8> = Vec::new();

    {
        let mut resource = try!(url.open());
        'reading: loop {
            let mut bytes = [0; 4096];
            match resource.read(&mut bytes) {
                Ok(0) => break 'reading,
                Ok(count) => vec.push_all(bytes.get_slice(.. count)),
                Err(err) => return Err(err)
            }
        }
    }

    match Elf::from(&vec) {
        Ok(executable) => {
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    let offset = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + offset);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy((physical_address + offset) as *mut u8,
                                 (executable.data.as_ptr() as usize + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            ::memset((physical_address + offset + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - offset,
                            virtual_size: virtual_size + offset,
                            writeable: segment.flags & 2 == 2,
                            allocated: true,
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                let mut contexts = ::env().contexts.lock();
                let mut context = try!(contexts.current_mut());
                context.name = url.string;
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));

                unsafe { context.unmap() };
                context.memory = Arc::new(UnsafeCell::new(memory));
                unsafe { context.map() };

                Ok((context.deref_mut(), entry))
            } else {
                Err(Error::new(ENOEXEC))
            }
        },
        Err(msg) => {
            debugln!("execute: failed to exec '{}': {}", url.string, msg);
            Err(Error::new(ENOEXEC))
        }
    }
}

pub fn execute_outer(context_ptr: *mut Context, entry: usize, mut args: Vec<String>) -> ! {
    Context::spawn("kexec".to_string(), box move || {
        let context = unsafe { &mut *context_ptr };

        let mut context_args: Vec<usize> = Vec::new();
        context_args.push(0); // ENVP
        context_args.push(0); // ARGV NULL
        let mut argc = 0;
        for i in 0..args.len() {
            let reverse_i = args.len() - i - 1;
            if let Some(ref mut arg) = args.get_mut(reverse_i) {
                if ! arg.ends_with('\0') {
                    arg.push('\0');
                }

                let physical_address = arg.as_ptr() as usize;
                let virtual_address = context.next_mem();
                let virtual_size = arg.len();

                mem::forget(arg);

                unsafe {
                    (*context.memory.get()).push(ContextMemory {
                        physical_address: physical_address,
                        virtual_address: virtual_address,
                        virtual_size: virtual_size,
                        writeable: false,
                        allocated: true,
                    });
                }

                context_args.push(virtual_address as usize);
                argc += 1;
            }
        }
        context_args.push(argc);

        context.regs = Regs::default();
        context.regs.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

        context.stack = Some(ContextMemory {
            physical_address: unsafe { memory::alloc(CONTEXT_STACK_SIZE) },
            virtual_address: CONTEXT_STACK_ADDR,
            virtual_size: CONTEXT_STACK_SIZE,
            writeable: true,
            allocated: true,
        });

        let user_sp = if let Some(ref stack) = context.stack {
            let mut sp = stack.physical_address + stack.virtual_size - 128;
            for arg in context_args.iter() {
                sp -= mem::size_of::<usize>();
                unsafe { ptr::write(sp as *mut usize, *arg) };
            }
            sp - stack.physical_address + stack.virtual_address
        } else {
            0
        };

        unsafe {
            context.push(0x20 | 3);
            context.push(user_sp);
            context.push(1 << 9);
            context.push(0x18 | 3);
            context.push(entry);
            context.push(context_userspace as usize);
        }
    });

    loop {
        unsafe { context_switch(false) };
    }
}

/// Execute an executable
pub fn execute(args: Vec<String>) -> Result<usize> {
    let contexts = ::env().contexts.lock();
    let current = try!(contexts.current());

    if let Ok((context_ptr, entry)) = execute_inner(Url::from_string(current.canonicalize(args.get(0).map_or("", |p| &p)))) {
        execute_outer(context_ptr, entry, args);
    }else{
        let (context_ptr, entry) = try!(execute_inner(Url::from_string("file:/bin/".to_string() + args.get(0).map_or("", |p| &p))));
        execute_outer(context_ptr, entry, args);
    }
}
<commit_msg>Fix arguments<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;

use arch::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, Context, ContextMemory};
use arch::elf::Elf;
use arch::memory;
use arch::regs::Regs;

use collections::string::{String, ToString};
use collections::vec::Vec;

use common::slice::GetSlice;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use fs::Url;

use system::error::{Error, Result, ENOEXEC};

fn execute_inner(url: Url) -> Result<(*mut Context, usize)> {
    let mut vec: Vec<u8> = Vec::new();

    {
        let mut resource = try!(url.open());
        'reading: loop {
            let mut bytes = [0; 4096];
            match resource.read(&mut bytes) {
                Ok(0) => break 'reading,
                Ok(count) => vec.push_all(bytes.get_slice(.. count)),
                Err(err) => return Err(err)
            }
        }
    }

    match Elf::from(&vec) {
        Ok(executable) => {
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    let offset = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + offset);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy((physical_address + offset) as *mut u8,
                                 (executable.data.as_ptr() as usize + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            ::memset((physical_address + offset + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - offset,
                            virtual_size: virtual_size + offset,
                            writeable: segment.flags & 2 == 2,
                            allocated: true,
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                let mut contexts = ::env().contexts.lock();
                let mut context = try!(contexts.current_mut());
                context.name = url.string;
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));

                unsafe { context.unmap() };
                context.memory = Arc::new(UnsafeCell::new(memory));
                unsafe { context.map() };

                Ok((context.deref_mut(), entry))
            } else {
                Err(Error::new(ENOEXEC))
            }
        },
        Err(msg) => {
            debugln!("execute: failed to exec '{}': {}", url.string, msg);
            Err(Error::new(ENOEXEC))
        }
    }
}

pub fn execute_outer(context_ptr: *mut Context, entry: usize, mut args: Vec<String>) -> ! {
    Context::spawn("kexec".to_string(), box move || {
        let context = unsafe { &mut *context_ptr };

        let mut context_args: Vec<usize> = Vec::new();
        context_args.push(0); // ENVP
        context_args.push(0); // ARGV NULL
        let mut argc = 0;
        while let Some(mut arg) = args.pop() {
            if ! arg.ends_with('\0') {
                arg.push('\0');
            }

            let virtual_address = context.next_mem();

            unsafe {
                let arg_ptr = Box::into_raw(arg.into_boxed_str());

                (*context.memory.get()).push(ContextMemory {
                    physical_address: (*arg_ptr).as_ptr() as usize,
                    virtual_address: virtual_address,
                    virtual_size: (*arg_ptr).len(),
                    writeable: false,
                    allocated: true,
                });
            }

            context_args.push(virtual_address as usize);
            argc += 1;
        }
        context_args.push(argc);

        context.regs = Regs::default();
        context.regs.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

        context.stack = Some(ContextMemory {
            physical_address: unsafe { memory::alloc(CONTEXT_STACK_SIZE) },
            virtual_address: CONTEXT_STACK_ADDR,
            virtual_size: CONTEXT_STACK_SIZE,
            writeable: true,
            allocated: true,
        });

        let user_sp = if let Some(ref stack) = context.stack {
            let mut sp = stack.physical_address + stack.virtual_size - 128;
            for arg in context_args.iter() {
                sp -= mem::size_of::<usize>();
                unsafe { ptr::write(sp as *mut usize, *arg) };
            }
            sp - stack.physical_address + stack.virtual_address
        } else {
            0
        };

        unsafe {
            context.push(0x20 | 3);
            context.push(user_sp);
            context.push(1 << 9);
            context.push(0x18 | 3);
            context.push(entry);
            context.push(context_userspace as usize);
        }
    });

    loop {
        unsafe { context_switch(false) };
    }
}

/// Execute an executable
pub fn execute(args: Vec<String>) -> Result<usize> {
    let contexts = ::env().contexts.lock();
    let current = try!(contexts.current());

    if let Ok((context_ptr, entry)) = execute_inner(Url::from_string(current.canonicalize(args.get(0).map_or("", |p| &p)))) {
        execute_outer(context_ptr, entry, args);
    }else{
        let (context_ptr, entry) = try!(execute_inner(Url::from_string("file:/bin/".to_string() + args.get(0).map_or("", |p| &p))));
        execute_outer(context_ptr, entry, args);
    }
}
<|endoftext|>


<commit_before>use crate::{run_ping, Parser, PingResult, Pinger};
use anyhow::Context;
use regex::Regex;
use std::time::Duration;
use thiserror::Error;

#[derive(Debug, Eq, PartialEq)]
pub enum LinuxPingType {
    BusyBox,
    IPTools,
}

#[derive(Error, Debug)]
pub enum PingDetectionError {
    #[error("Could not detect ping. Stderr: {stderr:?}\nStdout: {stdout:?}")]
    UnknownPing {
        stderr: Vec<String>,
        stdout: Vec<String>,
    },
    #[error(transparent)]
    CommandError(#[from] anyhow::Error),
}

pub fn detect_linux_ping() -> Result<LinuxPingType, PingDetectionError> {
    // Err(PingDetectionError::Thing)
    let child = run_ping(vec!["-V".to_string()], true);
    let output = child
        .wait_with_output()
        .context("Error getting ping stdout/stderr")?;
    let stdout = String::from_utf8(output.stdout).context("Error decoding ping stdout")?;
    let stderr = String::from_utf8(output.stderr).context("Error decoding ping stderr")?;

    if stderr.contains("BusyBox") {
        Ok(LinuxPingType::BusyBox)
    } else if stdout.contains("iputils") {
        Ok(LinuxPingType::IPTools)
    } else {
        let first_two_lines_stderr: Vec<String> =
            stderr.lines().take(2).map(str::to_string).collect();
        let first_two_lines_stout: Vec<String> =
            stdout.lines().take(2).map(str::to_string).collect();
        Err(PingDetectionError::UnknownPing {
            stdout: first_two_lines_stout,
            stderr: first_two_lines_stderr,
        })
    }
}

#[derive(Default)]
pub struct LinuxPinger {
    interval: Duration,
}

impl Pinger for LinuxPinger {
    fn set_interval(&mut self, interval: Duration) {
        self.interval = interval;
    }

    fn ping_args(&self, target: String) -> Vec<String> {
        // The -O flag ensures we "no answer yet" messages from ping
        // See https://superuser.com/questions/270083/linux-ping-show-time-out
        vec![
            "-O".to_string(),
            format!("-i{:.1}", self.interval.as_millis() as f32 / 1_000_f32),
            target,
        ]
    }
}

#[derive(Default)]
pub struct AlpinePinger {
    interval: Duration,
}

// Alpine doesn't support timeout notifications, so we don't add the -O flag here
impl Pinger for AlpinePinger {
    fn set_interval(&mut self, interval: Duration) {
        self.interval = interval;
    }
}

lazy_static! {
    static ref UBUNTU_RE: Regex = Regex::new(r"(?i-u)time=(?P<time>\d+(?:\.\d+)?) *ms").unwrap();
}

#[derive(Default)]
pub struct LinuxParser {}

impl Parser for LinuxParser {
    fn parse(&self, line: String) -> Option<PingResult> {
        if line.starts_with("64 bytes from") {
            return self.extract_regex(&UBUNTU_RE, line);
        } else if line.starts_with("no answer yet") {
            return Some(PingResult::Timeout(line));
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[cfg(target_os = "linux")]
    fn test_linux_detection() {
        use os_info::Type;
        let ping_type = detect_linux_ping().expect("Error getting ping");
        match os_info::get().os_type() {
            Type::Alpine => {
                assert_eq!(ping_type, LinuxPingType::BusyBox)
            }
            Type::Ubuntu => {
                assert_eq!(ping_type, LinuxPingType::IPTools)
            }
            _ => {}
        }
    }
}
<commit_msg>Fix tests<commit_after>use crate::{run_ping, Parser, PingResult, Pinger};
use anyhow::Context;
use regex::Regex;
use std::time::Duration;
use thiserror::Error;

#[derive(Debug, Eq, PartialEq)]
pub enum LinuxPingType {
    BusyBox,
    IPTools,
}

#[derive(Error, Debug)]
pub enum PingDetectionError {
    #[error("Could not detect ping. Stderr: {stderr:?}\nStdout: {stdout:?}")]
    UnknownPing {
        stderr: Vec<String>,
        stdout: Vec<String>,
    },
    #[error(transparent)]
    CommandError(#[from] anyhow::Error),
}

pub fn detect_linux_ping() -> Result<LinuxPingType, PingDetectionError> {
    // Err(PingDetectionError::Thing)
    let child = run_ping(vec!["-V".to_string()], true);
    let output = child
        .wait_with_output()
        .context("Error getting ping stdout/stderr")?;
    let stdout = String::from_utf8(output.stdout).context("Error decoding ping stdout")?;
    let stderr = String::from_utf8(output.stderr).context("Error decoding ping stderr")?;

    if stderr.contains("BusyBox") {
        Ok(LinuxPingType::BusyBox)
    } else if stdout.contains("iputils") {
        Ok(LinuxPingType::IPTools)
    } else {
        let first_two_lines_stderr: Vec<String> =
            stderr.lines().take(2).map(str::to_string).collect();
        let first_two_lines_stout: Vec<String> =
            stdout.lines().take(2).map(str::to_string).collect();
        Err(PingDetectionError::UnknownPing {
            stdout: first_two_lines_stout,
            stderr: first_two_lines_stderr,
        })
    }
}

#[derive(Default)]
pub struct LinuxPinger {
    interval: Duration,
}

impl Pinger for LinuxPinger {
    fn set_interval(&mut self, interval: Duration) {
        self.interval = interval;
    }

    fn ping_args(&self, target: String) -> Vec<String> {
        // The -O flag ensures we "no answer yet" messages from ping
        // See https://superuser.com/questions/270083/linux-ping-show-time-out
        vec![
            "-O".to_string(),
            format!("-i{:.1}", self.interval.as_millis() as f32 / 1_000_f32),
            target,
        ]
    }
}

#[derive(Default)]
pub struct AlpinePinger {
    interval: Duration,
}

// Alpine doesn't support timeout notifications, so we don't add the -O flag here
impl Pinger for AlpinePinger {
    fn set_interval(&mut self, interval: Duration) {
        self.interval = interval;
    }
}

lazy_static! {
    static ref UBUNTU_RE: Regex = Regex::new(r"(?i-u)time=(?P<time>\d+(?:\.\d+)?) *ms").unwrap();
}

#[derive(Default)]
pub struct LinuxParser {}

impl Parser for LinuxParser {
    fn parse(&self, line: String) -> Option<PingResult> {
        if line.starts_with("64 bytes from") {
            return self.extract_regex(&UBUNTU_RE, line);
        } else if line.starts_with("no answer yet") {
            return Some(PingResult::Timeout(line));
        }
        None
    }
}

#[cfg(test)]
mod tests {
    #[test]
    #[cfg(target_os = "linux")]
    fn test_linux_detection() {
        use super::*;
        use os_info::Type;
        let ping_type = detect_linux_ping().expect("Error getting ping");
        match os_info::get().os_type() {
            Type::Alpine => {
                assert_eq!(ping_type, LinuxPingType::BusyBox)
            }
            Type::Ubuntu => {
                assert_eq!(ping_type, LinuxPingType::IPTools)
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher, SipHasher};

pub fn name_hash(str_: &str) -> u64 {
    let mut hasher = SipHasher::new();
    str_.hash(&mut hasher);
    hasher.finish()
}

pub trait NameTableIdx {
    fn to_index(&self) -> usize;
}

impl NameTableIdx for usize {
    fn to_index(&self) -> usize {
        *self
    }
}

pub trait NameTable {
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>>;

    fn initial_local(&self) -> usize;
    fn len_local(&self) -> usize;
    fn at_local<'a>(&'a self, idx: usize) -> &'a str;
    fn find_local(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }

    fn len(&self) -> usize {
        return self.len_local() + self.parent().map_or(0usize, |parent_table| parent_table.len());
    }

    fn at<'a>(&'a self, idx: usize) -> &'a str {
        let initial = self.initial_local();
        if idx >= initial {
            return self.at_local(idx - initial);
        } else if let Some(parent_table) = self.parent().as_ref() {
            &parent_table.at(idx)
        } else {
            panic!("access out of bound");
        }
    }

    fn find(&self, name: &str) -> Option<usize> {
        let initial = self.initial_local();
        self.find_local(name).map(|idx| idx + initial).or_else(|| {
            if let Some(parent_table) = self.parent().as_ref() {
                return parent_table.find(name);
            }
            return None;
        })
    }
}

pub struct StaticNameTable<'a> {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    parent: Option<Box<NameTable + 'a>>,
}

impl<'x> NameTable for StaticNameTable<'x> {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> {
        self.parent.as_ref()
    }
}

impl<'x> StaticNameTable<'x> {
    pub fn new(names_: &'static str, name_offsets_: &'static [usize]) -> Self {
        return StaticNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     parent: ParentTableType)
                                                     -> Self {
        return StaticNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            parent: Some(Box::new(parent)),
        };
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct DynamicNameTable<'a> {
    initial_idx: usize,
    names: Box<Vec<String>>,
    parent: Option<Box<NameTable + 'a>>,
}

impl<'x> NameTable for DynamicNameTable<'x> {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.names.len()
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        self.names[idx].as_str()
    }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> {
        self.parent.as_ref()
    }
}

impl<'x> DynamicNameTable<'x> {
    pub fn new() -> Self {
        return DynamicNameTable {
            initial_idx: 0usize,
            names: Box::new(Vec::new()),
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(parent: ParentTableType) -> Self {
        return DynamicNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: Box::new(Vec::new()),
            parent: Some(Box::new(parent)),
        };
    }

    pub fn intern(&mut self, name: &str) -> usize {
        self.find(name)
            .or_else(|| {
                Some({
                    self.names.as_mut().push(name.to_owned());
                    self.initial_idx + self.names.len() - 1
                })
            })
            .unwrap()
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct StaticHashedNameTable<'a> {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    hash_idxes: &'static [(u64, usize)],
    parent: Option<Box<NameTable + 'a>>,
}

impl<'x> StaticHashedNameTable<'x> {
    pub fn new(names_: &'static str,
               name_offsets_: &'static [usize],
               hash_idxes_: &'static [(u64, usize)])
               -> Self {

        return StaticHashedNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     hash_idxes_: &'static [(u64, usize)],
                                                     parent: ParentTableType)
                                                     -> Self {

        return StaticHashedNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: Some(Box::new(parent)),
        };
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }

    fn hash_enabled(&self) -> bool {
        self.hash_idxes.len() != 0
    }

    fn find_local_hashing(&self, name: &str) -> Option<usize> {
        let target = name_hash(name);
        let result = self.hash_idxes.binary_search_by(|&(a, _)| a.cmp(&target));
        match result {
            Ok(val) => {
                if self.at_local(self.hash_idxes[val].1) == name {
                    Some(self.hash_idxes[val].1)
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn find_local_fallback(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }
}

impl<'x> NameTable for StaticHashedNameTable<'x> {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> {
        self.parent.as_ref()
    }

    fn find_local(&self, name: &str) -> Option<usize> {
        if self.hash_enabled() {
            self.find_local_hashing(name)
        } else {
            self.find_local_fallback(name)
        }
    }
}
<commit_msg>Simplify lifetime management.<commit_after>use std::hash::{Hash, Hasher, SipHasher};

pub fn name_hash(str_: &str) -> u64 {
    let mut hasher = SipHasher::new();
    str_.hash(&mut hasher);
    hasher.finish()
}

pub trait NameTableIdx {
    fn to_index(&self) -> usize;
}

impl NameTableIdx for usize {
    fn to_index(&self) -> usize {
        *self
    }
}

pub trait NameTable {
    fn parent<'a>(&'a self) -> Option<&'a NameTable>;

    fn initial_local(&self) -> usize;
    fn len_local(&self) -> usize;
    fn at_local<'a>(&'a self, idx: usize) -> &'a str;
    fn find_local(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }

    fn len(&self) -> usize {
        return self.len_local() + self.parent().map_or(0usize, |parent_table| parent_table.len());
    }

    fn at<'a>(&'a self, idx: usize) -> &'a str {
        let initial = self.initial_local();
        if idx >= initial {
            return self.at_local(idx - initial);
        } else if let Some(parent_table) = self.parent().as_ref() {
            &parent_table.at(idx)
        } else {
            panic!("access out of bound");
        }
    }

    fn find(&self, name: &str) -> Option<usize> {
        let initial = self.initial_local();
        self.find_local(name).map(|idx| idx + initial).or_else(|| {
            if let Some(parent_table) = self.parent().as_ref() {
                return parent_table.find(name);
            }
            return None;
        })
    }
}

pub struct StaticNameTable {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    parent: Option<Box<NameTable>>,
}

impl NameTable for StaticNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }
}

impl StaticNameTable {
    pub fn new(names_: &'static str, name_offsets_: &'static [usize]) -> Self {
        return StaticNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     parent: ParentTableType)
                                                     -> Self {
        return StaticNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            parent: Some(Box::new(parent)),
        };
    }

    pub fn index<'x, T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct DynamicNameTable {
    initial_idx: usize,
    names: Box<Vec<String>>,
    parent: Option<Box<NameTable>>,
}

impl NameTable for DynamicNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.names.len()
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        self.names[idx].as_str()
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }
}

impl DynamicNameTable {
    pub fn new() -> Self {
        return DynamicNameTable {
            initial_idx: 0usize,
            names: Box::new(Vec::new()),
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(parent: ParentTableType) -> Self {
        return DynamicNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: Box::new(Vec::new()),
            parent: Some(Box::new(parent)),
        };
    }

    pub fn intern(&mut self, name: &str) -> usize {
        self.find(name)
            .or_else(|| {
                Some({
                    self.names.as_mut().push(name.to_owned());
                    self.initial_idx + self.names.len() - 1
                })
            })
            .unwrap()
    }

    pub fn index<'x, T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct StaticHashedNameTable {
    initial_idx: usize,
    names: &'static str,
    name_offsets: &'static [usize],
    hash_idxes: &'static [(u64, usize)],
    parent: Option<Box<NameTable>>,
}

impl StaticHashedNameTable {
    pub fn new(names_: &'static str,
               name_offsets_: &'static [usize],
               hash_idxes_: &'static [(u64, usize)])
               -> Self {

        return StaticHashedNameTable {
            initial_idx: 0usize,
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: None,
        };
    }

    pub fn new_upon<ParentTableType: 'static + NameTable>(names_: &'static str,
                                                     name_offsets_: &'static [usize],
                                                     hash_idxes_: &'static [(u64, usize)],
                                                     parent: ParentTableType)
                                                     -> Self {

        return StaticHashedNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names: names_,
            name_offsets: name_offsets_,
            hash_idxes: hash_idxes_,
            parent: Some(Box::new(parent)),
        };
    }

    pub fn index<'x, T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }

    fn hash_enabled(&self) -> bool {
        self.hash_idxes.len() != 0
    }

    fn find_local_hashing(&self, name: &str) -> Option<usize> {
        let target = name_hash(name);
        let result = self.hash_idxes.binary_search_by(|&(a, _)| a.cmp(&target));
        match result {
            Ok(val) => {
                if self.at_local(self.hash_idxes[val].1) == name {
                    Some(self.hash_idxes[val].1)
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    fn find_local_fallback(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None;
    }
}

impl NameTable for StaticHashedNameTable {
    fn initial_local(&self) -> usize {
        self.initial_idx
    }
    fn len_local(&self) -> usize {
        self.name_offsets.len() - 1
    }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str {
        &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]]
    }
    fn parent<'a>(&'a self) -> Option<&'a NameTable> {
        self.parent.as_ref().map(|boxed| boxed.as_ref())
    }

    fn find_local(&self, name: &str) -> Option<usize> {
        if self.hash_enabled() {
            self.find_local_hashing(name)
        } else {
            self.find_local_fallback(name)
        }
    }
}
<|endoftext|>


<commit_before>use piston_window;
use gfx_device_gl::{Resources, Output, CommandBuffer};
use gfx_graphics::GfxGraphics;
use piston_window::Transformed;

pub struct Object {
    x: f64,
    y: f64,
    sprite: Option<piston_window::Texture<Resources>>,
}

impl Object {
    pub fn new() -> Object {
        Object { x: 0., y: 0., sprite: None }
    }

    pub fn mov(&mut self, x: f64, y: f64) {
        self.x += x;
        self.y += y;
    }

    pub fn mov_to(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn render(&self, graphic: &mut GfxGraphics<Resources, CommandBuffer<Resources>, Output>, view: &piston_window::math::Matrix2d) {
        let red = [1.0, 0.0, 0.0, 1.0];
        let square = piston_window::rectangle::square(0.0, 0.0, 100.0);
        piston_window::rectangle(red, square, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
    }
}
<commit_msg>Object sprite rendering<commit_after>use piston_window;
use gfx_device_gl::{Resources, Output, CommandBuffer};
use gfx_graphics::GfxGraphics;
use piston_window::Transformed;

pub struct Object {
    x: f64,
    y: f64,
    sprite: Option<piston_window::Texture<Resources>>,
}

impl Object {
    pub fn new() -> Object {
        Object { x: 0., y: 0., sprite: None }
    }

    pub fn mov(&mut self, x: f64, y: f64) {
        self.x += x;
        self.y += y;
    }

    pub fn mov_to(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn set_sprite(&mut self, sprite: Texture<Resources>) {
        self.sprite = Some(sprite);
    }

    pub fn render(&self, graphic: &mut GfxGraphics<Resources, CommandBuffer<Resources>, Output>, view: &piston_window::math::Matrix2d) {\
        match self.sprite {
            None => {
                let red = [1.0, 0.0, 0.0, 1.0];
                let square = piston_window::rectangle::square(0.0, 0.0, 100.0);
                piston_window::rectangle(red, square, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
            }
            Some(ref sprite) => {
                piston_window::image(sprite, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
            }
        }
    }
}
<|endoftext|>