<commit_before>extern crate mio;
extern crate regex;

#[cfg(test)]
mod tests;

pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

use route::*;
use request::*;
use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::new(),
            o_buf:  Vec::new(),
        }
    }

    fn readable(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(sz) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None     => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    /* write the client's output buffer to the socket.
     *
     * the following return values mean:
     *  - Ok(true):  we can close the connection
     *  - Ok(false): keep listening for writeable event and continue next time
     *  - Err(e):    something dun fucked up
     */
    fn writable(&mut self) -> Result<bool> {
        let tmp = self.o_buf.clone();
        let out = tmp.as_slice();
        match self.sock.write(&out) {
            Ok(sz)  => {
                if sz == self.o_buf.len() {
                    /* we did it! */
                    self.events.remove(EventSet::writable());
                    return Ok(true);
                } else {
                    let tmp: Vec<u8> = self.o_buf.split_off(sz);
                    self.o_buf = tmp;

                    return Ok(false);
                }
            },
            Err(e)  => {
                panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
            }
        }

        Ok(false)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/* our primary object. similar interface to Flask, the
 * Python microframework. much faster, however! :)
 */
pub struct Canteen {
    routes:  HashMap<String, Route>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).writable() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: Route::err_404,
        }
    }

    pub fn add_route(&mut self, path: &str, mlist: Vec<Method>, handler: fn(&Request) -> Response) {
        let pc = String::from(path);

        if self.routes.contains_key(&pc) {
            panic!("a route handler for {} has already been defined!", path);
        }

        self.routes.insert(String::from(path), Route::new(&path, mlist, handler));
    }

    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&self, req: &mut Request) -> Vec<u8> {
        let mut handler: fn(&Request) -> Response = self.default;

        for (_, route) in &self.routes {
            match (route).is_match(req) {
                true  => {
                    handler = route.handler;
                    req.params = route.parse(&req.path);
                    break;
                },
                false => continue,
            }
        }

        handler(req).gen_output()
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).readable() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let mut req = Request::from_str(&rqstr);
                let output = self.handle_request(&mut req);

                self.get_client(token).o_buf.extend(output);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        /* kill the connection */
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<commit_msg>add another couple common handlers for the ToOutput trait<commit_after>extern crate mio;
extern crate regex;

#[cfg(test)]
mod tests;

pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

use route::*;
use request::*;
use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::new(),
            o_buf:  Vec::new(),
        }
    }

    fn readable(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    /* write the client's output buffer to the socket.
     *
     * the following return values mean:
     *  - Ok(true):  we can close the connection
     *  - Ok(false): keep listening for writeable event and continue next time
     *  - Err(e):    something dun fucked up
     */
    fn writable(&mut self) -> Result<bool> {
        let tmp = self.o_buf.clone();
        let out = tmp.as_slice();
        match self.sock.write(&out) {
            Ok(sz)  => {
                if sz == self.o_buf.len() {
                    /* we did it! */
                    self.events.remove(EventSet::writable());
                    return Ok(true);
                } else {
                    let tmp: Vec<u8> = self.o_buf.split_off(sz);
                    self.o_buf = tmp;

                    return Ok(false);
                }
            },
            Err(e)  => {
                panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
            }
        }

        Ok(false)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/* our primary object. similar interface to Flask, the
 * Python microframework. much faster, however! :)
 */
pub struct Canteen {
    routes:  HashMap<String, Route>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).writable() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: Route::err_404,
        }
    }

    pub fn add_route(&mut self, path: &str, mlist: Vec<Method>, handler: fn(&Request) -> Response) {
        let pc = String::from(path);

        if self.routes.contains_key(&pc) {
            panic!("a route handler for {} has already been defined!", path);
        }

        self.routes.insert(String::from(path), Route::new(&path, mlist, handler));
    }

    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&self, req: &mut Request) -> Vec<u8> {
        let mut handler: fn(&Request) -> Response = self.default;

        for (_, route) in &self.routes {
            match (route).is_match(req) {
                true  => {
                    handler = route.handler;
                    req.params = route.parse(&req.path);
                    break;
                },
                false => continue,
            }
        }

        handler(req).gen_output()
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).readable() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let mut req = Request::from_str(&rqstr);
                let output = self.handle_request(&mut req);

                self.get_client(token).o_buf.extend(output);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        /* kill the connection */
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate variable_size_byte_writer;

use test::Bencher;
use variable_size_byte_writer::*;

#[bench]
fn write_32_vec(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut target = std::io::Cursor::new(vec![]);

    bench.iter(|| writer.write_32(&mut target, 0x7_F1F0, 21));
}

#[bench]
fn write_32_file(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut file = std::fs::File::create("benches/temp/write_32_file.temp").unwrap();
    bench.iter(|| writer.write_32(&mut file, 0x7_F1F0, 21));
    std::fs::remove_file("benches/temp/write_32_file.temp").unwrap();
}

#[bench]
fn write_16_vec(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut target = std::io::Cursor::new(vec![]);

    bench.iter(|| writer.write_16(&mut target, 0x1A, 9));
}

#[bench]
fn write_16_file(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut file = std::fs::File::create("benches/temp/write_16_file.temp").unwrap();
    bench.iter(|| writer.write_16(&mut file, 0x1A, 9));
    std::fs::remove_file("benches/temp/write_16_file.temp").unwrap();
}

#[bench]
fn write_8_vec(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut target = std::io::Cursor::new(vec![]);

    bench.iter(|| writer.write_8(&mut target, 0x1A, 7));
}

#[bench]
fn write_8_file(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut file = std::fs::File::create("benches/temp/write_8_file.temp").unwrap();
    bench.iter(|| writer.write_8(&mut file, 0x1A, 7));
    std::fs::remove_file("benches/temp/write_8_file.temp").unwrap();
}

<commit_msg>added 'temp' directory creation to benches since the directory is ignored by git<commit_after>#![feature(test)]

extern crate test;
extern crate variable_size_byte_writer;

use test::Bencher;
use variable_size_byte_writer::*;

#[bench]
fn write_32_vec(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut target = std::io::Cursor::new(vec![]);

    bench.iter(|| writer.write_32(&mut target, 0x7_F1F0, 21));
}

#[bench]
fn write_32_file(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    std::fs::create_dir("benches/temp");
    let mut file = std::fs::File::create("benches/temp/write_32_file.temp").unwrap();
    bench.iter(|| writer.write_32(&mut file, 0x7_F1F0, 21));
    std::fs::remove_file("benches/temp/write_32_file.temp").unwrap();
}

#[bench]
fn write_16_vec(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut target = std::io::Cursor::new(vec![]);

    bench.iter(|| writer.write_16(&mut target, 0x1A, 9));
}

#[bench]
fn write_16_file(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    std::fs::create_dir("benches/temp");
    let mut file = std::fs::File::create("benches/temp/write_16_file.temp").unwrap();
    bench.iter(|| writer.write_16(&mut file, 0x1A, 9));
    std::fs::remove_file("benches/temp/write_16_file.temp").unwrap();
}

#[bench]
fn write_8_vec(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    let mut target = std::io::Cursor::new(vec![]);

    bench.iter(|| writer.write_8(&mut target, 0x1A, 7));
}

#[bench]
fn write_8_file(bench: &mut Bencher) {
    let mut writer = VariableSizeByteWriter::new(8192);
    std::fs::create_dir("benches/temp");
    let mut file = std::fs::File::create("benches/temp/write_8_file.temp").unwrap();
    bench.iter(|| writer.write_8(&mut file, 0x1A, 7));
    std::fs::remove_file("benches/temp/write_8_file.temp").unwrap();
}

<|endoftext|>


<commit_before>extern crate bf_lib;

use bf_lib::traits::*;
use bf_lib::bf_lexer::BFLexer;
use bf_lib::bf_vm::BFVM;
use bf_lib::bf_vm::VMSettings;
use std::process;

use std::fs::File;
use std::io::prelude::*;

#[derive(Debug)]
enum ArgumentMode {
    Skip,
    Start,
    Str,
    File,
}

fn read_file(in_str : String, mut out_str : &mut String ) {
    let mut file = File::open(in_str).expect("Unable to open file.");
    file.read_to_string(&mut out_str).expect("Unable to read file.");
}

