<commit_before>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_buffer (buf: &[u8]) {
        let fin = buf[0] & 0b1000_0000;
        let rsv = buf[0] & 0b0111_0000;
        let opc = buf[0] & 0b0000_1111;
        let msk = buf[0] & 0b0000_0001;
        let len = buf[1] & 0b0111_1111;
        let mskkey = buf.slice(2, 6);

        let firstchar = mskkey[0] ^ buf[6];
        for ii in range(0u, len as uint) {
            let i = ii % 4;
            let ch = mskkey[i] ^ buf[6 + ii];
            println!("ch {}", ch as char);
        }

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, firstchar {}, \nbuf {}",
            fin, rsv, msk, opc, len, mskkey, firstchar as char,  buf.as_slice());
    }

    fn continue_from_buffer(buf: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    let mut stream2 = stream;
    msg.send(&mut stream2);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    let mut stream3 = stream2;
    msg.send(&mut stream3);

    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);

    let mut stream4 = stream3;
    let mut buf = [0, ..100];
    match stream4.read(&mut buf) {
        Ok(nread) => println!("Read {} bytes", nread),
        Err(e) => println!("error reading: {}", e)
    }

    Message::from_buffer(&buf);

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>putting the string together<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_buffer (buf: &[u8]) {
        let fin = buf[0] & 0b1000_0000;
        let rsv = buf[0] & 0b0111_0000;
        let opc = buf[0] & 0b0000_1111;
        let msk = buf[0] & 0b0000_0001;
        let len = (buf[1] & 0b0111_1111) as uint;
        let mskkey = buf.slice(2, 6);

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let ch = mskkey[ii % 4] ^ buf[6 + ii];
            msg.push(ch);
        }

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}, \nbuf {}",
            fin, rsv, msk, opc, len, mskkey, String::from_utf8(msg),  buf.as_slice());
    }

    fn continue_from_buffer(buf: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    let mut stream2 = stream;
    msg.send(&mut stream2);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    let mut stream3 = stream2;
    msg.send(&mut stream3);

    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);

    let mut stream4 = stream3;
    let mut buf = [0, ..100];
    match stream4.read(&mut buf) {
        Ok(nread) => println!("Read {} bytes", nread),
        Err(e) => println!("error reading: {}", e)
    }

    Message::from_buffer(&buf);

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>use std::mem;
use std::os::unix::io::RawFd;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:          usize = 1024;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
                   ptr as *mut c_void,
                   flags.bits(),
                   &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<commit_msg>Auto merge of #344 - fiveop:clone_flags, r=kamalmarhubi<commit_after>use std::mem;
use std::os::unix::io::RawFd;
use std::option::Option;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:          usize = 1024;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags, signal: Option<c_int>) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let combined = flags.bits() | signal.unwrap_or(0);
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
                   ptr as *mut c_void,
                   combined,
                   &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<|endoftext|>


<commit_before>use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use std::cmp::Ordering;
use syntax::ast::{Item, ItemKind, LitKind, MetaItemKind, Mod, PathListItemKind};
use syntax::ast::{ViewPath_, Visibility};
use syntax::codemap::Span;
use syntax::print::pprust::path_to_string;

// Warn unsorted declarations by default (since denying is a poor choice for styling lints)
declare_lint!(UNSORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorty;

impl LintPass for Sorty {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNSORTED_DECLARATIONS)
    }
}

