<commit_before>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

static REVISION: &'static str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);
    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = Path::new("tests/rust").join(relative);
        entry.unpack(&out)?;
    }
    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Remove existing tests/rust dir before unpacking<commit_after>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

static REVISION: &'static str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<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_stream(mut stream: &mut BufferedStream<TcpStream>) -> Message {
        let cur_byte: u8 = stream.read_byte().unwrap();

        let fin = cur_byte & 0b1000_0000;
        let rsv = cur_byte & 0b0111_0000;
        let opc = cur_byte & 0b0000_1111;
        let msk = cur_byte & 0b0000_0001;

        let cur_byte: u8 = stream.read_byte().unwrap();
        let len = (cur_byte & 0b0111_1111) as uint;

        let mskkey = stream.read_exact(4).unwrap();

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let cur_byte: u8 = stream.read_byte().unwrap();
            let ch = mskkey[ii % 4] ^ cur_byte;
            msg.push(ch);
        }

        let utf8_msg = match String::from_utf8(msg) {
            Ok(m) => m,
            Err(_) => panic!("I don't know how to ut8 that")
        };

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}",
            fin, rsv, msk, opc, len, mskkey, utf8_msg);

        let payload = Payload::Text(utf8_msg);
        return Message::from_payload(payload, fin);
    }

    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 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);
    msg.send(&mut stream);

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

    println!("done sending");

    Message::from_stream(&mut stream);

    let echo_msg = Message::from_stream(&mut stream);

    echo_msg.send(&mut stream);

    echo_msg.send(&mut stream);

    /*
    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>remove from_buffer dead_code<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_stream(mut stream: &mut BufferedStream<TcpStream>) -> Message {
        let cur_byte: u8 = stream.read_byte().unwrap();

        let fin = cur_byte & 0b1000_0000;
        let rsv = cur_byte & 0b0111_0000;
        let opc = cur_byte & 0b0000_1111;
        let msk = cur_byte & 0b0000_0001;

        let cur_byte: u8 = stream.read_byte().unwrap();
        let len = (cur_byte & 0b0111_1111) as uint;

        let mskkey = stream.read_exact(4).unwrap();

        let mut msg = Vec::new();
        for ii in range(0u, len) {
            let cur_byte: u8 = stream.read_byte().unwrap();
            let ch = mskkey[ii % 4] ^ cur_byte;
            msg.push(ch);
        }

        let utf8_msg = match String::from_utf8(msg) {
            Ok(m) => m,
            Err(_) => panic!("I don't know how to ut8 that")
        };

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, msg {}",
            fin, rsv, msk, opc, len, mskkey, utf8_msg);

        let payload = Payload::Text(utf8_msg);
        return Message::from_payload(payload, fin);
    }

}

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);
    msg.send(&mut stream);

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

    println!("done sending");

    Message::from_stream(&mut stream);

    let echo_msg = Message::from_stream(&mut stream);

    echo_msg.send(&mut stream);

    echo_msg.send(&mut stream);

}

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>pub struct Export {
    pub name: String,
    pub func: String,
}

pub enum Expr {
    Add(Typ,Box<Expr>,Box<Expr>),
    Return(usize),
}

pub struct Function {
    pub name: String,
    pub params: Vec<Var>,
    pub result: Option<Typ>,
    pub locals: Vec<Var>,
    pub body: Vec<Expr>,
}

pub struct Import {
    pub func: String,
    pub module: String,
    pub name: String,
}

pub struct Memory {
    pub init: usize,
    pub max: Option<usize>,
    pub segments: Vec<Segment>,
}

pub struct Module {
    pub memory: Option<Memory>,
    pub imports: Vec<Import>,
    pub exports: Vec<Export>,
    pub functions: Vec<Function>,
}

pub struct Segment {
    pub addr: usize,
    pub data: String,
}

pub enum Typ {
    I32,
    I64,
    F32,
    F64,
}

pub struct Var {
    pub name: String,
    pub typ: Typ,
}
<commit_msg>Added derived traits to AST types.<commit_after>#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Export {
    pub name: String,
    pub func: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Expr {
    Add(Typ,Box<Expr>,Box<Expr>),
    Return(usize),
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Function {
    pub name: String,
    pub params: Vec<Var>,
    pub result: Option<Typ>,
    pub locals: Vec<Var>,
    pub body: Vec<Expr>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Import {
    pub func: String,
    pub module: String,
    pub name: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Memory {
    pub init: usize,
    pub max: Option<usize>,
    pub segments: Vec<Segment>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Module {
    pub memory: Option<Memory>,
    pub imports: Vec<Import>,
    pub exports: Vec<Export>,
    pub functions: Vec<Function>,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Segment {
    pub addr: usize,
    pub data: String,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum Typ {
    I32,
    I64,
    F32,
    F64,
}

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub struct Var {
    pub name: String,
    pub typ: Typ,
}
<|endoftext|>


<commit_before>use ffmpeg_sys;
use libc::*;
use std::cmp;
use std::ffi::{ CStr, CString };
use std::ops::Deref;
use std::ptr;

use errors::*;

#[derive(Debug, Clone, Copy)]
pub struct Rational {
    pub numerator: i32,
    pub denominator: i32,
}

#[derive(Clone, Copy)]
pub struct Codec {
    ptr: *mut ffmpeg_sys::AVCodec,
}

unsafe impl Send for Codec {}
unsafe impl Sync for Codec {}

pub struct PixelFormats {
    codec: Codec,
    index: isize,
}

pub struct Context {
    // The Codec which was used to initialize this Context.
    codec: Codec,
    ptr: *mut ffmpeg_sys::AVCodecContext,
}

pub struct OpenContext {
    context: Context,
}

pub struct Frame {
    ptr: *mut ffmpeg_sys::AVFrame,
}

impl From<(i32, i32)> for Rational {
    fn from((numerator, denominator): (i32, i32)) -> Self {
        Self {
            numerator,
            denominator,
        }
    }
}

impl From<ffmpeg_sys::AVRational> for Rational {
    fn from(rational: ffmpeg_sys::AVRational) -> Self {
        Self {
            numerator: rational.num,
            denominator: rational.den,
        }
    }
}

impl From<Rational> for ffmpeg_sys::AVRational {
    fn from(rational: Rational) -> Self {
        Self {
            num: rational.numerator,
            den: rational.denominator,
        }
    }
}

impl Codec {
    pub fn description(self) -> String {
        unsafe {
            CStr::from_ptr((*self.ptr).long_name).to_string_lossy().into_owned()
        }
    }

    #[inline]
    pub fn kind(self) -> ffmpeg_sys::AVMediaType {
        unsafe {
            (*self.ptr).kind
        }
    }

    #[inline]
    pub fn is_video(self) -> bool {
        self.kind() == ffmpeg_sys::AVMediaType::AVMEDIA_TYPE_VIDEO
    }

    pub fn pixel_formats(self) -> Option<PixelFormats> {
        unsafe {
            if (*self.ptr).pix_fmts.is_null() {
                None
            } else {
                Some(PixelFormats::new(self))
            }
        }
    }

    pub fn context(self) -> Result<Context> {
        let ptr = unsafe {
            ffmpeg_sys::avcodec_alloc_context3(self.ptr)
        };

        ensure!(!ptr.is_null(), "unable to allocate the codec context");

        Ok(Context {
            codec: self,
            ptr,
        })
    }
}

impl PixelFormats {
    fn new(codec: Codec) -> Self {
        Self {
            codec,
            index: 0,
        }
    }
}

impl Iterator for PixelFormats {
    type Item = ffmpeg_sys::AVPixelFormat;

    fn next(&mut self) -> Option<Self::Item> {
        let format = unsafe {
            *(*self.codec.ptr).pix_fmts.offset(self.index)
        };

        if format == ffmpeg_sys::AVPixelFormat::AV_PIX_FMT_NONE {
            None
        } else {
            self.index += 1;
            Some(format)
        }
    }
}

impl Context {
    #[inline]
    pub fn width(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).width) as u32
        }
    }

    #[inline]
    pub fn set_width(&mut self, width: u32) {
        unsafe {
            (*self.ptr).width = cmp::min(width, c_int::max_value() as u32) as c_int;
        }
    }

    #[inline]
    pub fn height(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).height) as u32
        }
    }

    #[inline]
    pub fn set_height(&mut self, height: u32) {
        unsafe {
            (*self.ptr).height = cmp::min(height, c_int::max_value() as u32) as c_int;
        }
    }

    #[inline]
    pub fn time_base(&self) -> Rational {
        unsafe {
            (*self.ptr).time_base.into()
        }
    }

    #[inline]
    pub fn set_time_base(&mut self, time_base: &Rational) {
        unsafe {
            (*self.ptr).time_base = (*time_base).into();
        }
    }

    #[inline]
    pub fn pixel_format(&self) -> ffmpeg_sys::AVPixelFormat {
        unsafe {
            (*self.ptr).pix_fmt
        }
    }

    #[inline]
    pub fn set_pixel_format(&mut self, pixel_format: ffmpeg_sys::AVPixelFormat) {
        unsafe {
            (*self.ptr).pix_fmt = pixel_format;
        }
    }

    pub fn open(self) -> Result<OpenContext> {
        let rv = unsafe {
            ffmpeg_sys::avcodec_open2(self.ptr, self.codec.ptr, ptr::null_mut())
        };

        ensure!(rv == 0, "error opening context");

        Ok(OpenContext { context: self })
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            ffmpeg_sys::avcodec_free_context(&mut self.ptr);
        }
    }
}

impl Drop for Frame {
    fn drop(&mut self) {
        unsafe {
            ffmpeg_sys::av_frame_free(&mut self.ptr);
        }
    }
}

pub fn initialize() {
    unsafe {
        ffmpeg_sys::avcodec_register_all();
    }
}

pub fn find_encoder_by_name(name: &str) -> Result<Option<Codec>> {
    let name = CString::new(name).chain_err(|| "could not convert name to CString")?;

    let codec = unsafe {
        ffmpeg_sys::avcodec_find_encoder_by_name(name.as_ptr())
    };

    if codec.is_null() {
        Ok(None)
    } else {
        Ok(Some(Codec { ptr: codec }))
    }
}
<commit_msg>Init AVFormat<commit_after>use ffmpeg_sys;
use libc::*;
use std::cmp;
use std::ffi::{ CStr, CString };
use std::ops::Deref;
use std::ptr;

use errors::*;

#[derive(Debug, Clone, Copy)]
pub struct Rational {
    pub numerator: i32,
    pub denominator: i32,
}

#[derive(Clone, Copy)]
pub struct Codec {
    ptr: *mut ffmpeg_sys::AVCodec,
}

unsafe impl Send for Codec {}
unsafe impl Sync for Codec {}

pub struct PixelFormats {
    codec: Codec,
    index: isize,
}

pub struct Context {
    // The Codec which was used to initialize this Context.
    codec: Codec,
    ptr: *mut ffmpeg_sys::AVCodecContext,
}

pub struct OpenContext {
    context: Context,
}

pub struct Frame {
    ptr: *mut ffmpeg_sys::AVFrame,
}

impl From<(i32, i32)> for Rational {
    fn from((numerator, denominator): (i32, i32)) -> Self {
        Self {
            numerator,
            denominator,
        }
    }
}

impl From<ffmpeg_sys::AVRational> for Rational {
    fn from(rational: ffmpeg_sys::AVRational) -> Self {
        Self {
            numerator: rational.num,
            denominator: rational.den,
        }
    }
}

impl From<Rational> for ffmpeg_sys::AVRational {
    fn from(rational: Rational) -> Self {
        Self {
            num: rational.numerator,
            den: rational.denominator,
        }
    }
}

impl Codec {
    pub fn description(self) -> String {
        unsafe {
            CStr::from_ptr((*self.ptr).long_name).to_string_lossy().into_owned()
        }
    }

    #[inline]
    pub fn kind(self) -> ffmpeg_sys::AVMediaType {
        unsafe {
            (*self.ptr).kind
        }
    }

    #[inline]
    pub fn is_video(self) -> bool {
        self.kind() == ffmpeg_sys::AVMediaType::AVMEDIA_TYPE_VIDEO
    }

    pub fn pixel_formats(self) -> Option<PixelFormats> {
        unsafe {
            if (*self.ptr).pix_fmts.is_null() {
                None
            } else {
                Some(PixelFormats::new(self))
            }
        }
    }

    pub fn context(self) -> Result<Context> {
        let ptr = unsafe {
            ffmpeg_sys::avcodec_alloc_context3(self.ptr)
        };

        ensure!(!ptr.is_null(), "unable to allocate the codec context");

        Ok(Context {
            codec: self,
            ptr,
        })
    }
}

impl PixelFormats {
    fn new(codec: Codec) -> Self {
        Self {
            codec,
            index: 0,
        }
    }
}

impl Iterator for PixelFormats {
    type Item = ffmpeg_sys::AVPixelFormat;

    fn next(&mut self) -> Option<Self::Item> {
        let format = unsafe {
            *(*self.codec.ptr).pix_fmts.offset(self.index)
        };

        if format == ffmpeg_sys::AVPixelFormat::AV_PIX_FMT_NONE {
            None
        } else {
            self.index += 1;
            Some(format)
        }
    }
}

impl Context {
    #[inline]
    pub fn width(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).width) as u32
        }
    }

    #[inline]
    pub fn set_width(&mut self, width: u32) {
        unsafe {
            (*self.ptr).width = cmp::min(width, c_int::max_value() as u32) as c_int;
        }
    }

    #[inline]
    pub fn height(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).height) as u32
        }
    }

    #[inline]
    pub fn set_height(&mut self, height: u32) {
        unsafe {
            (*self.ptr).height = cmp::min(height, c_int::max_value() as u32) as c_int;
        }
    }

    #[inline]
    pub fn time_base(&self) -> Rational {
        unsafe {
            (*self.ptr).time_base.into()
        }
    }

    #[inline]
    pub fn set_time_base(&mut self, time_base: &Rational) {
        unsafe {
            (*self.ptr).time_base = (*time_base).into();
        }
    }

    #[inline]
    pub fn pixel_format(&self) -> ffmpeg_sys::AVPixelFormat {
        unsafe {
            (*self.ptr).pix_fmt
        }
    }

    #[inline]
    pub fn set_pixel_format(&mut self, pixel_format: ffmpeg_sys::AVPixelFormat) {
        unsafe {
            (*self.ptr).pix_fmt = pixel_format;
        }
    }

    pub fn open(self) -> Result<OpenContext> {
        let rv = unsafe {
            ffmpeg_sys::avcodec_open2(self.ptr, self.codec.ptr, ptr::null_mut())
        };

        ensure!(rv == 0, "error opening context");

        Ok(OpenContext { context: self })
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            ffmpeg_sys::avcodec_free_context(&mut self.ptr);
        }
    }
}

impl Drop for Frame {
    fn drop(&mut self) {
        unsafe {
            ffmpeg_sys::av_frame_free(&mut self.ptr);
        }
    }
}

pub fn initialize() {
    unsafe {
        ffmpeg_sys::av_register_all();
        ffmpeg_sys::avcodec_register_all();
    }
}

pub fn find_encoder_by_name(name: &str) -> Result<Option<Codec>> {
    let name = CString::new(name).chain_err(|| "could not convert name to CString")?;

    let codec = unsafe {
        ffmpeg_sys::avcodec_find_encoder_by_name(name.as_ptr())
    };

    if codec.is_null() {
        Ok(None)
    } else {
        Ok(Some(Codec { ptr: codec }))
    }
}
<|endoftext|>


<commit_before>//!
//! Raw communication channel to the FUSE kernel driver.
//!

use std::{ffi, os};
use std::ffi::CString;
use std::old_path::PosixPath;
use libc::{c_int, c_void, size_t};
use fuse::{fuse_args, fuse_mount_compat25, fuse_unmount_compat22};

// Libc provides iovec based I/O using readv and writev functions
#[allow(dead_code, non_camel_case_types)]
mod libc {
    use libc::{c_char, c_int, c_void, size_t, ssize_t};

    /// Iovec data structure for readv and writev calls.
    #[repr(C)]
    pub struct iovec {
        pub iov_base: *const c_void,
        pub iov_len: size_t,
    }

    extern "system" {
        /// Read data from fd into multiple buffers
        pub fn readv (fd: c_int, iov: *mut iovec, iovcnt: c_int) -> ssize_t;
        /// Write data from multiple buffers to fd
        pub fn writev (fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t;

        pub fn realpath (file_name: *const c_char, resolved_name: *mut c_char) -> *const c_char;

        pub fn unmount(dir: *const c_char, flags: c_int) -> c_int;
    }

    /// Max length for path names. 4096 should be reasonable safe (OS X uses 1024, Linux uses 4096)
    pub const PATH_MAX: usize = 4096;
}

/// Wrapper around libc's realpath.  Returns the errno value if the real path cannot be obtained.
/// FIXME: Use Rust's realpath method once available in std (see also https://github.com/mozilla/rust/issues/11857)
fn real_path (path: &PosixPath) -> Result<PosixPath, c_int> {
    let cpath = CString::from_slice(path.as_vec());
    let mut resolved = [0; libc::PATH_MAX];
    unsafe {
        if libc::realpath(cpath.as_ptr(), resolved.as_mut_ptr()).is_null() {
            Err(os::errno() as c_int)
        } else {
            Ok(PosixPath::new(ffi::c_str_to_bytes(&resolved.as_ptr())))
        }
    }
}

/// Helper function to provide options as a fuse_args struct
/// (which contains an argc count and an argv pointer)
fn with_fuse_args<T, F: FnOnce(&fuse_args) -> T> (options: &[&[u8]], f: F) -> T {
    let args: Vec<CString> = Some(b"rust-fuse").iter().chain(options.iter()).map(|s| CString::from_slice(s)).collect();
    let argptrs: Vec<*const i8> = args.iter().map(|s| s.as_ptr()).collect();
    f(&fuse_args { argc: argptrs.len() as i32, argv: argptrs.as_ptr(), allocated: 0 })
}

/// A raw communication channel to the FUSE kernel driver
pub struct Channel {
    mountpoint: Path,
    fd: c_int,
}

impl Channel {
    /// Create a new communication channel to the kernel driver by mounting the
    /// given path. The kernel driver will delegate filesystem operations of
    /// the given path to the channel. If the channel is dropped, the path is
    /// unmounted.
    pub fn new (mountpoint: &Path, options: &[&[u8]]) -> Result<Channel, c_int> {
        real_path(mountpoint).and_then(|mountpoint| {
            with_fuse_args(options, |args| {
                let mnt = CString::from_slice(mountpoint.as_vec()).as_ptr();
                let fd = unsafe { fuse_mount_compat25(mnt, args) };
                if fd < 0 {
                    Err(os::errno() as c_int)
                } else {
                    Ok(Channel { mountpoint: mountpoint.clone(), fd: fd })
                }
            })
        })
    }

    /// Receives data up to the capacity of the given buffer (can block).
    pub fn receive (&self, buffer: &mut Vec<u8>) -> Result<(), c_int> {
        let rc = unsafe { ::libc::read(self.fd, buffer.as_ptr() as *mut c_void, buffer.capacity() as size_t) };
        if rc < 0 {
            Err(os::errno() as c_int)
        } else {
            unsafe { buffer.set_len(rc as usize); }
            Ok(())
        }
    }

    /// Returns a sender object for this channel. The sender object can be
    /// used to send to the channel. Multiple sender objects can be used
    /// and they can safely be sent to other threads.
    pub fn sender (&self) -> ChannelSender {
        // Since write/writev syscalls are threadsafe, we can simply create
        // a sender by using the same fd and use it in other threads. Only
        // the channel closes the fd when dropped. If any sender is used after
        // dropping the channel, it'll return an EBADF error.
        ChannelSender { fd: self.fd }
    }
}

impl Drop for Channel {
    fn drop (&mut self) {
        // TODO: send ioctl FUSEDEVIOCSETDAEMONDEAD on OS X before closing the fd
        // Close the communication channel to the kernel driver
        // (closing it before unnmount prevents sync unmount deadlock)
        unsafe { ::libc::close(self.fd); }
        // Unmount this channel's mount point
        unmount(&self.mountpoint);
    }
}

#[derive(Copy)]
pub struct ChannelSender {
    fd: c_int,
}

impl ChannelSender {
    /// Send all data in the slice of slice of bytes in a single write (can block).
    pub fn send (&self, buffer: &[&[u8]]) -> Result<(), c_int> {
        let iovecs: Vec<libc::iovec> = buffer.iter().map(|d| {
            libc::iovec { iov_base: d.as_ptr() as *const c_void, iov_len: d.len() as size_t }
        }).collect();
        let rc = unsafe { libc::writev(self.fd, iovecs.as_ptr(), iovecs.len() as c_int) };
        if rc < 0 {
            Err(os::errno() as c_int)
        } else {
            Ok(())
        }
    }
}

/// Unmount an arbitrary mount point
pub fn unmount (mountpoint: &Path) {
    // On OS X, fuse_unmount_compat22 attempts to call realpath, which in turn calls into the filesystem.
    // If the filesystem returns an error, the unmount does not take place, with no indication of the error
    // available to the caller.  So we call unmount directly, which is what osxfuse does anyway, since
    // we already converted to the real path when we first mounted.
    let mnt = CString::from_slice(mountpoint.as_vec()).as_ptr();
    if cfg!(target_os = "macos") {
        unsafe { libc::unmount(mnt, 0); }
    } else {
        unsafe { fuse_unmount_compat22(mnt); }
    }
}

#[cfg(test)]
mod test {
    use super::with_fuse_args;
    use std::ffi;

    #[test]
    fn fuse_args () {
        with_fuse_args(&[b"foo", b"bar"], |args| {
            assert!(args.argc == 3);
            assert_eq!(unsafe { ffi::c_str_to_bytes(&*args.argv.offset(0)) }, b"rust-fuse");
            assert_eq!(unsafe { ffi::c_str_to_bytes(&*args.argv.offset(1)) }, b"foo");
            assert_eq!(unsafe { ffi::c_str_to_bytes(&*args.argv.offset(2)) }, b"bar");
        });
    }
}
<commit_msg>Use i32 for errno values like os:errno() does<commit_after>//!
//! Raw communication channel to the FUSE kernel driver.
//!

use std::{ffi, os};
use std::ffi::CString;
use std::old_path::PosixPath;
use libc::{c_int, c_void, size_t};
use fuse::{fuse_args, fuse_mount_compat25, fuse_unmount_compat22};

// Libc provides iovec based I/O using readv and writev functions
#[allow(dead_code, non_camel_case_types)]
mod libc {
    use libc::{c_char, c_int, c_void, size_t, ssize_t};

    /// Iovec data structure for readv and writev calls.
    #[repr(C)]
    pub struct iovec {
        pub iov_base: *const c_void,
        pub iov_len: size_t,
    }

    extern "system" {
        /// Read data from fd into multiple buffers
        pub fn readv (fd: c_int, iov: *mut iovec, iovcnt: c_int) -> ssize_t;
        /// Write data from multiple buffers to fd
        pub fn writev (fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t;

        pub fn realpath (file_name: *const c_char, resolved_name: *mut c_char) -> *const c_char;

        pub fn unmount(dir: *const c_char, flags: c_int) -> c_int;
    }

    /// Max length for path names. 4096 should be reasonable safe (OS X uses 1024, Linux uses 4096)
    pub const PATH_MAX: usize = 4096;
}

/// Wrapper around libc's realpath.  Returns the errno value if the real path cannot be obtained.
/// FIXME: Use Rust's realpath method once available in std (see also https://github.com/mozilla/rust/issues/11857)
fn real_path (path: &PosixPath) -> Result<PosixPath, i32> {
    let cpath = CString::from_slice(path.as_vec());
    let mut resolved = [0; libc::PATH_MAX];
    unsafe {
        if libc::realpath(cpath.as_ptr(), resolved.as_mut_ptr()).is_null() {
            Err(os::errno())
        } else {
            Ok(PosixPath::new(ffi::c_str_to_bytes(&resolved.as_ptr())))
        }
    }
}

/// Helper function to provide options as a fuse_args struct
/// (which contains an argc count and an argv pointer)
fn with_fuse_args<T, F: FnOnce(&fuse_args) -> T> (options: &[&[u8]], f: F) -> T {
    let args: Vec<CString> = Some(b"rust-fuse").iter().chain(options.iter()).map(|s| CString::from_slice(s)).collect();
    let argptrs: Vec<*const i8> = args.iter().map(|s| s.as_ptr()).collect();
    f(&fuse_args { argc: argptrs.len() as i32, argv: argptrs.as_ptr(), allocated: 0 })
}

/// A raw communication channel to the FUSE kernel driver
pub struct Channel {
    mountpoint: Path,
    fd: c_int,
}

impl Channel {
    /// Create a new communication channel to the kernel driver by mounting the
    /// given path. The kernel driver will delegate filesystem operations of
    /// the given path to the channel. If the channel is dropped, the path is
    /// unmounted.
    pub fn new (mountpoint: &Path, options: &[&[u8]]) -> Result<Channel, i32> {
        real_path(mountpoint).and_then(|mountpoint| {
            with_fuse_args(options, |args| {
                let mnt = CString::from_slice(mountpoint.as_vec()).as_ptr();
                let fd = unsafe { fuse_mount_compat25(mnt, args) };
                if fd < 0 {
                    Err(os::errno())
                } else {
                    Ok(Channel { mountpoint: mountpoint.clone(), fd: fd })
                }
            })
        })
    }

    /// Receives data up to the capacity of the given buffer (can block).
    pub fn receive (&self, buffer: &mut Vec<u8>) -> Result<(), i32> {
        let rc = unsafe { ::libc::read(self.fd, buffer.as_ptr() as *mut c_void, buffer.capacity() as size_t) };
        if rc < 0 {
            Err(os::errno())
        } else {
            unsafe { buffer.set_len(rc as usize); }
            Ok(())
        }
    }

    /// Returns a sender object for this channel. The sender object can be
    /// used to send to the channel. Multiple sender objects can be used
    /// and they can safely be sent to other threads.
    pub fn sender (&self) -> ChannelSender {
        // Since write/writev syscalls are threadsafe, we can simply create
        // a sender by using the same fd and use it in other threads. Only
        // the channel closes the fd when dropped. If any sender is used after
        // dropping the channel, it'll return an EBADF error.
        ChannelSender { fd: self.fd }
    }
}

impl Drop for Channel {
    fn drop (&mut self) {
        // TODO: send ioctl FUSEDEVIOCSETDAEMONDEAD on OS X before closing the fd
        // Close the communication channel to the kernel driver
        // (closing it before unnmount prevents sync unmount deadlock)
        unsafe { ::libc::close(self.fd); }
        // Unmount this channel's mount point
        unmount(&self.mountpoint);
    }
}

#[derive(Copy)]
pub struct ChannelSender {
    fd: c_int,
}

impl ChannelSender {
    /// Send all data in the slice of slice of bytes in a single write (can block).
    pub fn send (&self, buffer: &[&[u8]]) -> Result<(), i32> {
        let iovecs: Vec<libc::iovec> = buffer.iter().map(|d| {
            libc::iovec { iov_base: d.as_ptr() as *const c_void, iov_len: d.len() as size_t }
        }).collect();
        let rc = unsafe { libc::writev(self.fd, iovecs.as_ptr(), iovecs.len() as c_int) };
        if rc < 0 {
            Err(os::errno())
        } else {
            Ok(())
        }
    }
}

/// Unmount an arbitrary mount point
pub fn unmount (mountpoint: &Path) {
    // On OS X, fuse_unmount_compat22 attempts to call realpath, which in turn calls into the filesystem.
    // If the filesystem returns an error, the unmount does not take place, with no indication of the error
    // available to the caller.  So we call unmount directly, which is what osxfuse does anyway, since
    // we already converted to the real path when we first mounted.
    let mnt = CString::from_slice(mountpoint.as_vec()).as_ptr();
    if cfg!(target_os = "macos") {
        unsafe { libc::unmount(mnt, 0); }
    } else {
        unsafe { fuse_unmount_compat22(mnt); }
    }
}

#[cfg(test)]
mod test {
    use super::with_fuse_args;
    use std::ffi;

    #[test]
    fn fuse_args () {
        with_fuse_args(&[b"foo", b"bar"], |args| {
            assert!(args.argc == 3);
            assert_eq!(unsafe { ffi::c_str_to_bytes(&*args.argv.offset(0)) }, b"rust-fuse");
            assert_eq!(unsafe { ffi::c_str_to_bytes(&*args.argv.offset(1)) }, b"foo");
            assert_eq!(unsafe { ffi::c_str_to_bytes(&*args.argv.offset(2)) }, b"bar");
        });
    }
}
<|endoftext|>


<commit_before>extern crate llvm_sys as llvm;

// use std::mem;
use std::ffi::CString;
use std::ptr;

use self::llvm::core::*;
use self::llvm::prelude::*;
use std::rc::Rc;

// use parser;
// use lexer;
use node;
use types::Type;
use error;

pub struct Codegen {
    context: LLVMContextRef,
    module: LLVMModuleRef,
    builder: LLVMBuilderRef,
}

impl Codegen {
    pub unsafe fn new(mod_name: &str) -> Codegen {
        let c_mod_name = CString::new(mod_name).unwrap();
        Codegen {
            context: LLVMContextCreate(),
            module: LLVMModuleCreateWithNameInContext(c_mod_name.as_ptr(), LLVMContextCreate()),
            builder: LLVMCreateBuilderInContext(LLVMContextCreate()),
        }
    }

    pub unsafe fn type_to_llvmty(&mut self, ty: &Type) -> LLVMTypeRef {
        match ty {
            &Type::Void => LLVMVoidType(),
            &Type::Char(_) => LLVMInt8Type(),
            &Type::Short(_) => LLVMInt16Type(),
            &Type::Int(_) => LLVMInt32Type(),
            &Type::Long(_) => LLVMInt32Type(),
            &Type::LLong(_) => LLVMInt64Type(),
            &Type::Float => LLVMFloatType(),
            &Type::Double => LLVMDoubleType(),
            &Type::Ptr(ref elemty) => LLVMPointerType(self.type_to_llvmty(&**elemty), 0),
            &Type::Array(ref elemty, ref size) => {
                LLVMArrayType(self.type_to_llvmty(&**elemty), *size as u32)
            }
            &Type::Func(ref ret_type, ref param_types, ref is_vararg) => {
                LLVMFunctionType(self.type_to_llvmty(&**ret_type),
                                 || -> *mut LLVMTypeRef {
                                     let mut param_llvm_types: Vec<LLVMTypeRef> = Vec::new();
                                     for param_type in &*param_types {
                                         param_llvm_types.push(self.type_to_llvmty(&param_type));
                                     }
                                     param_llvm_types.as_mut_slice().as_mut_ptr()
                                 }(),
                                 (*param_types).len() as u32,
                                 if *is_vararg { 1 } else { 0 })
            }
        }
    }

    pub unsafe fn run(&mut self, node: Vec<node::AST>) {
        for ast in node {
            self.gen(&ast);
        }

        // e.g. create func
        // let int_t = LLVMInt32TypeInContext(self.context);
        // let func_t = LLVMFunctionType(/* ret type = */
        //                               int_t,
        //                               /* param types = */
        //                               ptr::null_mut(),
        //                               /* param count = */
        //                               0,
        //                               /* is vararg? = */
        //                               0);
        // let main_func =
        //     LLVMAddFunction(self.module, CString::new("main").unwrap().as_ptr(), func_t);
        //
        // // create basic block 'entry'
        // let bb_entry = LLVMAppendBasicBlock(main_func, CString::new("entry").unwrap().as_ptr());
        //
        // LLVMPositionBuilderAtEnd(self.builder, bb_entry); // SetInsertPoint in C++
        //
        // LLVMBuildRet(self.builder, self.make_int(0, false));

        LLVMDumpModule(self.module);
    }

    pub unsafe fn gen(&mut self, ast: &node::AST) -> LLVMValueRef {
        match ast {
            &node::AST::FuncDef(ref functy, ref param_names, ref name, ref body) => {
                self.gen_func_def(functy, param_names, name, body)
            }
            // &node::AST::VariableDecl(_, _, _) => {}
            &node::AST::Block(ref block) => self.gen_block(block),
            &node::AST::Return(ref ret) => {
                let retval = self.gen(ret);
                self.gen_return(retval)
            }
            &node::AST::Int(ref n) => self.make_int(*n as u64, false),
            _ => {
                error::error_exit(0,
                                  format!("codegen: unknown ast (given {:?})", ast).as_str())
            }
        }
    }

    pub unsafe fn gen_func_def(&mut self,
                               functy: &Type,
                               param_names: &Vec<String>,
                               name: &String,
                               body: &Rc<node::AST>)
                               -> LLVMValueRef {
        let func_t = self.type_to_llvmty(functy);
        let func = LLVMAddFunction(self.module,
                                   CString::new(name.as_str()).unwrap().as_ptr(),
                                   func_t);

        let bb_entry = LLVMAppendBasicBlock(func, CString::new("entry").unwrap().as_ptr());
        LLVMPositionBuilderAtEnd(self.builder, bb_entry);

        self.gen(&**body);

        func
    }

    unsafe fn gen_block(&mut self, block: &Vec<node::AST>) -> LLVMValueRef {
        for stmt in block {
            self.gen(stmt);
        }
        ptr::null_mut()
    }

    unsafe fn gen_return(&mut self, retval: LLVMValueRef) -> LLVMValueRef {
        LLVMBuildRet(self.builder, retval)
    }

    pub unsafe fn make_int(&mut self, n: u64, is_unsigned: bool) -> LLVMValueRef {
        LLVMConstInt(LLVMInt32TypeInContext(self.context),
                     n,
                     if is_unsigned { 1 } else { 0 })
    }
    pub unsafe fn make_float(&mut self, f: f64) -> LLVMValueRef {
        LLVMConstReal(LLVMDoubleTypeInContext(self.context), f)
    }
}
<commit_msg>implement some bin op<commit_after>extern crate llvm_sys as llvm;