fn print_help() {
    println!("
Rust BrainFuck Interpreter

Usage:
    bf-cli <file>
    bf-cli <file> -u
    bf-cli ( -f | --file ) <file>
    bf-cli ( -s | --str ) <bfstring>

Options:
    -h --help       Shows this screen.
    -u --usermode   Input is prompted for.
");
}

fn main() {
    /* ---------------------------------------------------.
    |     Load Arguments                                  |
    '---------------------------------------------------- */
    let mut mode = ArgumentMode::Skip;
    let mut input = String::new();
    let mut settings = VMSettings::new();
    for argument in std::env::args() {
        match mode {
            ArgumentMode::Skip => mode = ArgumentMode::Start,
            ArgumentMode::Start => {
                match argument.as_ref() {
                    "-s" | "--str" => mode = ArgumentMode::Str,
                    "-f" | "--file" => mode = ArgumentMode::File,
                    "-h" | "--help" => {
                        print_help();
                        process::exit(1);
                    },
                    "-u" | "--usermode" => settings.prompt_for_input = true,
                    _ => read_file(argument, &mut input)
                };
            },
            ArgumentMode::Str => {
                input = argument;
                mode = ArgumentMode::Start;
            },
            ArgumentMode::File => {
                read_file(argument, &mut input);
                mode = ArgumentMode::Start;
            },
        }
    }

    /* ---------------------------------------------------.
    |    Interpret and Run Input                          |
    '---------------------------------------------------- */
    let tokens = BFLexer::parse(String::from(input));
    let mut bfvm = BFVM::new(settings);

    let result = match tokens {
        LexResult::Success(t) => bfvm.run(t),
        _ =>  {
            println!("Error !");
            VMResult::Error { message : String::from("Uh oh") }
        }
    };
    println!();

    /* ---------------------------------------------------.
    |    Output Result                                    |
    '---------------------------------------------------- */
    let return_code = if result == VMResult::Success { 0 } else { 1 };
    process::exit(return_code);
}
<commit_msg>Added more comments to the main file for bf-cli<commit_after>// Load the main BF library
extern crate bf_lib;

// Import the tools we need from BF library
use bf_lib::traits::*;
use bf_lib::bf_lexer::BFLexer;
use bf_lib::bf_vm::BFVM;
use bf_lib::bf_vm::VMSettings;

// Import various STD library components
use std::process;
use std::fs::File;
use std::io::prelude::*;

// Command line arguments are parsed using a simpel state machine
#[derive(Debug)]
enum ArgumentMode {
    Skip,
    Start,
    Str,
    File,
}

// Reads a file and puts the contents into the out_str String.
fn read_file(in_str : String, mut out_str : &mut String ) {
    // TODO: Return an code here if needed and then print out
    //  a usable error message.
    // Currently panics on failure (expect)!
    let mut file = File::open(in_str).expect("Unable to open file.");
    file.read_to_string(&mut out_str).expect("Unable to read file.");
}

fn print_help() {
    println!("
Rust BrainFuck Interpreter

Usage:
    bf-cli <file>
    bf-cli <file> -u
    bf-cli ( -f | --file ) <file>
    bf-cli ( -s | --str ) <bfstring>

Options:
    -h --help       Shows this screen.
    -u --usermode   Input is prompted for.
");
}

fn main() {
    /* ---------------------------------------------------.
    |     Load Arguments                                  |
    '---------------------------------------------------- */

    // Argument Setup - Skip first argument as it's the binary location.
    let mut mode = ArgumentMode::Skip;
    let mut input = String::new();
    let mut settings = VMSettings::new();

    // Loop through each argument and set various settings as per the state
    // Aka if in Str mode the next argument will be considered the input.
    for argument in std::env::args() {
        match mode {
            ArgumentMode::Skip => mode = ArgumentMode::Start,
            ArgumentMode::Start => {
                match argument.as_ref() {
                    "-s" | "--str" => mode = ArgumentMode::Str,
                    "-f" | "--file" => mode = ArgumentMode::File,
                    "-h" | "--help" => {
                        print_help();
                        process::exit(1);
                    },
                    "-u" | "--usermode" => settings.prompt_for_input = true,
                    _ => read_file(argument, &mut input)
                };
            },
            ArgumentMode::Str => {
                input = argument;
                mode = ArgumentMode::Start;
            },
            ArgumentMode::File => {
                read_file(argument, &mut input);
                mode = ArgumentMode::Start;
            },
        }
    }

    /* ---------------------------------------------------.
    |    Interpret and Run Input                          |
    '---------------------------------------------------- */

    // Parse string input into Vector of BFTokens
    // This step also matches brackets up to each other
    let tokens = BFLexer::parse(String::from(input));

    // Create a new VM instance
    let mut bfvm = BFVM::new(settings);

    // If parsing was successful run the script,
    //  otherwise Error
    // Currently parsing can't fail.
    let result = match tokens {
        LexResult::Success(t) => bfvm.run(t),
        _ =>  {
            println!("Error !");
            VMResult::Error { message : String::from("Uh oh") }
        }
    };

    // In case there was no new line printed
    //  print one now before exit so prompt is on
    //  new line if running from command line.
    println!();

    /* ---------------------------------------------------.
    |    Output Result                                    |
    '---------------------------------------------------- */

    // Setup exit code - 0 = Success
    // Currently all error's except panics are 1
    let return_code = if result == VMResult::Success { 0 } else { 1 };
    process::exit(return_code);
}
<|endoftext|>


<commit_before>#![allow(missing_docs, unused_variables)]

mod pascal_str;
mod pascal_string;

pub use self::pascal_str::{Chars, Bytes, Lines, PascalStr};
pub use self::pascal_string::PascalString;

#[cfg(test)]
mod tests {
}
<commit_msg>Add some tests for utf8 string<commit_after>#![allow(missing_docs, unused_variables)]

mod pascal_str;
mod pascal_string;

pub use self::pascal_str::{Chars, Bytes, Lines, PascalStr};
pub use self::pascal_string::PascalString;

#[cfg(test)]
mod tests {
    use super::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};
    use std::iter::IntoIterator;

    /*
    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());

        let too_many_bytes = vec![12u8; 256];
        assert!(match PascalString::from(&too_many_bytes) {
            Err(PascalStringCreateError::InputTooLong) => true,
            _ => false
        });
    }
    */

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8 as char);
        string.push('l');
        string.push('L');
        string.push('o');
        string.push('\0');

        assert_eq!(string.as_str(), "heLlLo\0");
    }
}
<|endoftext|>


<commit_before>//! Interfaces for set-theoretic operations and relations on arbitrary types.
//!
//! These traits define interfaces for set-like operations on pre-defined
//! types, and when implemented for a type allow use of several
//! included algorithms.

use std::iter::Iterator;

/// Trait for checking if a set contains the given element.
pub trait Contains<E>
    where E: PartialEq
{
    /// Check if the set contains the given element.
    fn contains(&self, element: E) -> bool;
}

/// Interface used to check if a set contains zero elements.
pub trait IsEmpty {
    /// Check if the set is empty.
    fn is_empty(&self) -> bool;
}

/// Trait for checking if a particular set's members are all contained in
/// another set.
pub trait IsSubsetOf<S> {
    /// Determine whether all elements in this are also elements of the
    /// given set.
    fn is_subset_of(&self, other: &S) -> bool;
}

/// Trait for checking if a particular set contains all members of another set.
///
/// `IsSupersetOf<S>` is automatically defined for all types `T` where
/// `S: [IsSubsetOf](trait.IsSubsetOf.html)<T>`; therefore you should prefer to
/// implement `IsSubsetOf` instead.
pub trait IsSupersetOf<S> {
    /// Check if this set contains all elements of the given set.
    fn is_superset_of(&self, other: &S) -> bool;
}

impl<T, S> IsSupersetOf<S> for T
    where S: IsSubsetOf<T>
{
    #[inline(always)]
    fn is_superset_of(&self, other: &S) -> bool {
        other.is_subset_of(self)
    }
}

/// Trait for set types whose elements can be accessed by iteration.
pub trait IterableSet<'a, E: 'a> {
    /// Iterator type used when iterating over the set's elements.
    type Iter: Iterator<Item=&'a E>;

    /// Fetch an iterator over (references to) the members of the set.
    fn iter(&self) -> Self::Iter;
}

/// Trait for set types that support the [absolute
/// complement][absolute-complement] operation.
///
/// [absolute-complement]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Absolute_complement
pub trait Complement {
    /// Type returned by an instance's `complement()` method.
    type Output;

    /// Calculate the absolute complement of the set.
    fn complement(&self) -> Self::Output;
}

/// Trait for set types that support the [set-theoretic difference][setdiff]
/// operation, which is also called the relative complement.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Difference<S> {
    /// Type of the result of computing this difference.
    type Output;
    /// Calculate the set-theoretic difference of this set with the one given.
    fn difference(&self, other: &S) -> Self::Output;
}

/// Trait for computing the [set-theoretic difference][setdiff] in-place, modifying
/// the receiver.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Subtract<S> {
    /// Remove the values in `other` from `self`, and return `self`.
    fn subtract(&mut self, other: &S) -> &Self;
}