impl EarlyLintPass for Sorty {
    // walking through all the modules is enough for our purpose
    fn check_mod(&mut self, cx: &EarlyContext, module: &Mod, _span: Span, _id: u32) {
        // TODO: lint should stop ignoring the comments near the declarations
        let session_codemap = cx.sess.codemap();    // required only for checking inline mods
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();

        for item in &module.items {
            // I've made use of `format!` most of the time, because we have a mixture of
            // `String` & `InternedString`
            let item_name = format!("{}", item.ident.name.as_str());
            let item_span = item.span;
            match item.node.clone() {
                ItemKind::ExternCrate(optional_name) if item_name != "std" => {
                    // We've put the declaration here because, we have to sort crate declarations
                    // with respect to the renamed version (instead of the old one).
                    // Since we also don't have `pub` (indicated by the `false` below),
                    // we could just append the declaration to the attributes.
                    let mut item_attrs = get_item_attrs(&item, false);
                    item_attrs = match optional_name {    // for `extern crate foo as bar`
                        Some(old_name) => format!("{}extern crate {} as", item_attrs, old_name),
                        None => format!("{}extern crate", item_attrs),
                    };

                    extern_crates.push((item_name, item_attrs, item_span, false));
                }

                ItemKind::Mod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {          // ignores inline modules
                        let item_attrs = get_item_attrs(&item, true);
                        mods.push((item_name, item_attrs, item_span, false));
                    }
                }

                ItemKind::Use(spanned) => {
                    let item_attrs = get_item_attrs(&item, true);
                    match spanned.node {
                        ViewPath_::ViewPathSimple(ref ident, ref path) => {
                            let path_str = path_to_string(&path);
                            let name = ident.name.as_str();

                            let renamed = {     // `use foo as bar`
                                let split = path_str.split(":").collect::<Vec<_>>();
                                match split[split.len() - 1] == &*name {
                                    true => path_str.clone(),
                                    false => format!("{} as {}", &path_str, &name),
                                }
                            };

                            uses.push((renamed, item_attrs, item_span, false));
                        }

                        ViewPath_::ViewPathList(ref path, ref list) => {
                            // TODO: track the renamed items in use lists
                            let old_list = list.iter()
                                               .map(|&list_item| {
                                                   match list_item.node {
                                                       PathListItemKind::Mod { .. } => {
                                                           // this must be `self`
                                                           "self".to_owned()
                                                       },
                                                       PathListItemKind::Ident { name, .. } => {
                                                           let interned = name.name.as_str();
                                                           (&*interned).to_owned()
                                                       },
                                                   }
                                               }).collect::<Vec<_>>();

                            let mut new_list = old_list.clone();
                            new_list.sort_by(|a, b| {
                                match (&**a, &**b) {    // `self` should be first in a list of use items
                                    ("self", _) => Ordering::Less,
                                    (_, "self") => Ordering::Greater,
                                    _ => a.cmp(b),
                                }
                            });

                            let mut warn = false;
                            let use_list = format!("{}::{{{}}}", path_to_string(&path), new_list.join(", "));
                            for (old_stuff, new_stuff) in old_list.iter().zip(new_list.iter()) {
                                // check whether the use list is sorted
                                if old_stuff != new_stuff {
                                    warn = true;
                                    break
                                }
                            }

                            uses.push((use_list, item_attrs, path.span, warn));
                        }

                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path) + "::*";
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            if !path_str.starts_with("std::") {
                                uses.push((path_str, item_attrs, item_span, false));
                            }
                        }
                    }
                }
                _ => (),
            }
        }

        // we don't include the crate declaration here, because we've already appended it with the
        // attributes
        check_sort(&extern_crates, cx, "crate declarations", "");
        check_sort(&mods, cx, "module declarations (other than inline modules)", "mod");
        check_sort(&uses, cx, "use statements", "use");

        // for collecting, formatting & filtering the attributes (and checking the visibility)
        fn get_item_attrs(item: &Item, pub_check: bool) -> String {
            let mut attr_vec = item.attrs
                                   .iter()
                                   .filter_map(|attr| {
                                       let meta_item = attr.node.value.node.clone();
                                       let meta_string = get_meta_as_string(&meta_item);
                                       match meta_string.starts_with("doc = ") {
                                           true => None,
                                           false => Some(format!("#[{}]", meta_string)),
                                       }
                                   }).collect::<Vec<_>>();

            attr_vec.sort_by(|a, b| {
                match (&**a, &**b) {    // put `macro_use` first for later checking
                    ("#[macro_use]", _) => Ordering::Less,
                    (_, "#[macro_use]") => Ordering::Greater,
                    _ => a.cmp(b),
                }
            });

            let attr_string = attr_vec.join("\n");
            match item.vis {
                Visibility::Public if pub_check => match attr_string.is_empty() {
                    true => "pub ".to_owned(),
                    false => attr_string + "\npub ",    // `pub` for mods and uses
                },
                _ => match attr_string.is_empty() {
                    true => attr_string,
                    false => attr_string + "\n",
                },
            }
        }

        // collect the information from meta items into Strings
        fn get_meta_as_string(meta_item: &MetaItemKind) -> String {
            match *meta_item {
                MetaItemKind::Word(ref string) => format!("{}", string),
                MetaItemKind::List(ref string, ref meta_items) => {
                    let stuff = meta_items.iter()
                                          .map(|meta_item| get_meta_as_string(&meta_item.node))
                                          .collect::<Vec<_>>();
                    format!("{}({})", string, stuff.join(", "))
                },
                MetaItemKind::NameValue(ref string, ref literal) => {
                    let value = match literal.node {
                        LitKind::Str(ref inner_str, _style) => inner_str,
                        _ => panic!("unexpected literal found for meta item!"),

                    };

                    format!("{} = \"{}\"", string, value)
                },
            }
        }

        // checks the sorting of all the declarations and raises warnings whenever necessary
        // takes a slice of tuples with name, related attributes, spans and whether to warn for
        // unordered use lists
        fn check_sort(old_list: &[(String, String, Span, bool)], cx: &EarlyContext,
                      kind: &str, syntax: &str) {

            // prepend given characters to the names for "biased" sorting
            fn str_for_biased_sort(string: &str, choice: bool, prepend_char: &str) -> String {
                match choice {
                    true => prepend_char.to_owned() + string,
                    false => string.to_owned(),
                }
            }

            let mut new_list = old_list.iter()
                                       .map(|&(ref name, ref attrs, _span, warn)| {
                                           (name.clone(), attrs.clone(), warn)
                                       }).collect::<Vec<_>>();

            new_list.sort_by(|&(ref str_a, ref attr_a, _), &(ref str_b, ref attr_b, _)| {
                // move the `pub` statements below
                // (with `~` since it's on the farther side of ASCII)
                let mut new_str_a = str_for_biased_sort(&str_a, attr_a.ends_with("pub "), "~");
                let mut new_str_b = str_for_biased_sort(&str_b, attr_b.ends_with("pub "), "~");
                // move the #[macro_use] stuff above
                // (with `!` since it's on the lower extreme of ASCII)
                new_str_a = str_for_biased_sort(&new_str_a,
                                                attr_a.starts_with("#[macro_use]"), "!");
                new_str_b = str_for_biased_sort(&new_str_b,
                                                attr_b.starts_with("#[macro_use]"), "!");
                new_str_a.cmp(&new_str_b)
            });

            for (i, (&(ref old_name, _, span_start, _warn),
                     &(ref new_name, _, warn))) in old_list.iter()
                                                               .zip(new_list.iter())
                                                               .enumerate() {
                if (old_name != new_name) || warn {
                    // print all the declarations proceeding the first unsorted one
                    let suggestion_list = new_list[i..new_list.len()]
                                          .iter()
                                          .map(|&(ref name, ref attrs, _)| {
                                              format!("{}{} {};", attrs, syntax, name)
                                          }).collect::<Vec<_>>();

                    // increase the span to include more lines
                    let mut final_span = span_start;
                    let (_, _, old_span, _) = old_list[old_list.len() - 1];
                    final_span.hi = old_span.hi;

                    let message = format!("{} should be in alphabetical order!", kind);
                    let suggestion = format!("Try this...\n\n{}\n", suggestion_list.join("\n"));
                    cx.span_lint_help(UNSORTED_DECLARATIONS, final_span, &message, &suggestion);
                    break
                }
            }
        }
    }
}
<commit_msg>Rustup to 1.13.0<commit_after>use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use std::cmp::Ordering;
use syntax::ast::{Item, ItemKind, LitKind, MetaItemKind, Mod};
use syntax::ast::{NestedMetaItemKind, ViewPath_, Visibility};
use syntax::codemap::Span;
use syntax::parse::token::keywords;
use syntax::print::pprust::path_to_string;

// Warn unsorted declarations by default (since denying is a poor choice for styling lints)
declare_lint!(UNSORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorty;

impl LintPass for Sorty {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNSORTED_DECLARATIONS)
    }
}