// use std::mem;
use std::ffi::CString;
use std::ptr;

use self::llvm::core::*;
use self::llvm::prelude::*;
use std::rc::Rc;

// use parser;
// use lexer;
use node;
use types::{Type, Sign};
use error;

pub struct Codegen {
    context: LLVMContextRef,
    module: LLVMModuleRef,
    builder: LLVMBuilderRef,
}

impl Codegen {
    pub unsafe fn new(mod_name: &str) -> Codegen {
        let c_mod_name = CString::new(mod_name).unwrap();
        Codegen {
            context: LLVMContextCreate(),
            module: LLVMModuleCreateWithNameInContext(c_mod_name.as_ptr(), LLVMContextCreate()),
            builder: LLVMCreateBuilderInContext(LLVMContextCreate()),
        }
    }

    pub unsafe fn type_to_llvmty(&mut self, ty: &Type) -> LLVMTypeRef {
        match ty {
            &Type::Void => LLVMVoidType(),
            &Type::Char(_) => LLVMInt8Type(),
            &Type::Short(_) => LLVMInt16Type(),
            &Type::Int(_) => LLVMInt32Type(),
            &Type::Long(_) => LLVMInt32Type(),
            &Type::LLong(_) => LLVMInt64Type(),
            &Type::Float => LLVMFloatType(),
            &Type::Double => LLVMDoubleType(),
            &Type::Ptr(ref elemty) => LLVMPointerType(self.type_to_llvmty(&**elemty), 0),
            &Type::Array(ref elemty, ref size) => {
                LLVMArrayType(self.type_to_llvmty(&**elemty), *size as u32)
            }
            &Type::Func(ref ret_type, ref param_types, ref is_vararg) => {
                LLVMFunctionType(self.type_to_llvmty(&**ret_type),
                                 || -> *mut LLVMTypeRef {
                                     let mut param_llvm_types: Vec<LLVMTypeRef> = Vec::new();
                                     for param_type in &*param_types {
                                         param_llvm_types.push(self.type_to_llvmty(&param_type));
                                     }
                                     param_llvm_types.as_mut_slice().as_mut_ptr()
                                 }(),
                                 (*param_types).len() as u32,
                                 if *is_vararg { 1 } else { 0 })
            }
        }
    }