/// Utility for working with multiple sets as an aggregate.
pub struct AggregateSet<'a, S: 'a> {
    sets: Vec<&'a S>
}

impl<'a, S: 'a, E> Contains<E> for AggregateSet<'a, S>
    where S: Contains<E>, E: Copy + PartialEq
{
    #[inline]
    fn contains(&self, e: E) -> bool {
        self.sets.iter().any(|set| set.contains(e))
    }
}

impl<'a, S: 'a> IsSubsetOf<AggregateSet<'a, S>> for S
    where S: IsEmpty + IsSubsetOf<S> + Subtract<S> + Clone
{
    fn is_subset_of(&self, agg: &AggregateSet<'a, S>) -> bool {
        // If this set is empty, or is completely contained by any of the
        // aggregate's members, it's a subset.
        if self.is_empty() || agg.sets.iter().any(|set| self.is_subset_of(set)) {
            return true
        }

        // Otherwise we'll go the brute-force route: make a clone of `self`,
        // then subtract each member set from the clone until either the clone
        // is empty (=> this set is a subset of the aggregate) or we run out of
        // members (=> not a subset).
        let mut iter = agg.sets.iter();
        let mut diff = self.clone();

        while let Some(set) = iter.next() {
            if diff.subtract(set).is_empty() {
                return true;
            }
        }

        false
    }
}
<commit_msg>util/set: remove trait `Subtract`, modify `Difference`<commit_after>//! Interfaces for set-theoretic operations and relations on arbitrary types.
//!
//! These traits define interfaces for set-like operations on pre-defined
//! types, and when implemented for a type allow use of several
//! included algorithms.

use std::iter::Iterator;

/// Trait for checking if a set contains the given element.
pub trait Contains<E>
    where E: PartialEq
{
    /// Check if the set contains the given element.
    fn contains(&self, element: E) -> bool;
}

/// Interface used to check if a set contains zero elements.
pub trait IsEmpty {
    /// Check if the set is empty.
    fn is_empty(&self) -> bool;
}

/// Trait for checking if a particular set's members are all contained in
/// another set.
pub trait IsSubsetOf<S> {
    /// Determine whether all elements in this are also elements of the
    /// given set.
    fn is_subset_of(&self, other: &S) -> bool;
}

/// Trait for checking if a particular set contains all members of another set.
///
/// `IsSupersetOf<S>` is automatically defined for all types `T` where
/// `S: [IsSubsetOf](trait.IsSubsetOf.html)<T>`; therefore you should prefer to
/// implement `IsSubsetOf` instead.
pub trait IsSupersetOf<S> {
    /// Check if this set contains all elements of the given set.
    fn is_superset_of(&self, other: &S) -> bool;
}

impl<T, S> IsSupersetOf<S> for T
    where S: IsSubsetOf<T>
{
    #[inline(always)]
    fn is_superset_of(&self, other: &S) -> bool {
        other.is_subset_of(self)
    }
}

/// Trait for set types whose elements can be accessed by iteration.
pub trait IterableSet<'a, E: 'a> {
    /// Iterator type used when iterating over the set's elements.
    type Iter: Iterator<Item=&'a E>;

    /// Fetch an iterator over (references to) the members of the set.
    fn iter(&self) -> Self::Iter;
}

/// Trait for set types that support the [absolute
/// complement][absolute-complement] operation.
///
/// [absolute-complement]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Absolute_complement
pub trait Complement {
    /// Type returned by an instance's `complement()` method.
    type Output;

    /// Calculate the absolute complement of the set.
    fn complement(&self) -> Self::Output;
}

/// Trait for set types that support the [set-theoretic difference][setdiff]
/// operation, which is also called the relative complement.
///
/// [setdiff]: https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement
pub trait Difference<S> {
    /// Type of the result of computing this difference.
    type Output;
    /// Calculate the set-theoretic difference of this set with the one given.
    fn difference(self, other: &S) -> Self::Output;
}

/// Utility for working with multiple sets as an aggregate.
pub struct AggregateSet<'a, S: 'a> {
    sets: Vec<&'a S>
}

impl<'a, S: 'a, E> Contains<E> for AggregateSet<'a, S>
    where S: Contains<E>, E: Copy + PartialEq
{
    #[inline]
    fn contains(&self, e: E) -> bool {
        self.sets.iter().any(|set| set.contains(e))
    }
}

impl<'a, S: 'a> IsSubsetOf<AggregateSet<'a, S>> for S
    where S: IsEmpty + IsSubsetOf<S> + Subtract<S> + Clone
{
    fn is_subset_of(&self, agg: &AggregateSet<'a, S>) -> bool {
        // If this set is empty, or is completely contained by any of the
        // aggregate's members, it's a subset.
        if self.is_empty() || agg.sets.iter().any(|set| self.is_subset_of(set)) {
            return true
        }

        // Otherwise we'll go the brute-force route: make a clone of `self`,
        // then subtract each member set from the clone until either the clone
        // is empty (=> this set is a subset of the aggregate) or we run out of
        // members (=> not a subset).
        let mut iter = agg.sets.iter();
        let mut diff = self.clone();

        while let Some(set) = iter.next() {
            if diff.subtract(set).is_empty() {
                return true;
            }
        }

        false
    }
}
<|endoftext|>


<commit_before>//! sans-server – Libreflip sans server daemon
//!
//! The design principle for this software is taken from Aouglas Adams:
//!
//! > Don't Panic!
//!
//! Also something about towels.
//!
//! The daemon should never just stop. Every possible error needs to be wrapped
//! into a Result<_> and communicate them to the user interface. Any actual panic
//! is a condition in the operation that prevents communication with the UI. These
//! should however still be logged.
#![feature(custom_derive, plugin, decl_macro)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate rocket;
extern crate rocket_contrib;
extern crate sans_core;
extern crate sans_types;

use rocket::http::RawStr;
use rocket::request::{Form, FromFormValue};
use rocket::response::Redirect;

use rocket::response::NamedFile;

use sans_core::{Camera, CameraTrait, CameraType};
use std::io::{self, stdin};
use std::path::{Path, PathBuf};

#[derive(FromForm)]
struct CaptureRequest {}

#[post("/shoot", data = "<_form>")]
fn shoot(_form: Form<CaptureRequest>) -> Result<Redirect, String> {
    println!("Capturing new pictures!");

    let left = Camera::new("/dev/video0".into(), CameraType::Left).unwrap();
    left.capture_image().unwrap();

    let right = Camera::new("/dev/video0".into(), CameraType::Right).unwrap();
    right.capture_image().unwrap();

    Ok(Redirect::to("/"))
}

#[get("/")]
pub fn index() -> io::Result<NamedFile> {
    NamedFile::open("static/index.html")
}

fn rocket() -> rocket::Rocket {
    rocket::ignite().mount("/", routes![index, shoot])
}

fn main() {
    rocket().launch();
}

// fn main() {
// for n in 0..=11 {
//     let left = Camera::new(&format!("/dev/video{}", n), CameraType::Left).unwrap();
//     print!("Camera: {}", n);
//     match left.capture_image() {
//         Ok(_) => println!("OK!"),
//         Err(_) => println!("FAILED"),
//     };
// }
// }

// let right = Camera::new("/dev/video1".into(), CameraType::Right).unwrap();

// println!("Press <enter> to take two pictures – reload your browser after");
// loop {
//     let mut _s = String::new();
//     stdin()
//         .read_line(&mut _s)
//         .expect("Failed to read user input!");

//     right.capture_image().unwrap();
//     println!("*click*");
//     }
// }
<commit_msg>Camera finder<commit_after>//! sans-server – Libreflip sans server daemon
//!
//! The design principle for this software is taken from Aouglas Adams:
//!
//! > Don't Panic!
//!
//! Also something about towels.
//!
//! The daemon should never just stop. Every possible error needs to be wrapped
//! into a Result<_> and communicate them to the user interface. Any actual panic
//! is a condition in the operation that prevents communication with the UI. These
//! should however still be logged.
#![feature(custom_derive, plugin, decl_macro)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate rocket;
extern crate rocket_contrib;
extern crate sans_core;
extern crate sans_types;

use rocket::http::RawStr;
use rocket::request::{Form, FromFormValue};
use rocket::response::Redirect;

use rocket::response::NamedFile;

use sans_core::{Camera, CameraTrait, CameraType};
use std::io::{self, stdin};
use std::path::{Path, PathBuf};

#[derive(FromForm)]
struct CaptureRequest {}