impl EarlyLintPass for Sorty {
    // walking through all the modules is enough for our purpose
    fn check_mod(&mut self, cx: &EarlyContext, module: &Mod, _span: Span, _id: u32) {
        // TODO: lint should stop ignoring the comments near the declarations
        let session_codemap = cx.sess.codemap();    // required only for checking inline mods
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();

        for item in &module.items {
            // I've made use of `format!` most of the time, because we have a mixture of
            // `String` & `InternedString`
            let item_name = format!("{}", item.ident.name.as_str());
            let item_span = item.span;
            match item.node.clone() {
                ItemKind::ExternCrate(optional_name) if item_name != "std" => {
                    // We've put the declaration here because, we have to sort crate declarations
                    // with respect to the renamed version (instead of the old one).
                    // Since we also don't have `pub` (indicated by the `false` below),
                    // we could just append the declaration to the attributes.
                    let mut item_attrs = get_item_attrs(&item, false);
                    item_attrs = match optional_name {    // for `extern crate foo as bar`
                        Some(old_name) => format!("{}extern crate {} as", item_attrs, old_name),
                        None => format!("{}extern crate", item_attrs),
                    };

                    extern_crates.push((item_name, item_attrs, item_span, false));
                }

                ItemKind::Mod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {          // ignores inline modules
                        let item_attrs = get_item_attrs(&item, true);
                        mods.push((item_name, item_attrs, item_span, false));
                    }
                }

                ItemKind::Use(spanned) => {
                    let item_attrs = get_item_attrs(&item, true);
                    match spanned.node {
                        ViewPath_::ViewPathSimple(ref ident, ref path) => {
                            let path_str = path_to_string(&path);
                            let name = ident.name.as_str();

                            let renamed = {     // `use foo as bar`
                                let split = path_str.split(":").collect::<Vec<_>>();
                                match split[split.len() - 1] == &*name {
                                    true => path_str.clone(),
                                    false => format!("{} as {}", &path_str, &name),
                                }
                            };

                            uses.push((renamed, item_attrs, item_span, false));
                        }

                        ViewPath_::ViewPathList(ref path, ref list) => {
                            let old_list = list.iter().map(|&list_item| {
                                if list_item.node.name.name == keywords::SelfValue.name() {
                                    "self".to_owned()   // this must be `self`
                                } else {
                                    let name = list_item.node.name.name.as_str();
                                    match list_item.node.rename {
                                        Some(new_name) => format!("{} as {}", name, new_name),
                                        None => (&*name).to_owned(),
                                    }
                                }
                            }).collect::<Vec<_>>();

                            let mut new_list = old_list.clone();
                            new_list.sort_by(|a, b| {
                                match (&**a, &**b) {    // `self` should be first in a list of use items
                                    ("self", _) => Ordering::Less,
                                    (_, "self") => Ordering::Greater,
                                    _ => a.cmp(b),
                                }
                            });

                            let mut warn = false;
                            let use_list = format!("{}::{{{}}}", path_to_string(&path), new_list.join(", "));
                            for (old_stuff, new_stuff) in old_list.iter().zip(new_list.iter()) {
                                // check whether the use list is sorted
                                if old_stuff != new_stuff {
                                    warn = true;
                                    break
                                }
                            }

                            uses.push((use_list, item_attrs, path.span, warn));
                        }

                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path) + "::*";
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            if !path_str.starts_with("std::") {
                                uses.push((path_str, item_attrs, item_span, false));
                            }
                        }
                    }
                }
                _ => (),
            }
        }

        // we don't include the crate declaration here, because we've already appended it with the
        // attributes
        check_sort(&extern_crates, cx, "crate declarations", "");
        check_sort(&mods, cx, "module declarations (other than inline modules)", "mod");
        check_sort(&uses, cx, "use statements", "use");

        // for collecting, formatting & filtering the attributes (and checking the visibility)
        fn get_item_attrs(item: &Item, pub_check: bool) -> String {
            let mut attr_vec = item.attrs
                                   .iter()
                                   .filter_map(|attr| {
                                       let meta_item = attr.node.value.node.clone();
                                       let meta_string = get_meta_as_string(&meta_item);
                                       match meta_string.starts_with("doc = ") {
                                           true => None,
                                           false => Some(format!("#[{}]", meta_string)),
                                       }
                                   }).collect::<Vec<_>>();

            attr_vec.sort_by(|a, b| {
                match (&**a, &**b) {    // put `macro_use` first for later checking
                    ("#[macro_use]", _) => Ordering::Less,
                    (_, "#[macro_use]") => Ordering::Greater,
                    _ => a.cmp(b),
                }
            });

            let attr_string = attr_vec.join("\n");
            match item.vis {
                Visibility::Public if pub_check => match attr_string.is_empty() {
                    true => "pub ".to_owned(),
                    false => attr_string + "\npub ",    // `pub` for mods and uses
                },
                _ => match attr_string.is_empty() {
                    true => attr_string,
                    false => attr_string + "\n",
                },
            }
        }

        fn format_literal(lit: &LitKind) -> String {
            match lit {
                &LitKind::Str(ref inner_str, _) => format!("{}", inner_str),
                _ => panic!("unexpected literal for meta item!"),
            }
        }

        // collect the information from meta items into Strings
        fn get_meta_as_string(meta_item: &MetaItemKind) -> String {
            match *meta_item {
                MetaItemKind::Word(ref string) => format!("{}", string),
                MetaItemKind::List(ref string, ref meta_items) => {
                    let stuff = meta_items.iter().map(|meta_item| match meta_item.node {
                        NestedMetaItemKind::MetaItem(ref meta) => get_meta_as_string(&meta.node),
                        NestedMetaItemKind::Literal(ref value) => format_literal(&value.node),
                    }).collect::<Vec<_>>();

                    format!("{}({})", string, stuff.join(", "))
                },
                MetaItemKind::NameValue(ref string, ref literal) => {
                    let value = format_literal(&literal.node);
                    format!("{} = \"{}\"", string, value)
                },
            }
        }

        // checks the sorting of all the declarations and raises warnings whenever necessary
        // takes a slice of tuples with name, related attributes, spans and whether to warn for
        // unordered use lists
        fn check_sort(old_list: &[(String, String, Span, bool)], cx: &EarlyContext,
                      kind: &str, syntax: &str) {

            // prepend given characters to the names for "biased" sorting
            fn str_for_biased_sort(string: &str, choice: bool, prepend_char: &str) -> String {
                match choice {
                    true => prepend_char.to_owned() + string,
                    false => string.to_owned(),
                }
            }

            let mut new_list = old_list.iter()
                                       .map(|&(ref name, ref attrs, _span, warn)| {
                                           (name.clone(), attrs.clone(), warn)
                                       }).collect::<Vec<_>>();

            new_list.sort_by(|&(ref str_a, ref attr_a, _), &(ref str_b, ref attr_b, _)| {
                // move the `pub` statements below
                // (with `~` since it's on the farther side of ASCII)
                let mut new_str_a = str_for_biased_sort(&str_a, attr_a.ends_with("pub "), "~");
                let mut new_str_b = str_for_biased_sort(&str_b, attr_b.ends_with("pub "), "~");
                // move the #[macro_use] stuff above
                // (with `!` since it's on the lower extreme of ASCII)
                new_str_a = str_for_biased_sort(&new_str_a,
                                                attr_a.starts_with("#[macro_use]"), "!");
                new_str_b = str_for_biased_sort(&new_str_b,
                                                attr_b.starts_with("#[macro_use]"), "!");
                new_str_a.cmp(&new_str_b)
            });

            for (i, (&(ref old_name, _, span_start, _warn),
                     &(ref new_name, _, warn))) in old_list.iter()
                                                           .zip(new_list.iter())
                                                           .enumerate() {
                if (old_name != new_name) || warn {
                    // print all the declarations proceeding the first unsorted one
                    let suggestion_list = new_list[i..new_list.len()]
                                          .iter()
                                          .map(|&(ref name, ref attrs, _)| {
                                              format!("{}{} {};", attrs, syntax, name)
                                          }).collect::<Vec<_>>();

                    // increase the span to include more lines
                    let mut final_span = span_start;
                    let (_, _, old_span, _) = old_list[old_list.len() - 1];
                    final_span.hi = old_span.hi;

                    let message = format!("{} should be in alphabetical order!", kind);
                    let suggestion = format!("Try this...\n\n{}\n", suggestion_list.join("\n"));
                    cx.span_lint_help(UNSORTED_DECLARATIONS, final_span, &message, &suggestion);
                    break
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::start_server;
use graph;
use graph::*;
use graph::edge::*;
use graph::vertex::*;
use server::schema::{MorpheusSchema, SchemaError, EMPTY_FIELDS};
use neb::ram::schema::Field;
use neb::ram::types::{TypeId, Value, Map};

#[test]
pub fn schemas() {
    let server = start_server(4001);
    let graph = &server.graph;
    let mut edge_schema = MorpheusSchema::new(
        "test_edge_schema",
        None,
        &vec![Field::new(&"test_field", TypeId::U32 as u32, false, false, None)], false
    );
    assert_eq!(edge_schema.id, 0);
    assert!(
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new
            (
                graph::edge::EdgeType::Directed,
                false
            )).is_err());
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new(graph::edge::EdgeType::Directed, true)).unwrap();
    let mut vertex_schema = edge_schema.clone();
    vertex_schema.name = "test_vertex_schema".to_string();
    graph.new_vertex_group(&mut vertex_schema).unwrap();
    assert!(edge_schema.id > 0);
    assert!(vertex_schema.id > 0);
    let mut test_data = Map::new();
    test_data.insert("test_field", Value::U32(1));
    graph.new_vertex(&vertex_schema, test_data.clone()).unwrap();
    graph.new_vertex("test_edge_schema", test_data.clone()).is_err();
}

#[test]
pub fn relationship() {
    let server = start_server(4002);
    let graph = &server.graph;
    let mut people_schema = MorpheusSchema::new("people", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None)
    ], true);
    let mut movie_schema = MorpheusSchema::new("movie", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None),
        Field::new("year", TypeId::U32 as u32, false, false, None)
    ], true);
    let mut acted_in_schema = MorpheusSchema::new("acted-in", None, &vec! [
        Field::new("role", TypeId::String as u32, false, false, None)
    ], true);
    let mut spouse_schema = MorpheusSchema::new("spouse", None, &EMPTY_FIELDS, false);
    graph.new_vertex_group(&mut people_schema).unwrap();
    graph.new_vertex_group(&mut movie_schema).unwrap();
    graph.new_edge_group(
        &mut acted_in_schema,
        EdgeAttributes::new(
            EdgeType::Directed,
            true
        )
    ).unwrap();
    graph.new_edge_group(
        &mut spouse_schema,
        EdgeAttributes::new(
            EdgeType::Undirected,
            false
        )
    ).unwrap();
    graph.new_vertex("people", data_map!{
        name: "Morgan Freeman", age: 78 as u8
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "Batman Begins", year: 2005 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "The Dark Knight", year: 2008 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "The Dark Knight Rises", year: 2012 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "Oblivion", year: 2010 as u32
    }).unwrap();
    graph.new_vertex("people", data_map!{
        name: "Jeanette Adair Bradshaw"
    }).unwrap();

}<commit_msg>check schema id to eusure they are using different state machine<commit_after>use super::start_server;
use graph;
use graph::*;
use graph::edge::*;
use graph::vertex::*;
use server::schema::{MorpheusSchema, SchemaError, EMPTY_FIELDS};
use neb::ram::schema::Field;
use neb::ram::types::{TypeId, Value, Map};