    pub unsafe fn run(&mut self, node: Vec<node::AST>) {
        for ast in node {
            self.gen(&ast);
        }

        // e.g. create func
        // let int_t = LLVMInt32TypeInContext(self.context);
        // let func_t = LLVMFunctionType(/* ret type = */
        //                               int_t,
        //                               /* param types = */
        //                               ptr::null_mut(),
        //                               /* param count = */
        //                               0,
        //                               /* is vararg? = */
        //                               0);
        // let main_func =
        //     LLVMAddFunction(self.module, CString::new("main").unwrap().as_ptr(), func_t);
        //
        // // create basic block 'entry'
        // let bb_entry = LLVMAppendBasicBlock(main_func, CString::new("entry").unwrap().as_ptr());
        //
        // LLVMPositionBuilderAtEnd(self.builder, bb_entry); // SetInsertPoint in C++
        //
        // LLVMBuildRet(self.builder, self.make_int(0, false));

        LLVMDumpModule(self.module);
    }

    pub unsafe fn gen(&mut self, ast: &node::AST) -> (LLVMValueRef, Option<Type>) {
        match ast {
            &node::AST::FuncDef(ref functy, ref param_names, ref name, ref body) => {
                self.gen_func_def(functy, param_names, name, body)
            }
            // &node::AST::VariableDecl(_, _, _) => {}
            &node::AST::Block(ref block) => self.gen_block(block),
            &node::AST::BinaryOp(ref lhs, ref rhs, ref op) => {
                self.gen_binary_op(&**lhs, &**rhs, &*op)
            }
            &node::AST::Return(ref ret) => {
                let (retval, _) = self.gen(ret);
                self.gen_return(retval)
            }
            &node::AST::Int(ref n) => self.make_int(*n as u64, false),
            _ => {
                error::error_exit(0,
                                  format!("codegen: unknown ast (given {:?})", ast).as_str())
            }
        }
    }