#[post("/shoot", data = "<_form>")]
fn shoot(_form: Form<CaptureRequest>) -> Result<Redirect, String> {
    println!("Capturing new pictures!");

    let left = Camera::new("/dev/video0".into(), CameraType::Left).unwrap();
    left.capture_image().unwrap();

    let right = Camera::new("/dev/video0".into(), CameraType::Right).unwrap();
    right.capture_image().unwrap();

    Ok(Redirect::to("/"))
}

#[get("/")]
pub fn index() -> io::Result<NamedFile> {
    NamedFile::open("static/index.html")
}

fn rocket() -> rocket::Rocket {
    rocket::ignite().mount("/", routes![index, shoot])
}

// fn main() {
//     rocket().launch();
// }

fn main() {
    for n in 0..=11 {
        print!("Camera: {}", n);
        let left = match Camera::new(&format!("/dev/video{}", n), CameraType::Left) {
            Ok(c) => c,
            _ => continue
        };
        match left.capture_image() {
            Ok(_) => println!("OK!"),
            Err(_) => println!("FAILED"),
        };
    }
}

// let right = Camera::new("/dev/video1".into(), CameraType::Right).unwrap();

// println!("Press <enter> to take two pictures – reload your browser after");
// loop {
//     let mut _s = String::new();
//     stdin()
//         .read_line(&mut _s)
//         .expect("Failed to read user input!");

//     right.capture_image().unwrap();
//     println!("*click*");
//     }
// }
<|endoftext|>


<commit_before>use std::path::Path;

use clap::ArgMatches;
use log::LevelFilter;
use log4rs::{
    append::console::{ConsoleAppender, Target},
    config::{Appender, Config, Logger, Root},
    encode::pattern::PatternEncoder,
};

pub fn init_with_file<P>(path: P)
where
    P: AsRef<Path>,
{
    log4rs::init_file(path, Default::default()).expect("init logging with file");
}

pub fn init_with_config(bin_name: &str, matches: &ArgMatches) {
    let debug_level = matches.occurrences_of("VERBOSE");
    let without_time = matches.is_present("LOG_WITHOUT_TIME");

    let mut pattern = String::new();
    if !without_time {
        pattern += "{d} ";
    }
    pattern += "{h({l}):<5} ";
    if debug_level >= 1 {
        pattern += "[{P}:{I}] [{M}] ";
    }
    pattern += "{m}{n}";

    let logging_builder = Config::builder().appender(
        Appender::builder().build(
            "console",
            Box::new(
                ConsoleAppender::builder()
                    .encoder(Box::new(PatternEncoder::new(&pattern)))
                    .target(Target::Stderr)
                    .build(),
            ),
        ),
    );

    let config = match debug_level {
        0 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Info))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Info))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Info))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        1 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Debug))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Debug))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Debug))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        2 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        3 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .build(Root::builder().appender("console").build(LevelFilter::Debug)),
        _ => logging_builder.build(Root::builder().appender("console").build(LevelFilter::Trace)),
    }
    .expect("logging");

    log4rs::init_config(config).expect("logging");
}
<commit_msg>Removed duplicated shadowsocks Logger<commit_after>use std::path::Path;

use clap::ArgMatches;
use log::LevelFilter;
use log4rs::{
    append::console::{ConsoleAppender, Target},
    config::{Appender, Config, Logger, Root},
    encode::pattern::PatternEncoder,
};

pub fn init_with_file<P>(path: P)
where
    P: AsRef<Path>,
{
    log4rs::init_file(path, Default::default()).expect("init logging with file");
}

pub fn init_with_config(bin_name: &str, matches: &ArgMatches) {
    let debug_level = matches.occurrences_of("VERBOSE");
    let without_time = matches.is_present("LOG_WITHOUT_TIME");

    let mut pattern = String::new();
    if !without_time {
        pattern += "{d} ";
    }
    pattern += "{h({l}):<5} ";
    if debug_level >= 1 {
        pattern += "[{P}:{I}] [{M}] ";
    }
    pattern += "{m}{n}";

    let logging_builder = Config::builder().appender(
        Appender::builder().build(
            "console",
            Box::new(
                ConsoleAppender::builder()
                    .encoder(Box::new(PatternEncoder::new(&pattern)))
                    .target(Target::Stderr)
                    .build(),
            ),
        ),
    );

    let config = match debug_level {
        0 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Info))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Info))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        1 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Debug))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Debug))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        2 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .build(Root::builder().appender("console").build(LevelFilter::Off)),
        3 => logging_builder
            .logger(Logger::builder().build(bin_name, LevelFilter::Trace))
            .logger(Logger::builder().build("shadowsocks", LevelFilter::Trace))
            .build(Root::builder().appender("console").build(LevelFilter::Debug)),
        _ => logging_builder.build(Root::builder().appender("console").build(LevelFilter::Trace)),
    }
    .expect("logging");

    log4rs::init_config(config).expect("logging");
}
<|endoftext|>


<commit_before><commit_msg>changes: remove warning about mutuability<commit_after><|endoftext|>


<commit_before><commit_msg>update docs<commit_after><|endoftext|>


<commit_before><commit_msg>Further work on configuration file<commit_after><|endoftext|>


<commit_before>use vm::Value;
use std::rc::Rc;

#[experimental]
pub struct Gc {
  /// Describe the GC roots that we have. These are stack values.
  roots: ~[Rc<Value>]
}

#[experimental]
impl Gc {
  pub fn new() -> Gc {
    Gc {
      roots: ~[]
    }
  }

  pub fn register_root(&mut self, root: Rc<Value>) {
    self.roots.push(root);
  }
}

#[cfg(test)]
mod test {
  use super::Gc;
  use vm::Value;
  use vm::Int;
  use std::rc::Rc;

  #[test]
  fn should_have_empty_roots() {
    let gc = Gc::new();
    assert_eq!(gc.roots.len(), 0);
  }

  #[test]
  fn should_add_root() {
    let val = Int(55);
    let mut gc = Gc::new();
    gc.register_root(Rc::new(val));
  }

}<commit_msg>added assert<commit_after>use vm::Value;
use std::rc::Rc;

#[experimental]
pub struct Gc {
  /// Describe the GC roots that we have. These are stack values.
  roots: ~[Rc<Value>]
}

#[experimental]
impl Gc {
  pub fn new() -> Gc {
    Gc {
      roots: ~[]
    }
  }

  pub fn register_root(&mut self, root: Rc<Value>) {
    self.roots.push(root);
  }
}

#[cfg(test)]
mod test {
  use super::Gc;
  use vm::Value;
  use vm::Int;
  use std::rc::Rc;

  #[test]
  fn should_have_empty_roots() {
    let gc = Gc::new();
    assert_eq!(gc.roots.len(), 0);
  }

  #[test]
  fn should_add_root() {
    let val = Int(55);
    let mut gc = Gc::new();
    gc.register_root(Rc::new(val));

    assert_eq!(gc.roots.len(), 1);
  }

}<|endoftext|>


<commit_before><commit_msg>Consistent function naming<commit_after><|endoftext|>


<commit_before><commit_msg>rollup merge of #20754: nikomatsakis/int-feature<commit_after><|endoftext|>


<commit_before><commit_msg>Add on_change callback<commit_after><|endoftext|>


<commit_before><commit_msg>test update.<commit_after><|endoftext|>


<commit_before><commit_msg>add @antiguru tests<commit_after><|endoftext|>


<commit_before>//! Runfiles lookup library for Bazel-built Rust binaries and tests.
//!
//! USAGE:
//!
//! 1.  Depend on this runfiles library from your build rule:
//!     ```python
//!       rust_binary(
//!           name = "my_binary",
//!           ...
//!           data = ["//path/to/my/data.txt"],
//!           deps = ["@rules_rust//tools/runfiles"],
//!       )
//!     ```
//!
//! 2.  Import the runfiles library.
//!     ```ignore
//!     extern crate runfiles;
//!
//!     use runfiles::Runfiles;
//!     ```
//!
//! 3.  Create a Runfiles object and use rlocation to look up runfile paths:
//!     ```ignore -- This doesn't work under rust_doc_test because argv[0] is not what we expect.
//!
//!     use runfiles::Runfiles;
//!
//!     let r = Runfiles::create().unwrap();
//!     let path = r.rlocation("my_workspace/path/to/my/data.txt");
//!
//!     let f = File::open(path).unwrap();
//!     // ...
//!     ```

use std::collections::HashMap;
use std::env;
use std::ffi::OsString;
use std::fs;
use std::io;
use std::path::Path;
use std::path::PathBuf;

enum Mode {
    DirectoryBased(PathBuf),
    ManifestBased(HashMap<PathBuf, PathBuf>),
}

pub struct Runfiles {
    mode: Mode,
}