#[test]
pub fn schemas() {
    let server = start_server(4001);
    let graph = &server.graph;
    let mut edge_schema = MorpheusSchema::new(
        "test_edge_schema",
        None,
        &vec![Field::new(&"test_field", TypeId::U32 as u32, false, false, None)], false
    );
    assert_eq!(edge_schema.id, 0);
    assert!(
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new
            (
                graph::edge::EdgeType::Directed,
                false
            )).is_err());
    assert_eq!(edge_schema.id, 0);
    graph.new_edge_group(
        &mut edge_schema,
        graph::edge::EdgeAttributes::new(graph::edge::EdgeType::Directed, true)).unwrap();
    let mut vertex_schema = edge_schema.clone();
    vertex_schema.name = "test_vertex_schema".to_string();
    graph.new_vertex_group(&mut vertex_schema).unwrap();
    assert_eq!(edge_schema.id, 1);
    assert_eq!(vertex_schema.id, 2);
    let mut test_data = Map::new();
    test_data.insert("test_field", Value::U32(1));
    graph.new_vertex(&vertex_schema, test_data.clone()).unwrap();
    graph.new_vertex("test_edge_schema", test_data.clone()).is_err();
}

#[test]
pub fn relationship() {
    let server = start_server(4002);
    let graph = &server.graph;
    let mut people_schema = MorpheusSchema::new("people", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None)
    ], true);
    let mut movie_schema = MorpheusSchema::new("movie", Some(&vec!["name".to_string()]), &vec! [
        Field::new("name", TypeId::String as u32, false, false, None),
        Field::new("year", TypeId::U32 as u32, false, false, None)
    ], true);
    let mut acted_in_schema = MorpheusSchema::new("acted-in", None, &vec! [
        Field::new("role", TypeId::String as u32, false, false, None)
    ], true);
    let mut spouse_schema = MorpheusSchema::new("spouse", None, &EMPTY_FIELDS, false);
    graph.new_vertex_group(&mut people_schema).unwrap();
    graph.new_vertex_group(&mut movie_schema).unwrap();
    graph.new_edge_group(
        &mut acted_in_schema,
        EdgeAttributes::new(
            EdgeType::Directed,
            true
        )
    ).unwrap();
    graph.new_edge_group(
        &mut spouse_schema,
        EdgeAttributes::new(
            EdgeType::Undirected,
            false
        )
    ).unwrap();
    assert_eq!(people_schema.id, 1);
    assert_eq!(movie_schema.id, 2);
    assert_eq!(acted_in_schema.id, 3);
    assert_eq!(spouse_schema.id, 4);
    graph.new_vertex("people", data_map!{
        name: "Morgan Freeman", age: 78 as u8
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "Batman Begins", year: 2005 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "The Dark Knight", year: 2008 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "The Dark Knight Rises", year: 2012 as u32
    }).unwrap();
    graph.new_vertex("movie", data_map!{
        name: "Oblivion", year: 2010 as u32
    }).unwrap();
    graph.new_vertex("people", data_map!{
        name: "Jeanette Adair Bradshaw"
    }).unwrap();

}<|endoftext|>


<commit_before>use super::{start};

use std;
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};

use time::{SteadyTime, Duration};

use mio;