    pub unsafe fn gen_func_def(&mut self,
                               functy: &Type,
                               param_names: &Vec<String>,
                               name: &String,
                               body: &Rc<node::AST>)
                               -> (LLVMValueRef, Option<Type>) {
        let func_t = self.type_to_llvmty(functy);
        let func = LLVMAddFunction(self.module,
                                   CString::new(name.as_str()).unwrap().as_ptr(),
                                   func_t);

        let bb_entry = LLVMAppendBasicBlock(func, CString::new("entry").unwrap().as_ptr());
        LLVMPositionBuilderAtEnd(self.builder, bb_entry);

        self.gen(&**body);

        (func, None)
    }

    unsafe fn gen_block(&mut self, block: &Vec<node::AST>) -> (LLVMValueRef, Option<Type>) {
        for stmt in block {
            self.gen(stmt);
        }
        (ptr::null_mut(), None)
    }

    unsafe fn gen_binary_op(&mut self,
                            lhsast: &node::AST,
                            rhsast: &node::AST,
                            op: &node::CBinOps)
                            -> (LLVMValueRef, Option<Type>) {
        // logical operators
        match *op {
            node::CBinOps::LAnd => {}
            node::CBinOps::LOr => {}
            _ => {}
        }

        // normal binary operators
        let (lhs, lhsty) = self.gen(lhsast);
        let (rhs, rhsty) = self.gen(rhsast);
        match lhsty.unwrap() {
            Type::Int(_) => {
                return (self.gen_int_binary_op(lhs, rhs, op), Some(Type::Int(Sign::Signed)))
            }
            _ => {}
        }
        (ptr::null_mut(), Some(Type::Void))
    }