impl Runfiles {
    /// Creates a manifest based Runfiles object when
    /// RUNFILES_MANIFEST_ONLY environment variable is present,
    /// or a directory based Runfiles object otherwise.
    pub fn create() -> io::Result<Self> {
        if is_manifest_only() {
            Self::create_manifest_based()
        } else {
            Self::create_directory_based()
        }
    }

    fn create_directory_based() -> io::Result<Self> {
        Ok(Runfiles {
            mode: Mode::DirectoryBased(find_runfiles_dir()?),
        })
    }

    fn create_manifest_based() -> io::Result<Self> {
        let manifest_path = find_manifest_path()?;
        let manifest_content = std::fs::read_to_string(manifest_path)?;
        let path_mapping = manifest_content
            .lines()
            .map(|line| {
                let pair = line
                    .split_once(" ")
                    .expect("manifest file contained unexpected content");
                (pair.0.into(), pair.1.into())
            })
            .collect::<HashMap<_, _>>();
        Ok(Runfiles {
            mode: Mode::ManifestBased(path_mapping),
        })
    }

    /// Returns the runtime path of a runfile.
    ///
    /// Runfiles are data-dependencies of Bazel-built binaries and tests.
    /// The returned path may not be valid. The caller should check the path's
    /// validity and that the path exists.
    pub fn rlocation(&self, path: impl AsRef<Path>) -> PathBuf {
        let path = path.as_ref();
        if path.is_absolute() {
            return path.to_path_buf();
        }
        match &self.mode {
            Mode::DirectoryBased(runfiles_dir) => runfiles_dir.join(path),
            Mode::ManifestBased(path_mapping) => path_mapping
                .get(path)
                .unwrap_or_else(|| {
                    panic!("Path {} not found among runfiles.", path.to_string_lossy())
                })
                .clone(),
        }
    }
}

/// Returns the .runfiles directory for the currently executing binary.
pub fn find_runfiles_dir() -> io::Result<PathBuf> {
    assert_ne!(
        std::env::var_os("RUNFILES_MANIFEST_ONLY").unwrap_or_else(|| OsString::from("0")),
        "1"
    );

    // If bazel told us about the runfiles dir, use that without looking further.
    if let Some(test_srcdir) = std::env::var_os("TEST_SRCDIR").map(PathBuf::from) {
        if test_srcdir.is_dir() {
            return Ok(test_srcdir);
        }
    }

    // Consume the first argument (argv[0])
    let exec_path = std::env::args().next().expect("arg 0 was not set");

    let mut binary_path = PathBuf::from(&exec_path);
    loop {
        // Check for our neighboring $binary.runfiles directory.
        let mut runfiles_name = binary_path.file_name().unwrap().to_owned();
        runfiles_name.push(".runfiles");

        let runfiles_path = binary_path.with_file_name(&runfiles_name);
        if runfiles_path.is_dir() {
            return Ok(runfiles_path);
        }

        // Check if we're already under a *.runfiles directory.
        {
            // TODO: 1.28 adds Path::ancestors() which is a little simpler.
            let mut next = binary_path.parent();
            while let Some(ancestor) = next {
                if ancestor
                    .file_name()
                    .map_or(false, |f| f.to_string_lossy().ends_with(".runfiles"))
                {
                    return Ok(ancestor.to_path_buf());
                }
                next = ancestor.parent();
            }
        }

        if !fs::symlink_metadata(&binary_path)?.file_type().is_symlink() {
            break;
        }
        // Follow symlinks and keep looking.
        let link_target = binary_path.read_link()?;
        binary_path = if link_target.is_absolute() {
            link_target
        } else {
            let link_dir = binary_path.parent().unwrap();
            env::current_dir()?.join(link_dir).join(link_target)
        }
    }

    Err(make_io_error("failed to find .runfiles directory"))
}

fn make_io_error(msg: &str) -> io::Error {
    io::Error::new(io::ErrorKind::Other, msg)
}

fn is_manifest_only() -> bool {
    match std::env::var("RUNFILES_MANIFEST_ONLY") {
        Ok(val) => val == "1",
        Err(_) => false,
    }
}