#[test]
fn empty_handler() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |_| {
        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn empty_subcoroutines() {
    let counter = Arc::new(Mutex::new(0i32));

    let counter_copy = counter.clone();

    start(move |mioco| {

        for _ in 0..512 {
            let counter_subcopy = counter_copy.clone();
            mioco.spawn(move |_| {
                let mut lock = counter_subcopy.lock().unwrap();
                *lock += 1;

                Ok(())
            });
        }

        let mut lock = counter_copy.lock().unwrap();
        *lock += 1;

        Ok(())
    });

    assert_eq!(*counter.lock().unwrap(), 512 + 1);
}

#[test]
fn contain_panics() {
    let finished_ok = Arc::new(Mutex::new(false));

    start(move |_| {
        panic!()
    });

    assert!(!*finished_ok.lock().unwrap());
}

#[test]
fn contain_panics_in_subcoroutines() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        for _ in 0..512 {
            mioco.spawn(|_| {
                panic!()
            });
        }

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn long_chain() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let (first_reader, first_writer) = try!(mio::unix::pipe());

        let mut prev_reader = first_reader;

        // TODO: increase after https://github.com/dpc/mioco/issues/8 is fixed
        for _ in 0..128 {
            let (reader, writer) = try!(mio::unix::pipe());

            mioco.spawn(move |mioco| {
                let mut reader = mioco.wrap(prev_reader);
                let mut writer = mioco.wrap(writer);

                let _ = std::io::copy(&mut reader, &mut writer);

                Ok(())
            });

            prev_reader = reader;
        }

        let mut first_writer = mioco.wrap(first_writer);
        let mut last_reader = mioco.wrap(prev_reader);

        for i in 0..9 {
            let test_str = format!("TeSt{}", i);
            let _ = first_writer.write_all(test_str.as_str().as_bytes());
            let mut buf = [0u8; 16];

            let _ = last_reader.read(&mut buf);

            if &buf[0..5] != test_str.as_str().as_bytes() {
                panic!();
            }
        }

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn lots_of_event_sources() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let (first_reader, first_writer) = try!(mio::unix::pipe());

        let mut prev_reader = first_reader;

        // TODO: increase after https://github.com/dpc/mioco/issues/8 is fixed
        for _ in 0..4 {
            let (reader, writer) = try!(mio::unix::pipe());

            mioco.spawn(move |mioco| {
                // This fake readers are not really used, they are just registered for the sake of
                // testing if event sources registered with high id number are handled correctly
                let mut readers = Vec::new();
                let mut writers = Vec::new();
                for _ in 0..100 {
                    let (r, w) = try!(mio::unix::pipe());
                    readers.push(mioco.wrap(r));
                    writers.push(mioco.wrap(w));
                }

                let mut reader = mioco.wrap(prev_reader);
                let mut writer = mioco.wrap(writer);

                let _ = std::io::copy(&mut reader, &mut writer);

                Ok(())
            });

            prev_reader = reader;
        }

        let mut first_writer = mioco.wrap(first_writer);
        let mut last_reader = mioco.wrap(prev_reader);

        for i in 0..9 {
            let test_str = format!("TeSt{}", i);
            let _ = first_writer.write_all(test_str.as_str().as_bytes());
            let mut buf = [0u8; 16];

            let _ = last_reader.read(&mut buf);

            if &buf[0..5] != test_str.as_str().as_bytes() {
                panic!();
            }
        }

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn timer_times_out() {
    let finished_ok_1 = Arc::new(Mutex::new(false));
    let finished_ok_2 = Arc::new(Mutex::new(false));

    let finished_ok_1_copy = finished_ok_1.clone();
    let finished_ok_2_copy = finished_ok_2.clone();
    start(move |mioco| {

        let (reader, writer) = try!(mio::unix::pipe());

        mioco.spawn(move |mioco| {
            let reader = mioco.wrap(reader);
            let timer_id = mioco.timer().id();
            mioco.timer().set_timeout(50);
            let ev = mioco.select_read_from(&[reader.id(), timer_id]);
            assert_eq!(ev.id(), timer_id);

            let mut lock = finished_ok_1_copy.lock().unwrap();
            *lock = true;
            Ok(())
        });

        mioco.spawn(move |mioco| {
            let mut writer = mioco.wrap(writer);
            let timer_id = mioco.timer().id();
            mioco.sleep(100);
            let _ = mioco.select_read_from(&[timer_id]);
            let _ = writer.write_all("test".as_bytes());

            let mut lock = finished_ok_2_copy.lock().unwrap();
            *lock = true;
            Ok(())
        });

        Ok(())
    });

    assert!(*finished_ok_1.lock().unwrap());
    assert!(*finished_ok_2.lock().unwrap());
}

#[test]
fn timer_default_timeout() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_ok_copy = finished_ok.clone();
    start(move |mioco| {

        mioco.spawn(move |mioco| {
            let timer_id = mioco.timer().id();
            let ev = mioco.select_read_from(&[timer_id]);
            assert_eq!(ev.id(), timer_id);

            let mut lock = finished_ok_copy.lock().unwrap();
            *lock = true;
            Ok(())
        });

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn sleep_takes_time() {
    let starting_time = SteadyTime::now();

    start(move |mioco| {
        mioco.sleep(500); Ok(())
    });

    assert!((SteadyTime::now() - starting_time) >= Duration::milliseconds(500));
}

#[test]
fn timer_select_takes_time() {
    let starting_time = SteadyTime::now();

    start(move |mioco| {
        let timer_id = mioco.timer().id();
        mioco.timer().set_timeout(500);
        let ev = mioco.select_read_from(&[timer_id]);
        assert_eq!(mioco.timer().id(), ev.id());
        Ok(())
    });

    assert!((SteadyTime::now() - starting_time) >= Duration::milliseconds(500));
}

#[test]
fn basic_timer_stress_test() {
    start(move |mioco| {
        for _ in 0..10 {
            for t in 0..100 {
                mioco.spawn(move |mioco| {
                    mioco.sleep(t);
                    Ok(())
                });

            }

            mioco.sleep(1);
        }
        Ok(())
    });
}

#[test]
fn exit_notifier_simple() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let notify = mioco.spawn(move |_| {
            Ok(())
        }).exit_notificator();

        let mut notify = mioco.wrap(notify);

        assert!(!notify.recv().unwrap().is_panic());

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;
        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn exit_notifier_simple_panic() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let notify = mioco.spawn(move |_| {
            panic!()
        }).exit_notificator();

        let mut notify = mioco.wrap(notify);

        assert!(notify.recv().unwrap().is_panic());

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;
        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn exit_notifier_wrap_after_finish() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let handle1 = mioco.spawn(move |_| {
            panic!()
        });

        let notify1 = handle1.exit_notificator();

        let handle2 = mioco.spawn(move |mioco| {
            let mut notify1 = mioco.wrap(notify1);
            assert!(notify1.recv().unwrap().is_panic());
            Ok(())
        });

        let notify2 = handle2.exit_notificator();
        let mut notify2 = mioco.wrap(notify2);
        assert!(!notify2.recv().unwrap().is_panic());

        let notify1 = handle1.exit_notificator();
        let mut notify1 = mioco.wrap(notify1);
        assert!(notify1.recv().unwrap().is_panic());

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;
        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}
<commit_msg>Fix a broken test.<commit_after>use super::{start};

use std;
use std::io::{Read, Write};
use std::sync::{Arc, Mutex};

use time::{SteadyTime, Duration};

use mio;

#[test]
fn empty_handler() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |_| {
        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn empty_subcoroutines() {
    let counter = Arc::new(Mutex::new(0i32));

    let counter_copy = counter.clone();

    start(move |mioco| {

        for _ in 0..512 {
            let counter_subcopy = counter_copy.clone();
            mioco.spawn(move |_| {
                let mut lock = counter_subcopy.lock().unwrap();
                *lock += 1;

                Ok(())
            });
        }

        let mut lock = counter_copy.lock().unwrap();
        *lock += 1;

        Ok(())
    });

    assert_eq!(*counter.lock().unwrap(), 512 + 1);
}

#[test]
fn contain_panics() {
    let finished_ok = Arc::new(Mutex::new(false));

    start(move |_| {
        panic!()
    });

    assert!(!*finished_ok.lock().unwrap());
}

#[test]
fn contain_panics_in_subcoroutines() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        for _ in 0..512 {
            mioco.spawn(|_| {
                panic!()
            });
        }

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn long_chain() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let (first_reader, first_writer) = try!(mio::unix::pipe());

        let mut prev_reader = first_reader;

        // TODO: increase after https://github.com/dpc/mioco/issues/8 is fixed
        for _ in 0..128 {
            let (reader, writer) = try!(mio::unix::pipe());

            mioco.spawn(move |mioco| {
                let mut reader = mioco.wrap(prev_reader);
                let mut writer = mioco.wrap(writer);

                let _ = std::io::copy(&mut reader, &mut writer);

                Ok(())
            });

            prev_reader = reader;
        }

        let mut first_writer = mioco.wrap(first_writer);
        let mut last_reader = mioco.wrap(prev_reader);

        for i in 0..9 {
            let test_str = format!("TeSt{}", i);
            let _ = first_writer.write_all(test_str.as_str().as_bytes());
            let mut buf = [0u8; 16];

            let _ = last_reader.read(&mut buf);

            if &buf[0..5] != test_str.as_str().as_bytes() {
                panic!();
            }
        }

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn lots_of_event_sources() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let (first_reader, first_writer) = try!(mio::unix::pipe());

        let mut prev_reader = first_reader;

        // TODO: increase after https://github.com/dpc/mioco/issues/8 is fixed
        for _ in 0..4 {
            let (reader, writer) = try!(mio::unix::pipe());

            mioco.spawn(move |mioco| {
                // This fake readers are not really used, they are just registered for the sake of
                // testing if event sources registered with high id number are handled correctly
                let mut readers = Vec::new();
                let mut writers = Vec::new();
                for _ in 0..100 {
                    let (r, w) = try!(mio::unix::pipe());
                    readers.push(mioco.wrap(r));
                    writers.push(mioco.wrap(w));
                }

                let mut reader = mioco.wrap(prev_reader);
                let mut writer = mioco.wrap(writer);

                let _ = std::io::copy(&mut reader, &mut writer);

                Ok(())
            });

            prev_reader = reader;
        }

        let mut first_writer = mioco.wrap(first_writer);
        let mut last_reader = mioco.wrap(prev_reader);

        for i in 0..9 {
            let test_str = format!("TeSt{}", i);
            let _ = first_writer.write_all(test_str.as_str().as_bytes());
            let mut buf = [0u8; 16];

            let _ = last_reader.read(&mut buf);

            if &buf[0..5] != test_str.as_str().as_bytes() {
                panic!();
            }
        }

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn timer_times_out() {
    let finished_ok_1 = Arc::new(Mutex::new(false));
    let finished_ok_2 = Arc::new(Mutex::new(false));

    let finished_ok_1_copy = finished_ok_1.clone();
    let finished_ok_2_copy = finished_ok_2.clone();
    start(move |mioco| {

        let (reader, writer) = try!(mio::unix::pipe());

        mioco.spawn(move |mioco| {
            let reader = mioco.wrap(reader);
            let timer_id = mioco.timer().id();
            mioco.timer().set_timeout(50);
            let ev = mioco.select_read_from(&[reader.id(), timer_id]);
            assert_eq!(ev.id(), timer_id);

            let mut lock = finished_ok_1_copy.lock().unwrap();
            *lock = true;
            Ok(())
        });

        mioco.spawn(move |mioco| {
            let mut writer = mioco.wrap(writer);
            mioco.sleep(100);
            let _ = writer.write_all("test".as_bytes());

            let mut lock = finished_ok_2_copy.lock().unwrap();
            *lock = true;
            Ok(())
        });

        Ok(())
    });

    assert!(*finished_ok_1.lock().unwrap());
    assert!(*finished_ok_2.lock().unwrap());
}

#[test]
fn timer_default_timeout() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_ok_copy = finished_ok.clone();
    start(move |mioco| {

        mioco.spawn(move |mioco| {
            let timer_id = mioco.timer().id();
            let ev = mioco.select_read_from(&[timer_id]);
            assert_eq!(ev.id(), timer_id);

            let mut lock = finished_ok_copy.lock().unwrap();
            *lock = true;
            Ok(())
        });

        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn sleep_takes_time() {
    let starting_time = SteadyTime::now();

    start(move |mioco| {
        mioco.sleep(500); Ok(())
    });

    assert!((SteadyTime::now() - starting_time) >= Duration::milliseconds(500));
}

#[test]
fn timer_select_takes_time() {
    let starting_time = SteadyTime::now();

    start(move |mioco| {
        let timer_id = mioco.timer().id();
        mioco.timer().set_timeout(500);
        let ev = mioco.select_read_from(&[timer_id]);
        assert_eq!(mioco.timer().id(), ev.id());
        Ok(())
    });

    assert!((SteadyTime::now() - starting_time) >= Duration::milliseconds(500));
}

#[test]
fn basic_timer_stress_test() {
    start(move |mioco| {
        for _ in 0..10 {
            for t in 0..100 {
                mioco.spawn(move |mioco| {
                    mioco.sleep(t);
                    Ok(())
                });

            }

            mioco.sleep(1);
        }
        Ok(())
    });
}

#[test]
fn exit_notifier_simple() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let notify = mioco.spawn(move |_| {
            Ok(())
        }).exit_notificator();

        let mut notify = mioco.wrap(notify);

        assert!(!notify.recv().unwrap().is_panic());

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;
        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn exit_notifier_simple_panic() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let notify = mioco.spawn(move |_| {
            panic!()
        }).exit_notificator();

        let mut notify = mioco.wrap(notify);

        assert!(notify.recv().unwrap().is_panic());

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;
        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}

#[test]
fn exit_notifier_wrap_after_finish() {
    let finished_ok = Arc::new(Mutex::new(false));

    let finished_copy = finished_ok.clone();
    start(move |mioco| {

        let handle1 = mioco.spawn(move |_| {
            panic!()
        });

        let notify1 = handle1.exit_notificator();

        let handle2 = mioco.spawn(move |mioco| {
            let mut notify1 = mioco.wrap(notify1);
            assert!(notify1.recv().unwrap().is_panic());
            Ok(())
        });

        let notify2 = handle2.exit_notificator();
        let mut notify2 = mioco.wrap(notify2);
        assert!(!notify2.recv().unwrap().is_panic());

        let notify1 = handle1.exit_notificator();
        let mut notify1 = mioco.wrap(notify1);
        assert!(notify1.recv().unwrap().is_panic());

        let mut lock = finished_copy.lock().unwrap();
        *lock = true;
        Ok(())
    });

    assert!(*finished_ok.lock().unwrap());
}
<|endoftext|>


<commit_before>use std::vec;
use naulang::objectspace::primitives::{Object};

#[derive(Clone)]
pub struct Frame {
	stack: vec::Vec<Object>,
	stack_pointer: u32,
	previous_frame: Option<Box<Frame>>,
	access_link: Option<Box<Frame>>,
	pc: u32,
	locals: vec::Vec<Object>,
}

impl Frame {
	pub fn new(stack_size: u32, local_count: u32) -> Box<Frame> {
		let mut new_frame = Frame {
			stack: vec::Vec::new(),
			stack_pointer: 0,
			pc: 0,
			access_link: Option::None,
			previous_frame: Option::None,
			locals: vec::Vec::new()
		};

		for x in 0..local_count {
			new_frame.locals.push(Object::None);
		}

		return Box::new(new_frame);
	}

	pub fn pop(&mut self) -> Option<Object> {
		self.stack.pop()
	}

	pub fn push(&mut self, object: Object) -> () {
		self.stack.push(object);
	}

	pub fn set_local_at(&mut self, index: usize, object: Object) -> () {
		self.locals[index] = object;
	}

	pub fn get_local_at(&self, index: usize) -> Option<Object> {
		if index >= self.locals.len() || index < 0 {
			Option::None
		} else {
			Option::Some(self.locals[index].clone())
		}
	}
}

#[cfg(test)]
mod tests {
	use super::Frame;
	use naulang::objectspace::primitives::{Object,IntegerObject};

	fn extract_primitive_integer(o: Option<Object>, default: i32) -> i32 {
		match o {
			Some(object) => match object {
				Object::Integer(i_obj) => i_obj.get_value(),
				_ => default,
			},
			None => default
		}
	}

	#[test]
	fn test_set_get_local_at() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.set_local_at(0, Object::Integer(integer_object));
		let local = frame.get_local_at(0);
		let internal_value = extract_primitive_integer(local, 0);

		assert!(internal_value == 42);
	}

	#[test]
	fn test_push_pop() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.push(Object::Integer(integer_object));
		let popped_object = frame.pop();
		let internal_value = extract_primitive_integer(popped_object, 0);

		assert!(internal_value == 42);
	}
}
<commit_msg>Add 'peek' returning an 'Option<&Object>' (borrowed Object) and test for it<commit_after>use std::vec;
use naulang::objectspace::primitives::{Object};

#[derive(Clone)]
pub struct Frame {
	stack: vec::Vec<Object>,
	stack_pointer: u32,
	previous_frame: Option<Box<Frame>>,
	access_link: Option<Box<Frame>>,
	pc: u32,
	locals: vec::Vec<Object>,
}

impl Frame {
	pub fn new(stack_size: u32, local_count: u32) -> Box<Frame> {
		let mut new_frame = Frame {
			stack: vec::Vec::new(),
			stack_pointer: 0,
			pc: 0,
			access_link: Option::None,
			previous_frame: Option::None,
			locals: vec::Vec::new()
		};

		for x in 0..local_count {
			new_frame.locals.push(Object::None);
		}

		return Box::new(new_frame);
	}

	pub fn pop(&mut self) -> Option<Object> {
		self.stack.pop()
	}

	pub fn push(&mut self, object: Object) -> () {
		self.stack.push(object);
	}

	pub fn peek(&self) -> Option<&Object> {
		let stack_top = self.stack.len() - 1;
		self.stack.get(stack_top)
	}

	pub fn stack_height(&self) -> usize {
		self.stack.len()
	}

	pub fn set_local_at(&mut self, index: usize, object: Object) -> () {
		self.locals[index] = object;
	}

	pub fn get_local_at(&self, index: usize) -> Option<&Object> {
		self.locals.get(index)
	}
}

#[cfg(test)]
mod tests {
	use super::Frame;
	use naulang::objectspace::primitives::{Object,IntegerObject};

	fn extract_referenced_primitive_integer(o: Option<&Object>, default: i32) -> i32 {
		match o {
			Some(object) => match *object {
				Object::Integer(ref i_obj) => i_obj.get_value(),
				_ => default,
			},
			None => default
		}
	}

	fn extract_primitive_integer(o: Option<Object>, default: i32) -> i32 {
		match o {
			Some(object) => extract_referenced_primitive_integer(Some(&object), default),
			None => default
		}
	}

	#[test]
	fn test_set_get_local_at() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.set_local_at(0, Object::Integer(integer_object));
		let local = frame.get_local_at(0);
		let internal_value = extract_referenced_primitive_integer(local, 0);

		assert!(internal_value == 42);
	}

	#[test]
	fn test_push_peek_pop() {
		let mut frame = Frame::new(3, 1);
		let integer_object = IntegerObject::new(42);
		frame.push(Object::Integer(integer_object));

		assert!(frame.stack_height() == 1);

		// Scoped so the lifetime of borrowed peeked_object is controlled here
		{
			let peeked_object = frame.peek();
			let peeked_value = extract_referenced_primitive_integer(peeked_object, 0);
			assert!(peeked_value == 42);
			assert!(frame.stack_height() == 1);
		}

		let popped_object = frame.pop();
		let popped_value = extract_primitive_integer(popped_object, 0);

		assert!(popped_value == 42);
		assert!(frame.stack_height() == 0);

	}
}
<|endoftext|>


<commit_before>
use ::TryInto;

use std::fmt;

/// Parses a String into a Value, first attempting bool, i64, and f64.
///
/// Examples:
/// ```
/// match parse_into_value("32.3") {
///     Value::Float(f) => println!("value is float: {}", f),
///     _ => panic!("it's broke yo"),
/// }
///
/// match parse_into_value("something silly") {
///     Value::String(s) => println!("none of the above: {}", s),
///     _ => panic!("it's really broke yo")
/// }
/// ```
pub fn parse_into_value(into: String) -> Value {
    match into.parse::<bool>() {
        Ok(b) => return Value::Bool(b),
        Err(_) => {},
    }

    match into.parse::<i64>() {
        Ok(i) => return Value::Integer(i),
        Err(_) => {},
    }

    match into.parse::<f64>() {
        Ok(f) => return Value::Float(f),
        Err(_) => {},
    }

    Value::String(into)
}

#[derive(Debug, PartialEq, Clone)]
/// Wrapper type for possible types in nccl configuration.
pub enum Value {
    String(String),
    Bool(bool),
    Integer(i64),
    Float(f64),
}

impl Value {
    fn into_string(self) -> Result<String, ()> {
        match self {
            Value::String(s) => Ok(s),
            _ => Err(())
        }
    }

    fn into_bool(self) -> Result<bool, ()> {
        match self {
            Value::Bool(b) => Ok(b),
            _ => Err(())
        }
    }

    fn into_integer(self) -> Result<i64, ()> {
        match self {
            Value::Integer(i) => Ok(i),
            _ => Err(())
        }
    }

    fn into_float(self) -> Result<f64, ()> {
        match self {
            Value::Float(f) => Ok(f),
            _ => Err(())
        }
    }
}

impl TryInto<String> for Value {
    type Error = ();
    fn try_into(self) -> Result<String, Self::Error> {
        self.into_string()
    }
}

impl TryInto<bool> for Value {
    type Error = ();
    fn try_into(self) -> Result<bool, Self::Error> {
        self.into_bool()
    }
}

impl TryInto<i64> for Value {
    type Error = ();
    fn try_into(self) -> Result<i64, Self::Error> {
        self.into_integer()
    }
}

impl TryInto<f64> for Value {
    type Error = ();
    fn try_into(self) -> Result<f64, Self::Error> {
        self.into_float()
    }
}

impl<'a> From<&'a Value> for Value {
    fn from(v: &'a Value) -> Self {
        v.clone()
    }
}

impl From<String> for Value {
    fn from(s: String) -> Self {
        Value::String(s)
    }
}

impl<'a> From<&'a String> for Value {
    fn from(s: &'a String) -> Self {
        Value::String(s.to_owned())
    }
}

impl<'a> From<&'a str> for Value {
    fn from(s: &'a str) -> Self {
        Value::String(s.to_owned())
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Self {
        Value::Bool(b)
    }
}

impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Value::Integer(i)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Value::Float(f)
    }
}