    unsafe fn gen_int_binary_op(&mut self,
                                lhs: LLVMValueRef,
                                rhs: LLVMValueRef,
                                op: &node::CBinOps)
                                -> LLVMValueRef {
        match *op {
            node::CBinOps::Add => {
                LLVMBuildAdd(self.builder,
                             lhs,
                             rhs,
                             CString::new("add").unwrap().as_ptr())
            }
            _ => ptr::null_mut(),
        }
    }

    unsafe fn gen_return(&mut self, retval: LLVMValueRef) -> (LLVMValueRef, Option<Type>) {
        (LLVMBuildRet(self.builder, retval), None)
    }

    pub unsafe fn make_int(&mut self, n: u64, is_unsigned: bool) -> (LLVMValueRef, Option<Type>) {
        (LLVMConstInt(LLVMInt32TypeInContext(self.context),
                      n,
                      if is_unsigned { 1 } else { 0 }),
         Some(Type::Int(Sign::Signed)))
    }
    pub unsafe fn make_float(&mut self, f: f64) -> (LLVMValueRef, Option<Type>) {
        (LLVMConstReal(LLVMFloatTypeInContext(self.context), f), Some(Type::Float))
    }
    pub unsafe fn make_double(&mut self, f: f64) -> (LLVMValueRef, Option<Type>) {
        (LLVMConstReal(LLVMDoubleTypeInContext(self.context), f), Some(Type::Double))
    }
}
<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Show, Clone)]
pub enum Method<'a> {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'a str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> Method<'a>;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler<E> {
    fn call(&self, request: &mut Request) -> Result<Response, E>;
}