fn find_manifest_path() -> io::Result<PathBuf> {
    assert_eq!(
        std::env::var_os("RUNFILES_MANIFEST_ONLY").expect("RUNFILES_MANIFEST_ONLY was not set"),
        OsString::from("1")
    );
    match std::env::var_os("RUNFILES_MANIFEST_FILE") {
        Some(path) => Ok(path.into()),
        None => Err(
            make_io_error(
                "RUNFILES_MANIFEST_ONLY was set to '1', but RUNFILES_MANIFEST_FILE was not set. Did Bazel change?"))
    }
}

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

    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_can_read_data_from_runfiles() {
        // We want to run two test cases: one with the $TEST_SRCDIR environment variable set and one
        // with it not set. Since environment variables are global state, we need to ensure the two
        // test cases do not run concurrently. Rust runs tests in parallel and does not provide an
        // easy way to synchronise them, so we run both test cases in the same #[test] function.

        let test_srcdir = env::var_os("TEST_SRCDIR").expect("bazel did not provide TEST_SRCDIR");

        // Test case 1: $TEST_SRCDIR is set.
        {
            let r = Runfiles::create().unwrap();

            let mut f =
                File::open(r.rlocation("rules_rust/tools/runfiles/data/sample.txt")).unwrap();

            let mut buffer = String::new();
            f.read_to_string(&mut buffer).unwrap();

            assert_eq!("Example Text!", buffer);
        }

        // Test case 2: $TEST_SRCDIR is *not* set.
        {
            env::remove_var("TEST_SRCDIR");

            let r = Runfiles::create().unwrap();

            let mut f =
                File::open(r.rlocation("rules_rust/tools/runfiles/data/sample.txt")).unwrap();

            let mut buffer = String::new();
            f.read_to_string(&mut buffer).unwrap();

            assert_eq!("Example Text!", buffer);

            env::set_var("TEST_SRCDIR", test_srcdir);
        }
    }

    #[test]
    fn test_manifest_based_can_read_data_from_runfiles() {
        let mut path_mapping = HashMap::new();
        path_mapping.insert("a/b".into(), "c/d".into());
        let r = Runfiles {
            mode: Mode::ManifestBased(path_mapping),
        };

        assert_eq!(r.rlocation("a/b"), PathBuf::from("c/d"));
    }
}
<commit_msg>Derive Debug for runfiles (#1037)<commit_after>//! Runfiles lookup library for Bazel-built Rust binaries and tests.
//!
//! USAGE:
//!
//! 1.  Depend on this runfiles library from your build rule:
//!     ```python
//!       rust_binary(
//!           name = "my_binary",
//!           ...
//!           data = ["//path/to/my/data.txt"],
//!           deps = ["@rules_rust//tools/runfiles"],
//!       )
//!     ```
//!
//! 2.  Import the runfiles library.
//!     ```ignore
//!     extern crate runfiles;
//!
//!     use runfiles::Runfiles;
//!     ```
//!
//! 3.  Create a Runfiles object and use rlocation to look up runfile paths:
//!     ```ignore -- This doesn't work under rust_doc_test because argv[0] is not what we expect.
//!
//!     use runfiles::Runfiles;
//!
//!     let r = Runfiles::create().unwrap();
//!     let path = r.rlocation("my_workspace/path/to/my/data.txt");
//!
//!     let f = File::open(path).unwrap();
//!     // ...
//!     ```

use std::collections::HashMap;
use std::env;
use std::ffi::OsString;
use std::fs;
use std::io;
use std::path::Path;
use std::path::PathBuf;

#[derive(Debug)]
enum Mode {
    DirectoryBased(PathBuf),
    ManifestBased(HashMap<PathBuf, PathBuf>),
}

#[derive(Debug)]
pub struct Runfiles {
    mode: Mode,
}

impl Runfiles {
    /// Creates a manifest based Runfiles object when
    /// RUNFILES_MANIFEST_ONLY environment variable is present,
    /// or a directory based Runfiles object otherwise.
    pub fn create() -> io::Result<Self> {
        if is_manifest_only() {
            Self::create_manifest_based()
        } else {
            Self::create_directory_based()
        }
    }

    fn create_directory_based() -> io::Result<Self> {
        Ok(Runfiles {
            mode: Mode::DirectoryBased(find_runfiles_dir()?),
        })
    }

    fn create_manifest_based() -> io::Result<Self> {
        let manifest_path = find_manifest_path()?;
        let manifest_content = std::fs::read_to_string(manifest_path)?;
        let path_mapping = manifest_content
            .lines()
            .map(|line| {
                let pair = line
                    .split_once(" ")
                    .expect("manifest file contained unexpected content");
                (pair.0.into(), pair.1.into())
            })
            .collect::<HashMap<_, _>>();
        Ok(Runfiles {
            mode: Mode::ManifestBased(path_mapping),
        })
    }

    /// Returns the runtime path of a runfile.
    ///
    /// Runfiles are data-dependencies of Bazel-built binaries and tests.
    /// The returned path may not be valid. The caller should check the path's
    /// validity and that the path exists.
    pub fn rlocation(&self, path: impl AsRef<Path>) -> PathBuf {
        let path = path.as_ref();
        if path.is_absolute() {
            return path.to_path_buf();
        }
        match &self.mode {
            Mode::DirectoryBased(runfiles_dir) => runfiles_dir.join(path),
            Mode::ManifestBased(path_mapping) => path_mapping
                .get(path)
                .unwrap_or_else(|| {
                    panic!("Path {} not found among runfiles.", path.to_string_lossy())
                })
                .clone(),
        }
    }
}

/// Returns the .runfiles directory for the currently executing binary.
pub fn find_runfiles_dir() -> io::Result<PathBuf> {
    assert_ne!(
        std::env::var_os("RUNFILES_MANIFEST_ONLY").unwrap_or_else(|| OsString::from("0")),
        "1"
    );

    // If bazel told us about the runfiles dir, use that without looking further.
    if let Some(test_srcdir) = std::env::var_os("TEST_SRCDIR").map(PathBuf::from) {
        if test_srcdir.is_dir() {
            return Ok(test_srcdir);
        }
    }

    // Consume the first argument (argv[0])
    let exec_path = std::env::args().next().expect("arg 0 was not set");

    let mut binary_path = PathBuf::from(&exec_path);
    loop {
        // Check for our neighboring $binary.runfiles directory.
        let mut runfiles_name = binary_path.file_name().unwrap().to_owned();
        runfiles_name.push(".runfiles");

        let runfiles_path = binary_path.with_file_name(&runfiles_name);
        if runfiles_path.is_dir() {
            return Ok(runfiles_path);
        }

        // Check if we're already under a *.runfiles directory.
        {
            // TODO: 1.28 adds Path::ancestors() which is a little simpler.
            let mut next = binary_path.parent();
            while let Some(ancestor) = next {
                if ancestor
                    .file_name()
                    .map_or(false, |f| f.to_string_lossy().ends_with(".runfiles"))
                {
                    return Ok(ancestor.to_path_buf());
                }
                next = ancestor.parent();
            }
        }

        if !fs::symlink_metadata(&binary_path)?.file_type().is_symlink() {
            break;
        }
        // Follow symlinks and keep looking.
        let link_target = binary_path.read_link()?;
        binary_path = if link_target.is_absolute() {
            link_target
        } else {
            let link_dir = binary_path.parent().unwrap();
            env::current_dir()?.join(link_dir).join(link_target)
        }
    }

    Err(make_io_error("failed to find .runfiles directory"))
}

fn make_io_error(msg: &str) -> io::Error {
    io::Error::new(io::ErrorKind::Other, msg)
}

fn is_manifest_only() -> bool {
    match std::env::var("RUNFILES_MANIFEST_ONLY") {
        Ok(val) => val == "1",
        Err(_) => false,
    }
}

fn find_manifest_path() -> io::Result<PathBuf> {
    assert_eq!(
        std::env::var_os("RUNFILES_MANIFEST_ONLY").expect("RUNFILES_MANIFEST_ONLY was not set"),
        OsString::from("1")
    );
    match std::env::var_os("RUNFILES_MANIFEST_FILE") {
        Some(path) => Ok(path.into()),
        None => Err(
            make_io_error(
                "RUNFILES_MANIFEST_ONLY was set to '1', but RUNFILES_MANIFEST_FILE was not set. Did Bazel change?"))
    }
}

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

    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_can_read_data_from_runfiles() {
        // We want to run two test cases: one with the $TEST_SRCDIR environment variable set and one
        // with it not set. Since environment variables are global state, we need to ensure the two
        // test cases do not run concurrently. Rust runs tests in parallel and does not provide an
        // easy way to synchronise them, so we run both test cases in the same #[test] function.

        let test_srcdir = env::var_os("TEST_SRCDIR").expect("bazel did not provide TEST_SRCDIR");

        // Test case 1: $TEST_SRCDIR is set.
        {
            let r = Runfiles::create().unwrap();

            let mut f =
                File::open(r.rlocation("rules_rust/tools/runfiles/data/sample.txt")).unwrap();

            let mut buffer = String::new();
            f.read_to_string(&mut buffer).unwrap();

            assert_eq!("Example Text!", buffer);
        }

        // Test case 2: $TEST_SRCDIR is *not* set.
        {
            env::remove_var("TEST_SRCDIR");

            let r = Runfiles::create().unwrap();

            let mut f =
                File::open(r.rlocation("rules_rust/tools/runfiles/data/sample.txt")).unwrap();

            let mut buffer = String::new();
            f.read_to_string(&mut buffer).unwrap();

            assert_eq!("Example Text!", buffer);

            env::set_var("TEST_SRCDIR", test_srcdir);
        }
    }

    #[test]
    fn test_manifest_based_can_read_data_from_runfiles() {
        let mut path_mapping = HashMap::new();
        path_mapping.insert("a/b".into(), "c/d".into());
        let r = Runfiles {
            mode: Mode::ManifestBased(path_mapping),
        };

        assert_eq!(r.rlocation("a/b"), PathBuf::from("c/d"));
    }
}
<|endoftext|>


<commit_before><commit_msg>fmt! is now deprecatedt<commit_after><|endoftext|>


<commit_before>use std::result::Result;
use std::marker::PhantomData;
use std::error::Error;
use serde::*;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;

///
/// Represents a tool made from a function
///
pub struct FnTool<TIn: Deserialize, TOut: Serialize, TErr: Serialize> {
    function: Box<Fn(TIn) -> Result<TOut, TErr>>
}

///
/// Creates a Tool from a function that can produce an error but does not use an environment
///
pub fn make_tool<TIn: Deserialize, TOut: Serialize, TErr: Serialize, F: 'static+Fn(TIn) -> Result<TOut, TErr>>(function: F) -> FnTool<TIn, TOut, TErr> {
    FnTool { function: Box::new(function) }
}

///
/// Creates a Tool from a function that cannot produce an error and doesn't use an environment
///
pub fn make_pure_tool<TIn: Deserialize, TOut: Serialize, F: 'static+Fn(TIn) -> TOut>(function: F) -> FnTool<TIn, TOut, ()> {
    make_tool(move |input| { Ok(function(input)) })
}

impl<TIn, TOut, TErr> Tool for FnTool<TIn, TOut, TErr>
where TIn: Deserialize, TOut: Serialize, TErr: Serialize {
    fn invoke_json(&self, input: Value, _environment: &Environment) -> Result<Value, Value> {
        // Decode
        let input_decoded = from_value::<TIn>(input);

        // Chain into the tool itself
        match input_decoded {
            Ok(input_decoded) => {
                // Successfully decoded as the tool's input format
                let result = (self.function)(input_decoded);

                // Encode the error or the result
                // The encoding can go wrong, and we need to handle it slightly differently for the error or the success case
                match result {
                    Ok(res) => {
                        let encoded = to_value(res);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "JSON encode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(erm) => {
                        let encoded = to_value(erm);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Error encode failed",
                                "description":  erm.description()
                            }])
                        }
                    }
                }
            },

            Err(input_error) => {
                // Input does not match the format expected by the tool
                Err(json![{
                    "error":        "JSON input decode failed",
                    "description":  input_error.description(),
                }])
            }
        }
    }
}

///
/// Represents a tool with Rust types
///
pub struct TypedTool<'a, TIn: Serialize, TOut: Deserialize> {
    param1: PhantomData<TIn>,
    param2: PhantomData<TOut>,
    tool: &'a Tool
}