impl Into<String> for Value {
    fn into(self) -> String {
        self.into_string().unwrap()
    }
}

impl Into<bool> for Value {
    fn into(self) -> bool {
        self.into_bool().unwrap()
    }
}

impl Into<i64> for Value {
    fn into(self) -> i64 {
        self.into_integer().unwrap()
    }
}

impl Into<f64> for Value {
    fn into(self) -> f64 {
        self.into_float().unwrap()
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

<commit_msg>update Display impl for Value<commit_after>
use ::TryInto;

use std::fmt;

/// Parses a String into a Value, first attempting bool, i64, and f64.
///
/// Examples:
/// ```
/// match parse_into_value("32.3") {
///     Value::Float(f) => println!("value is float: {}", f),
///     _ => panic!("it's broke yo"),
/// }
///
/// match parse_into_value("something silly") {
///     Value::String(s) => println!("none of the above: {}", s),
///     _ => panic!("it's really broke yo")
/// }
/// ```
pub fn parse_into_value(into: String) -> Value {
    match into.parse::<bool>() {
        Ok(b) => return Value::Bool(b),
        Err(_) => {},
    }

    match into.parse::<i64>() {
        Ok(i) => return Value::Integer(i),
        Err(_) => {},
    }

    match into.parse::<f64>() {
        Ok(f) => return Value::Float(f),
        Err(_) => {},
    }

    Value::String(into)
}

#[derive(Debug, PartialEq, Clone)]
/// Wrapper type for possible types in nccl configuration.
pub enum Value {
    String(String),
    Bool(bool),
    Integer(i64),
    Float(f64),
}

impl Value {
    fn into_string(self) -> Result<String, ()> {
        match self {
            Value::String(s) => Ok(s),
            _ => Err(())
        }
    }

    fn into_bool(self) -> Result<bool, ()> {
        match self {
            Value::Bool(b) => Ok(b),
            _ => Err(())
        }
    }

    fn into_integer(self) -> Result<i64, ()> {
        match self {
            Value::Integer(i) => Ok(i),
            _ => Err(())
        }
    }

    fn into_float(self) -> Result<f64, ()> {
        match self {
            Value::Float(f) => Ok(f),
            _ => Err(())
        }
    }
}

impl TryInto<String> for Value {
    type Error = ();
    fn try_into(self) -> Result<String, Self::Error> {
        self.into_string()
    }
}

impl TryInto<bool> for Value {
    type Error = ();
    fn try_into(self) -> Result<bool, Self::Error> {
        self.into_bool()
    }
}

impl TryInto<i64> for Value {
    type Error = ();
    fn try_into(self) -> Result<i64, Self::Error> {
        self.into_integer()
    }
}

impl TryInto<f64> for Value {
    type Error = ();
    fn try_into(self) -> Result<f64, Self::Error> {
        self.into_float()
    }
}

impl<'a> From<&'a Value> for Value {
    fn from(v: &'a Value) -> Self {
        v.clone()
    }
}

impl From<String> for Value {
    fn from(s: String) -> Self {
        Value::String(s)
    }
}

impl<'a> From<&'a String> for Value {
    fn from(s: &'a String) -> Self {
        Value::String(s.to_owned())
    }
}

impl<'a> From<&'a str> for Value {
    fn from(s: &'a str) -> Self {
        Value::String(s.to_owned())
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Self {
        Value::Bool(b)
    }
}

impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Value::Integer(i)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Value::Float(f)
    }
}

impl Into<String> for Value {
    fn into(self) -> String {
        self.into_string().unwrap()
    }
}

impl Into<bool> for Value {
    fn into(self) -> bool {
        self.into_bool().unwrap()
    }
}

impl Into<i64> for Value {
    fn into(self) -> i64 {
        self.into_integer().unwrap()
    }
}

impl Into<f64> for Value {
    fn into(self) -> f64 {
        self.into_float().unwrap()
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Value::Bool(b) => write!(f, "{}", b),
            &Value::String(ref s) => write!(f, "{}", s),
            &Value::Float(fl) => write!(f, "{}", fl),
            &Value::Integer(i) => write!(f, "{}", i),
        }
    }
}

<|endoftext|>