impl<E> Handler<E> for fn(&mut Request) -> Result<Response, E> {
    fn call(&self, request: &mut Request) -> Result<Response, E> {
        (*self)(request)
    }
}
<commit_msg>Eq is required for Hash key<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method<'a> {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'a str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> Method<'a>;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler<E> {
    fn call(&self, request: &mut Request) -> Result<Response, E>;
}

impl<E> Handler<E> for fn(&mut Request) -> Result<Response, E> {
    fn call(&self, request: &mut Request) -> Result<Response, E> {
        (*self)(request)
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, VecDeque};

use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use crate::block::{BlockContext, BlockParamHolder};
use crate::error::RenderError;
use crate::grammar::Rule;
use crate::json::path::*;
use crate::json::value::ScopedJson;
use crate::util::extend;

pub type Object = HashMap<String, Json>;

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[derive(Debug)]
enum ResolvedPath<'a> {
    // FIXME: change to borrowed when possible
    // full path
    AbsolutePath(Vec<String>),
    // relative path and path root
    RelativePath(Vec<String>),
    // relative path against block param value
    BlockParamValue(Vec<String>, &'a Json),
    // relative path against derived value,
    LocalValue(Vec<String>, &'a Json),
}

fn parse_json_visitor<'a, 'reg: 'rc, 'rc>(
    relative_path: &[PathSeg],
    block_contexts: &'a VecDeque<BlockContext<'reg>>,
    always_for_absolute_path: bool,
) -> Result<ResolvedPath<'a>, RenderError> {
    // TODO: add support for base value

    let mut path_context_depth: i64 = 0;
    let mut with_block_param = None;
    let mut from_root = false;

    // peek relative_path for block param, @root and  "../../"
    for path_seg in relative_path {
        match path_seg {
            PathSeg::Named(the_path) => {
                if let Some((holder, base_path)) = get_in_block_params(&block_contexts, the_path) {
                    with_block_param = Some((holder, base_path));
                }
                break;
            }
            PathSeg::Ruled(the_rule) => match the_rule {
                Rule::path_root => {
                    from_root = true;
                    break;
                }
                Rule::path_up => path_context_depth += 1,
                _ => break,
            },
        }
    }

    let mut path_stack = Vec::with_capacity(relative_path.len() + 5);
    match with_block_param {
        Some((BlockParamHolder::Value(ref value), _)) => {
            merge_json_path(&mut path_stack, &relative_path[1..]);
            Ok(ResolvedPath::BlockParamValue(path_stack, value))
        }
        Some((BlockParamHolder::Path(ref paths), base_path)) => {
            extend(&mut path_stack, base_path);
            if !paths.is_empty() {
                extend(&mut path_stack, paths);
            }
            merge_json_path(&mut path_stack, &relative_path[1..]);

            Ok(ResolvedPath::AbsolutePath(path_stack))
        }
        None => {
            if path_context_depth > 0 {
                if let Some(ref context_base_path) = block_contexts
                    .get(path_context_depth as usize)
                    .map(|blk| blk.base_path())
                {
                    extend(&mut path_stack, context_base_path);
                } else {
                    // TODO: is this correct behaviour?
                    if let Some(ref base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                        extend(&mut path_stack, base_path);
                    }
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if from_root {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if always_for_absolute_path {
                if let Some(base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                    extend(&mut path_stack, base_path);
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::RelativePath(path_stack))
            }
        }
    }
}

fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
    let result = match d {
        Some(&Json::Array(ref l)) => p.parse::<usize>().map(|idx_u| l.get(idx_u))?,
        Some(&Json::Object(ref m)) => m.get(p),
        Some(_) => None,
        None => None,
    };
    Ok(result)
}

fn get_in_block_params<'a, 'reg: 'rc, 'rc>(
    block_contexts: &'a VecDeque<BlockContext<'reg>>,
    p: &str,
) -> Option<(&'a BlockParamHolder, &'a Vec<String>)> {
    for bc in block_contexts {
        let v = bc.get_block_param(p);
        if v.is_some() {
            return v.map(|v| (v, bc.base_path()));
        }
    }

    None
}

pub(crate) fn merge_json(base: &Json, addition: &HashMap<&&str, &Json>) -> Json {
    let mut base_map = match base {
        Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert((*(*k)).to_string(), (*v).clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// Navigate the context with relative path and block scopes
    pub(crate) fn navigate<'reg, 'rc>(
        &'rc self,
        relative_path: &[PathSeg],
        block_contexts: &VecDeque<BlockContext<'reg>>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        // always use absolute at the moment until we get base_value lifetime issue fixed
        let resolved_visitor = parse_json_visitor(&relative_path, block_contexts, true)?;

        match resolved_visitor {
            ResolvedPath::AbsolutePath(paths) => {
                let mut ptr = Some(self.data());
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }

                Ok(ptr
                    .map(|v| ScopedJson::Context(v, paths))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::RelativePath(_paths) => {
                // relative path is disabled for now
                unreachable!()
                // let mut ptr = block_contexts.front().and_then(|blk| blk.base_value());
                // for p in paths.iter() {
                //     ptr = get_data(ptr, p)?;
                // }

                // Ok(ptr
                //     .map(|v| ScopedJson::Context(v, paths))
                //     .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::BlockParamValue(paths, value) => {
                let mut ptr = Some(value);
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }
                Ok(ptr
                    .map(|v| ScopedJson::Derived(v.clone()))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::LocalValue(paths, value) => {
                let mut ptr = Some(value);
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }
                Ok(ptr
                    .map(|v| ScopedJson::Derived(v.clone()))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
        }
    }

    /// Return the Json data wrapped in context
    pub fn data(&self) -> &Json {
        &self.data
    }

    /// Return the mutable reference to Json data wrapped in context
    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

#[cfg(test)]
mod test {
    use crate::block::{BlockContext, BlockParams};
    use crate::context::{self, Context};
    use crate::error::RenderError;
    use crate::json::path::Path;
    use crate::json::value::{self, ScopedJson};
    use serde_json::value::Map;
    use std::collections::{HashMap, VecDeque};

    fn navigate_from_root<'reg, 'rc>(
        ctx: &'rc Context,
        path: &str,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let relative_path = Path::parse(path).unwrap();
        ctx.navigate(relative_path.segs().unwrap(), &VecDeque::new())
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string()).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this").unwrap().render(),
            v.to_string()
        );
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographer".to_string()],
        };

        let ctx = Context::wraps(&person).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "./addr/country").unwrap().render(),
            "China".to_string()
        );
        assert_eq!(
            navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
            "China".to_string()
        );

        let v = true;
        let ctx2 = Context::wraps(&v).unwrap();
        assert_eq!(
            navigate_from_root(&ctx2, "this").unwrap().render(),
            "true".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
            "programmer".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "age").unwrap().render(),
            "27".to_string()
        );
    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), value::to_json("hello"));
        map_with_this.insert("age".to_string(), value::to_json(5usize));
        let ctx1 = Context::wraps(&map_with_this).unwrap();

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), value::to_json(4usize));
        let ctx2 = Context::wraps(&map_without_this).unwrap();