impl<'a, TIn: Serialize, TOut: Deserialize> TypedTool<'a, TIn, TOut> {
    ///
    /// Creates an object that can be used to invoke a tool with typed parameters instead of pure JSON
    ///
    pub fn from(tool: &'a Tool) -> TypedTool<'a, TIn, TOut> {
        TypedTool { param1: PhantomData, param2: PhantomData, tool: tool }
    }

    ///
    /// Invokes this tool
    ///
    pub fn invoke(&self, input: TIn, environment: &Environment) -> Result<TOut, Value> {
        let json_input = to_value(input);

        match json_input {
            Ok(json_input) => {
                let json_output = self.tool.invoke_json(json_input, environment);

                match json_output {
                    Ok(json_output) => {
                        let result = from_value::<TOut>(json_output);
                        match result {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Result decode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(json_error) => {
                        Err(json_error)
                    }
                }
            },

            Err(erm) => {
                Err(json![{
                    "error":        "Input encode failed",
                    "description":  erm.description()
                }])
            }
        }
    }
}

    /* -- Would like to be able to do this too, but can't figure out how to get the type system to accept it
///
/// Makes a function that can be called to invoke a particular tool
///
pub fn make_fn_from_tool<'a, TIn, TOut, F>(tool: &'a Tool) -> Box<F>
where
    TIn: Serialize,
    TOut: Deserialize,
    F: Fn(TIn, &Environment) -> Result<TOut, Value> {
    Box::new(move |input: TIn, environment: &Environment| {
        let json_input = to_value(input);

        match json_input {
            Ok(json_input) => {
                let json_output = tool.invoke_json(json_input, environment);

                match json_output {
                    Ok(json_output) => {
                        let result = from_value::<TOut>(json_output);
                        match result {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Result decode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(json_error) => {
                        Err(json_error)
                    }
                }
            },

            Err(erm) => {
                Err(json![{
                    "error":        "Input encode failed",
                    "description":  erm.description()
                }])
            }
        }
    })
}
    */

#[cfg(test)]
mod test {
    use super::super::super::*;
    use super::super::*;
    use std::result::Result;
    use serde_json::*;

    #[derive(Serialize, Deserialize)]
    struct TestIn {
        input: i32
    }

    #[derive(Serialize, Deserialize, PartialEq, Eq)]
    struct TestOut {
        output: i32
    }

    fn test_tool(x: TestIn) -> Result<TestOut, ()> {
        Ok(TestOut { output: x.input + 1 })
    }

    #[test]
    fn can_call_tool_via_json_interface() {
        let tool        = make_tool(test_tool);
        let environment = EmptyEnvironment::new();
        let result      = tool.invoke_json(json![{ "input": 4 }], &environment);

        assert!(result == Ok(json![{ "output": 5 }]));
    }

    #[test]
    fn can_call_tool_via_typed_interface() {
        let tool        = make_pure_tool(|x: i32| { x+1 });
        let environment = EmptyEnvironment::new();

        let typed_tool  = TypedTool::from(&tool);
        let result      = typed_tool.invoke(4, &environment);

        assert!(result == Ok(5));
    }
}
<commit_msg>Remove commented out code<commit_after>use std::result::Result;
use std::marker::PhantomData;
use std::error::Error;
use serde::*;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;

///
/// Represents a tool made from a function
///
pub struct FnTool<TIn: Deserialize, TOut: Serialize, TErr: Serialize> {
    function: Box<Fn(TIn) -> Result<TOut, TErr>>
}

///
/// Creates a Tool from a function that can produce an error but does not use an environment
///
pub fn make_tool<TIn: Deserialize, TOut: Serialize, TErr: Serialize, F: 'static+Fn(TIn) -> Result<TOut, TErr>>(function: F) -> FnTool<TIn, TOut, TErr> {
    FnTool { function: Box::new(function) }
}

///
/// Creates a Tool from a function that cannot produce an error and doesn't use an environment
///
pub fn make_pure_tool<TIn: Deserialize, TOut: Serialize, F: 'static+Fn(TIn) -> TOut>(function: F) -> FnTool<TIn, TOut, ()> {
    make_tool(move |input| { Ok(function(input)) })
}

impl<TIn, TOut, TErr> Tool for FnTool<TIn, TOut, TErr>
where TIn: Deserialize, TOut: Serialize, TErr: Serialize {
    fn invoke_json(&self, input: Value, _environment: &Environment) -> Result<Value, Value> {
        // Decode
        let input_decoded = from_value::<TIn>(input);

        // Chain into the tool itself
        match input_decoded {
            Ok(input_decoded) => {
                // Successfully decoded as the tool's input format
                let result = (self.function)(input_decoded);

                // Encode the error or the result
                // The encoding can go wrong, and we need to handle it slightly differently for the error or the success case
                match result {
                    Ok(res) => {
                        let encoded = to_value(res);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "JSON encode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(erm) => {
                        let encoded = to_value(erm);
                        match encoded {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Error encode failed",
                                "description":  erm.description()
                            }])
                        }
                    }
                }
            },

            Err(input_error) => {
                // Input does not match the format expected by the tool
                Err(json![{
                    "error":        "JSON input decode failed",
                    "description":  input_error.description(),
                }])
            }
        }
    }
}

///
/// Represents a tool with Rust types
///
pub struct TypedTool<'a, TIn: Serialize, TOut: Deserialize> {
    param1: PhantomData<TIn>,
    param2: PhantomData<TOut>,
    tool: &'a Tool
}

impl<'a, TIn: Serialize, TOut: Deserialize> TypedTool<'a, TIn, TOut> {
    ///
    /// Creates an object that can be used to invoke a tool with typed parameters instead of pure JSON
    ///
    pub fn from(tool: &'a Tool) -> TypedTool<'a, TIn, TOut> {
        TypedTool { param1: PhantomData, param2: PhantomData, tool: tool }
    }

    ///
    /// Invokes this tool
    ///
    pub fn invoke(&self, input: TIn, environment: &Environment) -> Result<TOut, Value> {
        let json_input = to_value(input);

        match json_input {
            Ok(json_input) => {
                let json_output = self.tool.invoke_json(json_input, environment);

                match json_output {
                    Ok(json_output) => {
                        let result = from_value::<TOut>(json_output);
                        match result {
                            Ok(final_value) => Ok(final_value),
                            Err(erm)        => Err(json![{
                                "error":        "Result decode failed",
                                "description":  erm.description()
                            }])
                        }
                    },

                    Err(json_error) => {
                        Err(json_error)
                    }
                }
            },

            Err(erm) => {
                Err(json![{
                    "error":        "Input encode failed",
                    "description":  erm.description()
                }])
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::super::super::*;
    use super::super::*;
    use std::result::Result;
    use serde_json::*;

    #[derive(Serialize, Deserialize)]
    struct TestIn {
        input: i32
    }

    #[derive(Serialize, Deserialize, PartialEq, Eq)]
    struct TestOut {
        output: i32
    }

    fn test_tool(x: TestIn) -> Result<TestOut, ()> {
        Ok(TestOut { output: x.input + 1 })
    }

    #[test]
    fn can_call_tool_via_json_interface() {
        let tool        = make_tool(test_tool);
        let environment = EmptyEnvironment::new();
        let result      = tool.invoke_json(json![{ "input": 4 }], &environment);

        assert!(result == Ok(json![{ "output": 5 }]));
    }

    #[test]
    fn can_call_tool_via_typed_interface() {
        let tool        = make_pure_tool(|x: i32| { x+1 });
        let environment = EmptyEnvironment::new();

        let typed_tool  = TypedTool::from(&tool);
        let result      = typed_tool.invoke(4, &environment);

        assert!(result == Ok(5));
    }
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DataEnum, DataStruct, DeriveInput, Error, Result, FieldsNamed, FieldsUnnamed, Fields};

pub fn derive(input: &DeriveInput) -> Result<TokenStream> {
    match &input.data {
        Data::Struct(data) => struct_error(input, data),
        Data::Enum(data) => enum_error(input, data),
        Data::Union(_) => Err(Error::new_spanned(
            input,
            "union as errors are not supported",
        )),
    }
}

fn struct_error(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
    match &data.fields {
        Fields::Named(fields) => braced_struct_error(input, fields),
        Fields::Unnamed(fields) => tuple_struct_error(input, fields),
        Fields::Unit => unit_struct_error(input),
    }
}

fn braced_struct_error(input: &DeriveInput, fields: &FieldsNamed) -> Result<TokenStream> {
    let _ = input;
    let _ = fields;
    unimplemented!()
}

fn tuple_struct_error(input: &DeriveInput, fields: &FieldsUnnamed) -> Result<TokenStream> {
    let _ = input;
    let _ = fields;
    unimplemented!()
}

fn unit_struct_error(input: &DeriveInput) -> Result<TokenStream> {
    let ident = &input.ident;
    Ok(quote! {
        impl std::error::Error for #ident {}
    })
}

fn enum_error(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
    let _ = input;
    let _ = data;
    unimplemented!()
}
<commit_msg>Add source() method for structs<commit_after>use proc_macro2::TokenStream;
use quote::quote;
use syn::{
    Data, DataEnum, DataStruct, DeriveInput, Error, Fields, FieldsNamed, FieldsUnnamed, Member,
    Result,
};

pub fn derive(input: &DeriveInput) -> Result<TokenStream> {
    match &input.data {
        Data::Struct(data) => struct_error(input, data),
        Data::Enum(data) => enum_error(input, data),
        Data::Union(_) => Err(Error::new_spanned(
            input,
            "union as errors are not supported",
        )),
    }
}

fn struct_error(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
    let ident = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source = match &data.fields {
        Fields::Named(fields) => braced_struct_source(input, fields)?,
        Fields::Unnamed(fields) => tuple_struct_source(input, fields)?,
        Fields::Unit => None,
    };

    let source_method = source.map(|source| {
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                std::option::Option::Some(&self.#source)
            }
        }
    });

    Ok(quote! {
        impl #impl_generics std::error::Error for #ident #ty_generics #where_clause {
            #source_method
        }
    })
}

fn braced_struct_source(input: &DeriveInput, fields: &FieldsNamed) -> Result<Option<Member>> {
    let _ = input;
    let _ = fields;
    unimplemented!()
}

fn tuple_struct_source(input: &DeriveInput, fields: &FieldsUnnamed) -> Result<Option<Member>> {
    let _ = input;
    let _ = fields;
    unimplemented!()
}

fn enum_error(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
    let _ = input;
    let _ = data;
    unimplemented!()
}
<|endoftext|>


<commit_before>#![crate_name = "yaml"]

#![comment = "LibYAML bindings for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]

#![feature(globs)]
#![feature(phase)]

#[cfg(test)]
extern crate debug;

extern crate libc;

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use parser::YamlParser;
use constructor::{YamlStandardData, YamlStandardConstructor, YamlConstructor};
use std::result;

pub mod ffi;
pub mod event;
pub mod parser;
pub mod emitter;
pub mod document;
pub mod codecs;
pub mod constructor;

mod type_size;

pub fn version_string() -> String {
    let c_vsn = unsafe {
        std::c_str::CString::new(ffi::yaml_get_version_string(), false)
    };

    c_vsn.as_str().unwrap().to_string()
}

pub fn version() -> (int, int, int) {
    let mut c_major: libc::c_int = 0;
    let mut c_minor: libc::c_int = 0;
    let mut c_patch: libc::c_int = 0;

    unsafe {
        ffi::yaml_get_version(
            &mut c_major as *mut libc::c_int,
            &mut c_minor as *mut libc::c_int,
            &mut c_patch as *mut libc::c_int
        );
    }

    (c_major as int, c_minor as int, c_patch as int)
}

pub fn parse_bytes_utf8(bytes: &[u8]) -> Result<Vec<YamlStandardData>, String> {
    parse_bytes(bytes, ffi::YamlUtf8Encoding)
}

pub fn parse_bytes(bytes: &[u8], encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlByteParser::init(bytes, encoding);
    let ctor = YamlStandardConstructor::new();

    result::collect(parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_str()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }))
}