        assert_eq!(
            navigate_from_root(&ctx1, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx2, "age").unwrap().render(),
            "4".to_owned()
        );
    }

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let mut hash = HashMap::new();
        let v = value::to_json("h1");
        hash.insert(&"tag", &v);

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a1, "age").unwrap().render(),
            "4".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a1, "tag").unwrap().render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a2, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a2, "tag").unwrap().render(),
            "h1".to_owned()
        );
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap! {
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this_name").unwrap().render(),
            "the_value".to_string()
        );
    }

    use serde::ser::Error as SerdeError;
    use serde::{Serialize, Serializer};

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        let mut block = BlockContext::new();
        *block.base_path_mut() = ["a".to_owned(), "b".to_owned()].to_vec();

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&Path::parse("@root/b").unwrap().segs().unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
    }

    #[test]
    fn test_block_params() {
        let m = json!([{
            "a": [1, 2]
        }, {
            "b": [2, 3]
        }]);

        let ctx = Context::wraps(&m).unwrap();
        let mut block_params = BlockParams::new();
        block_params
            .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
            .unwrap();
        block_params.add_value("t", json!("good")).unwrap();

        let mut block = BlockContext::new();
        block.set_block_params(block_params);

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&Path::parse("z.[1]").unwrap().segs().unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
        assert_eq!(
            ctx.navigate(&Path::parse("t").unwrap().segs().unwrap(), &blocks)
                .unwrap()
                .render(),
            "good".to_string()
        );
    }
}
<commit_msg>(refactor) reduce duplicate code<commit_after>use std::collections::{HashMap, VecDeque};

use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use crate::block::{BlockContext, BlockParamHolder};
use crate::error::RenderError;
use crate::grammar::Rule;
use crate::json::path::*;
use crate::json::value::ScopedJson;
use crate::util::extend;

pub type Object = HashMap<String, Json>;

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[derive(Debug)]
enum ResolvedPath<'a> {
    // FIXME: change to borrowed when possible
    // full path
    AbsolutePath(Vec<String>),
    // relative path and path root
    RelativePath(Vec<String>),
    // relative path against block param value
    BlockParamValue(Vec<String>, &'a Json),
    // relative path against derived value,
    LocalValue(Vec<String>, &'a Json),
}

fn parse_json_visitor<'a, 'reg: 'rc, 'rc>(
    relative_path: &[PathSeg],
    block_contexts: &'a VecDeque<BlockContext<'reg>>,
    always_for_absolute_path: bool,
) -> Result<ResolvedPath<'a>, RenderError> {
    // TODO: add support for base value

    let mut path_context_depth: i64 = 0;
    let mut with_block_param = None;
    let mut from_root = false;

    // peek relative_path for block param, @root and  "../../"
    for path_seg in relative_path {
        match path_seg {
            PathSeg::Named(the_path) => {
                if let Some((holder, base_path)) = get_in_block_params(&block_contexts, the_path) {
                    with_block_param = Some((holder, base_path));
                }
                break;
            }
            PathSeg::Ruled(the_rule) => match the_rule {
                Rule::path_root => {
                    from_root = true;
                    break;
                }
                Rule::path_up => path_context_depth += 1,
                _ => break,
            },
        }
    }

    let mut path_stack = Vec::with_capacity(relative_path.len() + 5);
    match with_block_param {
        Some((BlockParamHolder::Value(ref value), _)) => {
            merge_json_path(&mut path_stack, &relative_path[1..]);
            Ok(ResolvedPath::BlockParamValue(path_stack, value))
        }
        Some((BlockParamHolder::Path(ref paths), base_path)) => {
            extend(&mut path_stack, base_path);
            if !paths.is_empty() {
                extend(&mut path_stack, paths);
            }
            merge_json_path(&mut path_stack, &relative_path[1..]);

            Ok(ResolvedPath::AbsolutePath(path_stack))
        }
        None => {
            if path_context_depth > 0 {
                if let Some(ref context_base_path) = block_contexts
                    .get(path_context_depth as usize)
                    .map(|blk| blk.base_path())
                {
                    extend(&mut path_stack, context_base_path);
                } else {
                    // TODO: is this correct behaviour?
                    if let Some(ref base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                        extend(&mut path_stack, base_path);
                    }
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if from_root {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if always_for_absolute_path {
                if let Some(base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                    extend(&mut path_stack, base_path);
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::RelativePath(path_stack))
            }
        }
    }
}

fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
    let result = match d {
        Some(&Json::Array(ref l)) => p.parse::<usize>().map(|idx_u| l.get(idx_u))?,
        Some(&Json::Object(ref m)) => m.get(p),
        Some(_) => None,
        None => None,
    };
    Ok(result)
}

fn get_in_block_params<'a, 'reg: 'rc, 'rc>(
    block_contexts: &'a VecDeque<BlockContext<'reg>>,
    p: &str,
) -> Option<(&'a BlockParamHolder, &'a Vec<String>)> {
    for bc in block_contexts {
        let v = bc.get_block_param(p);
        if v.is_some() {
            return v.map(|v| (v, bc.base_path()));
        }
    }

    None
}

pub(crate) fn merge_json(base: &Json, addition: &HashMap<&&str, &Json>) -> Json {
    let mut base_map = match base {
        Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert((*(*k)).to_string(), (*v).clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// Navigate the context with relative path and block scopes
    pub(crate) fn navigate<'reg, 'rc>(
        &'rc self,
        relative_path: &[PathSeg],
        block_contexts: &VecDeque<BlockContext<'reg>>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        // always use absolute at the moment until we get base_value lifetime issue fixed
        let resolved_visitor = parse_json_visitor(&relative_path, block_contexts, true)?;

        match resolved_visitor {
            ResolvedPath::AbsolutePath(paths) => {
                let mut ptr = Some(self.data());
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }

                Ok(ptr
                    .map(|v| ScopedJson::Context(v, paths))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::RelativePath(_paths) => {
                // relative path is disabled for now
                unreachable!()
                // let mut ptr = block_contexts.front().and_then(|blk| blk.base_value());
                // for p in paths.iter() {
                //     ptr = get_data(ptr, p)?;
                // }

                // Ok(ptr
                //     .map(|v| ScopedJson::Context(v, paths))
                //     .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::BlockParamValue(paths, value)
            | ResolvedPath::LocalValue(paths, value) => {
                let mut ptr = Some(value);
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }
                Ok(ptr
                    .map(|v| ScopedJson::Derived(v.clone()))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
        }
    }

    /// Return the Json data wrapped in context
    pub fn data(&self) -> &Json {
        &self.data
    }

    /// Return the mutable reference to Json data wrapped in context
    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

#[cfg(test)]
mod test {
    use crate::block::{BlockContext, BlockParams};
    use crate::context::{self, Context};
    use crate::error::RenderError;
    use crate::json::path::Path;
    use crate::json::value::{self, ScopedJson};
    use serde_json::value::Map;
    use std::collections::{HashMap, VecDeque};

    fn navigate_from_root<'reg, 'rc>(
        ctx: &'rc Context,
        path: &str,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let relative_path = Path::parse(path).unwrap();
        ctx.navigate(relative_path.segs().unwrap(), &VecDeque::new())
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string()).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this").unwrap().render(),
            v.to_string()
        );
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographer".to_string()],
        };

        let ctx = Context::wraps(&person).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "./addr/country").unwrap().render(),
            "China".to_string()
        );
        assert_eq!(
            navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
            "China".to_string()
        );

        let v = true;
        let ctx2 = Context::wraps(&v).unwrap();
        assert_eq!(
            navigate_from_root(&ctx2, "this").unwrap().render(),
            "true".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
            "programmer".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "age").unwrap().render(),
            "27".to_string()
        );
    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), value::to_json("hello"));
        map_with_this.insert("age".to_string(), value::to_json(5usize));
        let ctx1 = Context::wraps(&map_with_this).unwrap();

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), value::to_json(4usize));
        let ctx2 = Context::wraps(&map_without_this).unwrap();

        assert_eq!(
            navigate_from_root(&ctx1, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx2, "age").unwrap().render(),
            "4".to_owned()
        );
    }

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let mut hash = HashMap::new();
        let v = value::to_json("h1");
        hash.insert(&"tag", &v);

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a1, "age").unwrap().render(),
            "4".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a1, "tag").unwrap().render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a2, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a2, "tag").unwrap().render(),
            "h1".to_owned()
        );
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap! {
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this_name").unwrap().render(),
            "the_value".to_string()
        );
    }

    use serde::ser::Error as SerdeError;
    use serde::{Serialize, Serializer};

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        let mut block = BlockContext::new();
        *block.base_path_mut() = ["a".to_owned(), "b".to_owned()].to_vec();

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&Path::parse("@root/b").unwrap().segs().unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
    }

    #[test]
    fn test_block_params() {
        let m = json!([{
            "a": [1, 2]
        }, {
            "b": [2, 3]
        }]);

        let ctx = Context::wraps(&m).unwrap();
        let mut block_params = BlockParams::new();
        block_params
            .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
            .unwrap();
        block_params.add_value("t", json!("good")).unwrap();

        let mut block = BlockContext::new();
        block.set_block_params(block_params);

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&Path::parse("z.[1]").unwrap().segs().unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
        assert_eq!(
            ctx.navigate(&Path::parse("t").unwrap().segs().unwrap(), &blocks)
                .unwrap()
                .render(),
            "good".to_string()
        );
    }
}
<|endoftext|>