pub fn parse_io_utf8(reader: &mut Reader) -> Result<Vec<YamlStandardData>, String> {
    parse_io(reader, ffi::YamlUtf8Encoding)
}

pub fn parse_io(reader: &mut Reader, encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlIoParser::init(reader, encoding);
    let ctor = YamlStandardConstructor::new();

    result::collect(parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_str()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }))
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::io;
    use constructor::*;

    #[test]
    fn test_version_string() {
        let vsn = super::version_string();
        assert!("0.1.4".to_string() <= vsn && vsn < "0.2".to_string())
    }

    #[test]
    fn test_version() {
        let vsn = super::version();
        assert!((0, 1, 4) <= vsn && vsn < (0, 2, 0))
    }

    #[test]
    fn test_event_size() {
        assert_eq!(super::type_size::yaml_event_t_size, mem::size_of::<super::ffi::yaml_event_t>())
    }

    #[test]
    fn test_parser_size() {
        assert_eq!(super::type_size::yaml_parser_t_size, mem::size_of::<super::ffi::yaml_parser_t>())
    }

    #[test]
    fn test_emitter_size() {
        assert_eq!(super::type_size::yaml_emitter_t_size, mem::size_of::<super::ffi::yaml_emitter_t>())
    }

    #[test]
    fn test_document_size() {
        assert_eq!(super::type_size::yaml_document_t_size, mem::size_of::<super::ffi::yaml_document_t>())
    }

    #[test]
    fn test_node_size() {
        assert_eq!(super::type_size::yaml_node_t_size, mem::size_of::<super::ffi::yaml_node_t>())
    }

    #[test]
    fn test_parse_bytes() {
        let data = "[1, 2, 3]";
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_bytes_utf8(data.as_bytes()))
    }

    #[test]
    fn test_parse_io() {
        let data = "[1, 2, 3]";
        let mut reader = io::BufReader::new(data.as_bytes());
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_io_utf8(&mut reader))
    }
}
<commit_msg>Language changes: to_str() is removed from stdlib<commit_after>#![crate_name = "yaml"]

#![comment = "LibYAML bindings for Rust"]
#![license = "MIT"]
#![crate_type = "lib"]

#![feature(globs)]
#![feature(phase)]

#[cfg(test)]
extern crate debug;

extern crate libc;

#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

use parser::YamlParser;
use constructor::{YamlStandardData, YamlStandardConstructor, YamlConstructor};
use std::result;

pub mod ffi;
pub mod event;
pub mod parser;
pub mod emitter;
pub mod document;
pub mod codecs;
pub mod constructor;

mod type_size;

pub fn version_string() -> String {
    let c_vsn = unsafe {
        std::c_str::CString::new(ffi::yaml_get_version_string(), false)
    };

    c_vsn.as_str().unwrap().to_string()
}

pub fn version() -> (int, int, int) {
    let mut c_major: libc::c_int = 0;
    let mut c_minor: libc::c_int = 0;
    let mut c_patch: libc::c_int = 0;

    unsafe {
        ffi::yaml_get_version(
            &mut c_major as *mut libc::c_int,
            &mut c_minor as *mut libc::c_int,
            &mut c_patch as *mut libc::c_int
        );
    }

    (c_major as int, c_minor as int, c_patch as int)
}

pub fn parse_bytes_utf8(bytes: &[u8]) -> Result<Vec<YamlStandardData>, String> {
    parse_bytes(bytes, ffi::YamlUtf8Encoding)
}

pub fn parse_bytes(bytes: &[u8], encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlByteParser::init(bytes, encoding);
    let ctor = YamlStandardConstructor::new();

    result::collect(parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_string()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }))
}

pub fn parse_io_utf8(reader: &mut Reader) -> Result<Vec<YamlStandardData>, String> {
    parse_io(reader, ffi::YamlUtf8Encoding)
}

pub fn parse_io(reader: &mut Reader, encoding: ffi::YamlEncoding) -> Result<Vec<YamlStandardData>, String> {
    let parser = parser::YamlIoParser::init(reader, encoding);
    let ctor = YamlStandardConstructor::new();

    result::collect(parser.load().map(|doc_res| {
        match doc_res {
            Err(e) => Err(e.to_string()),
            Ok(doc) => ctor.construct(doc.root().unwrap())
        }
    }))
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::io;
    use constructor::*;

    #[test]
    fn test_version_string() {
        let vsn = super::version_string();
        assert!("0.1.4".to_string() <= vsn && vsn < "0.2".to_string())
    }

    #[test]
    fn test_version() {
        let vsn = super::version();
        assert!((0, 1, 4) <= vsn && vsn < (0, 2, 0))
    }

    #[test]
    fn test_event_size() {
        assert_eq!(super::type_size::yaml_event_t_size, mem::size_of::<super::ffi::yaml_event_t>())
    }

    #[test]
    fn test_parser_size() {
        assert_eq!(super::type_size::yaml_parser_t_size, mem::size_of::<super::ffi::yaml_parser_t>())
    }

    #[test]
    fn test_emitter_size() {
        assert_eq!(super::type_size::yaml_emitter_t_size, mem::size_of::<super::ffi::yaml_emitter_t>())
    }

    #[test]
    fn test_document_size() {
        assert_eq!(super::type_size::yaml_document_t_size, mem::size_of::<super::ffi::yaml_document_t>())
    }

    #[test]
    fn test_node_size() {
        assert_eq!(super::type_size::yaml_node_t_size, mem::size_of::<super::ffi::yaml_node_t>())
    }

    #[test]
    fn test_parse_bytes() {
        let data = "[1, 2, 3]";
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_bytes_utf8(data.as_bytes()))
    }

    #[test]
    fn test_parse_io() {
        let data = "[1, 2, 3]";
        let mut reader = io::BufReader::new(data.as_bytes());
        assert_eq!(Ok(vec![YamlSequence(vec![YamlInteger(1), YamlInteger(2), YamlInteger(3)])]), super::parse_io_utf8(&mut reader))
    }
}
<|endoftext|>