<commit_before>extern crate time;
extern crate byteorder;
extern crate uuid;

use std::option::Option;
use std::cmp::Ordering;
use std::io::Write;
use std::io::Read;
use std::net::TcpStream;

use byteorder::{BigEndian, WriteBytesExt};
use byteorder::ReadBytesExt;
use uuid::Uuid;

pub mod constants;
use constants::*;

#[test]
fn constructor() {
    let c = Connection::new("localhost", 4730);

    assert!(c.host == "localhost");
    assert!(c.port == 4730);
    assert!(c.state == ConnectionState::INIT);

    let now = time::now_utc();
    match c.state_time {
        Some(c_time) => {
            let result = now.cmp(&c_time);  // Could fail if no nanoseconds
            assert_eq!(Ordering::Greater, result);
        },
        None => assert!(false)
    }
}

#[test]
fn change_state() {
    let mut c = Connection::new("localhost", 4730);

    c.change_state(ConnectionState::INIT);
    assert!(c.state == ConnectionState::INIT);
}

#[test]
fn packet_constructor() {
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    assert!(p.code == PacketCode::REQ);
    assert!(p.ptype == ECHO_REQ);
    assert!(p.data.len() == 1);
}

#[test]
#[should_panic]
fn send_packet() {
    let mut conn = Connection::new("localost", 4730);
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    conn.sendPacket(p)
}

#[test]
fn echo() {
    let mut test: Vec<u8> = Vec::new();
    test.extend("abc123".to_string().bytes());
    let mut conn = Connection::new("localhost", 4730);
    let result = String::from_utf8(conn.echo(test, 0)).unwrap();
    assert_eq!("abc123", result);
    let mut test2: Vec<u8> = Vec::new();
    let mut output = String::from_utf8(conn.echo(test2, 0)).unwrap();
    println!("UUID = {}", output);
}

#[derive(PartialEq)]
enum ConnectionState {
    INIT,
}

struct Connection {
    host: String,
    port: u16,
    conn: Option<TcpStream>,
    connected: bool,
    connect_time: Option<time::Tm>,
    state: ConnectionState,
    state_time: Option<time::Tm>,
}

struct Packet {
    code: PacketCode,
    ptype: u32,
    data: Box<[u8]>,
}

impl Connection {
    fn new(host: &str, port: u16) -> Connection {
        let mut c = Connection {
            host: host.to_string(),
            port: port,
            conn: None,
            connected: false,
            connect_time: None,
            state: ConnectionState::INIT,
            state_time: None,
        };
        c.change_state(ConnectionState::INIT);
        return c
    }

    fn change_state(&mut self, state: ConnectionState) {
        self.state_time = Some(time::now_utc());
        self.state = state;
    }

    fn connect(&mut self) {
        match self.conn {
            None => {
                self.conn = Some(TcpStream::connect((&*self.host, self.port)).unwrap());
self.connected = true;
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
    }

    fn disconnect(&mut self) {
        match self.conn {
            Some(_) => self.conn = None,
            None => { /* log debug "already disconnected" */ },
        }
    }

    fn reconnect(&mut self) {
        self.disconnect();
        self.connect()
    }

    fn sendPacket(&mut self, packet: Packet) {
        match self.conn {
            Some(ref mut c) => {
                match packet.code {
                    PacketCode::REQ => { c.write(&REQ).unwrap(); }
                    PacketCode::RES => { c.write(&RES).unwrap(); }
                }
                c.write_u32::<BigEndian>(packet.ptype);
                c.write_u32::<BigEndian>(packet.data.len() as u32).unwrap();
                c.write_all(&packet.data).unwrap()
            },
            None => panic!("Attempted to send packet on disconnected socket")
        }
    }

    fn _code_from_vec(code: Vec<u8>) -> Result<PacketCode, &'static str> {
        if code[..] == REQ {
            return Ok(PacketCode::REQ);
        } else if code[..] == RES {
            return Ok(PacketCode::RES);
        }
        return Err("Invalid packet code");
    }

    fn readPacket(&mut self) -> Packet {
        match self.conn {
            Some(ref mut c) => {
                let mut code: Vec<u8> = Vec::new();
                {
                    let mut codestream = c.take(4);
                    codestream.read_to_end(&mut code).unwrap();
                }
                let code: PacketCode = Connection::_code_from_vec(code).unwrap();
                let ptype   = c.read_u32::<BigEndian>().unwrap();
                let datalen = c.read_u32::<BigEndian>().unwrap();
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                datastream.read_to_end(&mut buf).unwrap();
                return Packet {
                    code: code,
                    ptype: ptype,
                    data: buf.into_boxed_slice(),
                }
            },
            None => panic!("Attempted to read packet on disconnected socket")
        }
    }

    fn echo(&mut self, mut data: Vec<u8>, timeout: u32) -> Vec<u8> {
        if data.len() == 0 {
            data.extend(Uuid::new_v4().to_simple_string().bytes());
        }

        data
    }

    fn sendEchoReq(&mut self, mut data: Vec<u8>) {
        let p = Packet::new(PacketCode::REQ, ECHO_REQ, data.into_boxed_slice());
        self.sendPacket(p);
    }
}

impl PartialEq for Packet {
    fn eq(&self, other: &Packet) -> bool {
        self.code == other.code &&
        self.ptype == other.ptype &&
        self.data == other.data
    }
}

impl Packet {
    fn new(code: PacketCode, ptype: u32, data: Box<[u8]>) -> Packet {
        Packet {
            code: code,
            ptype: ptype,
            data: data,
        }
    }
}
<commit_msg>Use condition vars for echo blocking<commit_after>extern crate time;
extern crate byteorder;
extern crate uuid;

use std::option::Option;
use std::cmp::Ordering;
use std::io::Write;
use std::io::Read;
use std::net::TcpStream;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::sync::{Mutex, Condvar, Arc};

use byteorder::{BigEndian, WriteBytesExt};
use byteorder::ReadBytesExt;
use uuid::Uuid;

pub mod constants;
use constants::*;

#[test]
fn constructor() {
    let c = Connection::new("localhost", 4730);

    assert!(c.host == "localhost");
    assert!(c.port == 4730);
    assert!(c.state == ConnectionState::INIT);

    let now = time::now_utc();
    match c.state_time {
        Some(c_time) => {
            let result = now.cmp(&c_time);  // Could fail if no nanoseconds
            assert_eq!(Ordering::Greater, result);
        },
        None => assert!(false)
    }
}

#[test]
fn change_state() {
    let mut c = Connection::new("localhost", 4730);

    c.change_state(ConnectionState::INIT);
    assert!(c.state == ConnectionState::INIT);
}

#[test]
fn packet_constructor() {
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    assert!(p.code == PacketCode::REQ);
    assert!(p.ptype == ECHO_REQ);
    assert!(p.data.len() == 1);
}

#[test]
#[should_panic]
fn send_packet() {
    let mut conn = Connection::new("localost", 4730);
    let data: Box<[u8]> = Box::new([0x00u8]);
    let p = Packet::new(PacketCode::REQ, ECHO_REQ, data);
    conn.sendPacket(p)
}

#[test]
#[should_panic]
fn echo() {
    let mut test: Vec<u8> = Vec::new();
    test.extend("abc123".to_string().bytes());
    let mut conn = Connection::new("localhost", 4730);
    let result = String::from_utf8(conn.echo(test, 0)).unwrap();
    assert_eq!("abc123", result);
    let mut test2: Vec<u8> = Vec::new();
    let mut output = String::from_utf8(conn.echo(test2, 0)).unwrap();
    println!("UUID = {}", output);
}

#[derive(PartialEq)]
enum ConnectionState {
    INIT,
}

struct Connection {
    host: String,
    port: u16,
    conn: Option<TcpStream>,
    connect_time: Option<time::Tm>,
    state: ConnectionState,
    state_time: Option<time::Tm>,
    echo_conditions: HashMap<Vec<u8>, Arc<(Mutex<bool>, Condvar)>>,
}

struct Packet {
    code: PacketCode,
    ptype: u32,
    data: Box<[u8]>,
}

impl Connection {
    fn new(host: &str, port: u16) -> Connection {
        let mut c = Connection {
            host: host.to_string(),
            port: port,
            conn: None,
            connect_time: None,
            state: ConnectionState::INIT,
            state_time: None,
            echo_conditions: HashMap::new(),
        };
        c.change_state(ConnectionState::INIT);
        return c
    }

    fn change_state(&mut self, state: ConnectionState) {
        self.state_time = Some(time::now_utc());
        self.state = state;
    }

    fn connect(&mut self) {
        match self.conn {
            None => {
                self.conn = Some(TcpStream::connect((&*self.host, self.port)).unwrap());
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
    }

    fn disconnect(&mut self) {
        match self.conn {
            Some(_) => self.conn = None,
            None => { /* log debug "already disconnected" */ },
        }
    }

    fn reconnect(&mut self) {
        self.disconnect();
        self.connect()
    }

    fn sendPacket(&mut self, packet: Packet) {
        match self.conn {
            Some(ref mut c) => {
                match packet.code {
                    PacketCode::REQ => { c.write(&REQ).unwrap(); }
                    PacketCode::RES => { c.write(&RES).unwrap(); }
                }
                c.write_u32::<BigEndian>(packet.ptype);
                c.write_u32::<BigEndian>(packet.data.len() as u32).unwrap();
                c.write_all(&packet.data).unwrap();
            },
            None => panic!("Attempted to send packet on disconnected socket")
        }
    }

    fn _code_from_vec(code: Vec<u8>) -> Result<PacketCode, &'static str> {
        if code[..] == REQ {
            return Ok(PacketCode::REQ);
        } else if code[..] == RES {
            return Ok(PacketCode::RES);
        }
        return Err("Invalid packet code");
    }

    fn readPacket(&mut self) -> Packet {
        match self.conn {
            Some(ref mut c) => {
                let mut code: Vec<u8> = Vec::new();
                {
                    let mut codestream = c.take(4);
                    codestream.read_to_end(&mut code).unwrap();
                }
                let code: PacketCode = Connection::_code_from_vec(code).unwrap();
                let ptype   = c.read_u32::<BigEndian>().unwrap();
                let datalen = c.read_u32::<BigEndian>().unwrap();
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                datastream.read_to_end(&mut buf).unwrap();
                return Packet {
                    code: code,
                    ptype: ptype,
                    data: buf.into_boxed_slice(),
                }
            },
            None => panic!("Attempted to read packet on disconnected socket")
        }
    }

    fn echo(&mut self, mut data: Vec<u8>, timeout: u32) -> Vec<u8> {
        if data.len() == 0 {
            data.extend(Uuid::new_v4().to_simple_string().bytes());
        }
        let lock_cond = Arc::new((Mutex::new(false), Condvar::new()));
        let &(ref lock, ref cond) = &*lock_cond;
        let mut handled_echo = lock.lock().unwrap();
        self.sendEchoReq(data.clone());
        self.echo_conditions.insert(data.clone(), lock_cond.clone());
        if !*cond.wait_timeout_ms(handled_echo, timeout * 1000).unwrap().0 {
            panic!("Timed out waiting for response from echo.");
        };
        data
    }

    fn sendEchoReq(&mut self, mut data: Vec<u8>) {
        let p = Packet::new(PacketCode::REQ, ECHO_REQ, data.into_boxed_slice());
        self.sendPacket(p)
    }

    fn handleEchoRes(&mut self, mut data: Vec<u8>) {
        if let Some(mutexlock) = self.echo_conditions.get_mut(&data) {
            let lock = &mutexlock.0;
            let cond = &mutexlock.1;
            let mut handled_echo = lock.lock().unwrap();
            *handled_echo = true;

            //self.echo_conditions.remove(&data);
            cond.notify_one();
        }
    }
}

impl PartialEq for Packet {
    fn eq(&self, other: &Packet) -> bool {
        self.code == other.code &&
        self.ptype == other.ptype &&
        self.data == other.data
    }
}

impl Packet {
    fn new(code: PacketCode, ptype: u32, data: Box<[u8]>) -> Packet {
        Packet {
            code: code,
            ptype: ptype,
            data: data,
        }
    }
}
<|endoftext|>


<commit_before>//! # Example
//!
//! ```rust
//! # extern crate env_logger;
//! # extern crate embed_lang;
//!
//! use embed_lang::{new_vm, run_expr};
//!
//! # fn main() {
//! # let _ = ::env_logger::init();
//!
//! let text = r#"
//! // `type` is used to declare a new type.
//! // In this case we declare `Eq` to be a record with a single field (`==`) which is a function
//! // which takes two arguments of the same type and returns a boolean
//! type Eq a = { (==) : a -> a -> Bool }
//! // `let` declares new variables.
//! let id x = x
//!
//! let factorial n =
//!         if n < 2
//!         then 1
//!         else n * factorial (n - 1)
//!
//! let list_module =
//!         // Declare a new type which only exists in the current scope
//!         type List a = | Cons a (List a) | Nil
//!         let map f xs =
//!                 case xs of
//!                     | Cons y ys -> Cons (f y) (map f ys)
//!                     | Nil -> Nil
//!         let eq eq_a: Eq a -> Eq (List a) =
//!                 let (==) l r =
//!                     case l of
//!                         | Cons la lxs ->
//!                             (case r of
//!                                 | Cons ra rxs -> eq_a.(==) la ra && lxs == rxs
//!                                 | Nil -> False)
//!                         | Nil ->
//!                             (case r of
//!                                 | Cons _ _ -> False
//!                                 | Nil -> True)
//!                 { (==) }
//!         {
//!             // Since `List` is local we export it so its constructors can be used
//!             // outside the current scope
//!             List,
//!             eq,
//!             map
//!         }
//!
//! // Bring the `List` type and its constructors into scope
//! let { List, eq = list_Eq } = list_module
//! // Create `==` for `List Int`
//! let { (==) }: Eq (List Int) = list_Eq { (==) }
//! if Cons 1 Nil == Nil then
//!     error "This branch is not executed"
//! else
//!     io.print "Hello world!"
//! "#;
//!
//! let vm = new_vm();
//! match run_expr(&vm, "example", text) {
//!     Ok(value) => {
//!         println!("{:?}", value);
//!     }
//!     Err(err) => {
//!         panic!("{}", err);
//!     }
//! }
//! return;
//!
//! # }
//! ```

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate vm as vm_mod;

mod io;
mod crates {
    extern crate base;
    extern crate parser;
    extern crate check;
}

pub use crates::base;
pub use crates::parser;
pub use crates::check;
pub use vm_mod as vm;

pub mod import;

pub use vm::vm::VM;

use base::ast;
use base::types::TcType;
use base::symbol::{Name, NameBuf, Symbol, Symbols, SymbolModule};
use std::result::Result as StdResult;
use std::string::String as StdString;
use std::error::Error as StdError;
use vm::vm::{ClosureDataDef, RootedValue};
use vm::compiler::CompiledFunction;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Parse(err: ::parser::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Typecheck(err: ::base::error::InFile<::check::typecheck::TypeError<Symbol>>) {
            description(err.description())
            display("{}", err)
            from()
        }
        IO(err: ::std::io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        VM(err: ::vm::vm::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Macro(err: ::base::error::Errors<::base::macros::Error>) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn include_implicit_prelude(symbols: &mut Symbols,
                            name: &str,
                            expr: &mut ast::LExpr<ast::TcIdent<Symbol>>) {
    use std::mem;
    if name == "std.prelude" {
        return;
    }

    let prelude_import = r#"
let __implicit_prelude = import "std/prelude.hs"
and { Num, Eq, Ord, Show, Functor, Monad, Option, Result, not } = __implicit_prelude
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Int
and { (==) } = __implicit_prelude.eq_Int
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Int
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Float
and { (==) } = __implicit_prelude.eq_Float
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Float
in 0
"#;
    let prelude_expr = parse_expr_(symbols, "", prelude_import).unwrap();
    let original_expr = mem::replace(expr, prelude_expr);
    fn assign_last_body(l: &mut ast::LExpr<ast::TcIdent<Symbol>>,
                        original_expr: ast::LExpr<ast::TcIdent<Symbol>>) {
        match l.value {
            ast::Expr::Let(_, ref mut e) => {
                assign_last_body(e, original_expr);
            }
            _ => *l = original_expr,
        }
    }
    assign_last_body(expr, original_expr);
}

fn compile_script(symbols: &mut Symbols,
                  vm: &VM,
                  filename: &str,
                  expr: &ast::LExpr<ast::TcIdent<Symbol>>)
                  -> CompiledFunction {
    use vm::compiler::Compiler;
    debug!("Compile `{}`", filename);
    let mut function = {
        let env = vm.get_env();
        let name = Name::new(filename);
        let name = NameBuf::from(name.module());
        let symbols = SymbolModule::new(StdString::from(name.as_ref()), symbols);
        let mut compiler = Compiler::new(&*env, vm, symbols);
        compiler.compile_expr(&expr)
    };
    function.id = Symbol::new(filename);
    function
}

/// Compiles `input` and if it is successful runs the resulting code and stores the resulting value
/// in the global variable named by running `filename_to_module` on `filename`.
///
/// If at any point the function fails the resulting error is returned and nothing is added to the
/// VM.
pub fn load_script(vm: &VM, filename: &str, input: &str) -> Result<()> {
    load_script2(vm, filename, input, true)
}

pub fn load_script2(vm: &VM, filename: &str, input: &str, implicit_prelude: bool) -> Result<()> {
    use check::metadata;
    let mut symbols = Symbols::new();
    let (mut expr, typ) = try!(typecheck_expr_(&mut symbols,
                                               vm,
                                               filename,
                                               input,
                                               implicit_prelude));
    let metadata = metadata::metadata(&*vm.get_env(), &mut expr);
    let function = compile_script(&mut symbols, vm, filename, &expr);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    try!(vm.set_global(function.name.clone(), typ, metadata, value));
    Ok(())
}

pub fn filename_to_module(filename: &str) -> StdString {
    use std::path::Path;
    let path = Path::new(filename);
    let name = path.extension()
                   .map(|ext| {
                       ext.to_str()
                          .map(|ext| &filename[..filename.len() - ext.len() - 1])
                          .unwrap_or(filename)
                   })
                   .expect("filename");

    name.replace("/", ".")
}

/// Loads `filename` and compiles and runs its input by calling `load_script`
pub fn load_file(vm: &VM, filename: &str) -> Result<()> {
    use std::fs::File;
    use std::io::Read;
    let mut file = try!(File::open(filename));
    let mut buffer = ::std::string::String::new();
    try!(file.read_to_string(&mut buffer));
    drop(file);
    let name = filename_to_module(filename);
    load_script(vm, &name, &buffer)
}

fn parse_expr_(symbols: &mut Symbols,
               file: &str,
               input: &str)
               -> StdResult<ast::LExpr<ast::TcIdent<Symbol>>, ::parser::Error> {
    Ok(try!(::parser::parse_tc(&mut SymbolModule::new(file.into(), symbols), input)))
}

pub fn parse_expr(file: &str,
                  input: &str)
                  -> StdResult<ast::LExpr<ast::TcIdent<Symbol>>, ::parser::Error> {
    let mut symbols = Symbols::new();
    parse_expr_(&mut symbols, file, input)
}

fn typecheck_expr_(symbols: &mut Symbols,
                   vm: &VM,
                   file: &str,
                   expr_str: &str,
                   implicit_prelude: bool)
                   -> Result<(ast::LExpr<ast::TcIdent<Symbol>>, TcType)> {
    use check::typecheck::Typecheck;
    use base::error;
    let mut expr = try!(parse_expr_(symbols, file, expr_str));
    if implicit_prelude {
        include_implicit_prelude(symbols, file, &mut expr);
    }
    try!(vm.get_macros().run(vm, &mut expr));
    let env = vm.get_env();
    let mut tc = Typecheck::new(file.into(), symbols, &*env);
    let typ = try!(tc.typecheck_expr(&mut expr)
                     .map_err(|err| error::InFile::new(StdString::from(file), expr_str, err)));
    Ok((expr, typ))
}

pub fn typecheck_expr(vm: &VM,
                      file: &str,
                      expr_str: &str,
                      implicit_prelude: bool)
                      -> Result<(ast::LExpr<ast::TcIdent<Symbol>>, TcType)> {
    let mut symbols = Symbols::new();
    typecheck_expr_(&mut symbols, vm, file, expr_str, implicit_prelude)
}

/// Compiles and runs the expression in `expr_str`. If successful the value from running the
/// expression is returned
pub fn run_expr<'vm>(vm: &'vm VM, name: &str, expr_str: &str) -> Result<RootedValue<'vm>> {
    run_expr2(vm, name, expr_str, true)
}

pub fn run_expr2<'vm>(vm: &'vm VM,
                      name: &str,
                      expr_str: &str,
                      implicit_prelude: bool)
                      -> Result<RootedValue<'vm>> {
    let mut symbols = Symbols::new();
    let (expr, typ) = try!(typecheck_expr_(&mut symbols, vm, name, expr_str, implicit_prelude));
    let mut function = compile_script(&mut symbols, vm, name, &expr);
    function.id = Symbol::new(name);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    Ok(vm.root_value(value))
}

/// Creates a new virtual machine with support for importing other modules and with all primitives
/// loaded.
pub fn new_vm() -> VM {
    let vm = VM::new();
    vm.get_macros().insert(String::from("import"), ::import::Import::new());
    run_expr2(&vm, "", r#" import "std/types.hs" "#, false).unwrap();
    ::vm::primitives::load(&vm).expect("Loaded primitives library");
    ::vm::channel::load(&vm).expect("Loaded channel library");
    ::io::load(&vm).expect("Loaded IO library");
    vm
}
<commit_msg>fix: Reexport the sub-crates using pub instead of pub mod<commit_after>//! # Example
//!
//! ```rust
//! # extern crate env_logger;
//! # extern crate embed_lang;
//!
//! use embed_lang::{new_vm, run_expr};
//!
//! # fn main() {
//! # let _ = ::env_logger::init();
//!
//! let text = r#"
//! // `type` is used to declare a new type.
//! // In this case we declare `Eq` to be a record with a single field (`==`) which is a function
//! // which takes two arguments of the same type and returns a boolean
//! type Eq a = { (==) : a -> a -> Bool }
//! // `let` declares new variables.
//! let id x = x
//!
//! let factorial n =
//!         if n < 2
//!         then 1
//!         else n * factorial (n - 1)
//!
//! let list_module =
//!         // Declare a new type which only exists in the current scope
//!         type List a = | Cons a (List a) | Nil
//!         let map f xs =
//!                 case xs of
//!                     | Cons y ys -> Cons (f y) (map f ys)
//!                     | Nil -> Nil
//!         let eq eq_a: Eq a -> Eq (List a) =
//!                 let (==) l r =
//!                     case l of
//!                         | Cons la lxs ->
//!                             (case r of
//!                                 | Cons ra rxs -> eq_a.(==) la ra && lxs == rxs
//!                                 | Nil -> False)
//!                         | Nil ->
//!                             (case r of
//!                                 | Cons _ _ -> False
//!                                 | Nil -> True)
//!                 { (==) }
//!         {
//!             // Since `List` is local we export it so its constructors can be used
//!             // outside the current scope
//!             List,
//!             eq,
//!             map
//!         }
//!
//! // Bring the `List` type and its constructors into scope
//! let { List, eq = list_Eq } = list_module
//! // Create `==` for `List Int`
//! let { (==) }: Eq (List Int) = list_Eq { (==) }
//! if Cons 1 Nil == Nil then
//!     error "This branch is not executed"
//! else
//!     io.print "Hello world!"
//! "#;
//!
//! let vm = new_vm();
//! match run_expr(&vm, "example", text) {
//!     Ok(value) => {
//!         println!("{:?}", value);
//!     }
//!     Err(err) => {
//!         panic!("{}", err);
//!     }
//! }
//! return;
//!
//! # }
//! ```

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate quick_error;

#[macro_use]
pub extern crate vm;
pub extern crate base;
pub extern crate parser;
pub extern crate check;

mod io;
pub mod import;

pub use vm::vm::VM;

use base::ast;
use base::types::TcType;
use base::symbol::{Name, NameBuf, Symbol, Symbols, SymbolModule};
use std::result::Result as StdResult;
use std::string::String as StdString;
use std::error::Error as StdError;
use vm::vm::{ClosureDataDef, RootedValue};
use vm::compiler::CompiledFunction;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Parse(err: ::parser::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Typecheck(err: ::base::error::InFile<::check::typecheck::TypeError<Symbol>>) {
            description(err.description())
            display("{}", err)
            from()
        }
        IO(err: ::std::io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        VM(err: ::vm::vm::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
        Macro(err: ::base::error::Errors<::base::macros::Error>) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

pub type Result<T> = StdResult<T, Error>;

fn include_implicit_prelude(symbols: &mut Symbols,
                            name: &str,
                            expr: &mut ast::LExpr<ast::TcIdent<Symbol>>) {
    use std::mem;
    if name == "std.prelude" {
        return;
    }

    let prelude_import = r#"
let __implicit_prelude = import "std/prelude.hs"
and { Num, Eq, Ord, Show, Functor, Monad, Option, Result, not } = __implicit_prelude
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Int
and { (==) } = __implicit_prelude.eq_Int
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Int
in
let { (+), (-), (*), (/) } = __implicit_prelude.num_Float
and { (==) } = __implicit_prelude.eq_Float
and { (<), (<=), (=>), (>) } = __implicit_prelude.make_Ord __implicit_prelude.ord_Float
in 0
"#;
    let prelude_expr = parse_expr_(symbols, "", prelude_import).unwrap();
    let original_expr = mem::replace(expr, prelude_expr);
    fn assign_last_body(l: &mut ast::LExpr<ast::TcIdent<Symbol>>,
                        original_expr: ast::LExpr<ast::TcIdent<Symbol>>) {
        match l.value {
            ast::Expr::Let(_, ref mut e) => {
                assign_last_body(e, original_expr);
            }
            _ => *l = original_expr,
        }
    }
    assign_last_body(expr, original_expr);
}

fn compile_script(symbols: &mut Symbols,
                  vm: &VM,
                  filename: &str,
                  expr: &ast::LExpr<ast::TcIdent<Symbol>>)
                  -> CompiledFunction {
    use vm::compiler::Compiler;
    debug!("Compile `{}`", filename);
    let mut function = {
        let env = vm.get_env();
        let name = Name::new(filename);
        let name = NameBuf::from(name.module());
        let symbols = SymbolModule::new(StdString::from(name.as_ref()), symbols);
        let mut compiler = Compiler::new(&*env, vm, symbols);
        compiler.compile_expr(&expr)
    };
    function.id = Symbol::new(filename);
    function
}

/// Compiles `input` and if it is successful runs the resulting code and stores the resulting value
/// in the global variable named by running `filename_to_module` on `filename`.
///
/// If at any point the function fails the resulting error is returned and nothing is added to the
/// VM.
pub fn load_script(vm: &VM, filename: &str, input: &str) -> Result<()> {
    load_script2(vm, filename, input, true)
}

pub fn load_script2(vm: &VM, filename: &str, input: &str, implicit_prelude: bool) -> Result<()> {
    use check::metadata;
    let mut symbols = Symbols::new();
    let (mut expr, typ) = try!(typecheck_expr_(&mut symbols,
                                               vm,
                                               filename,
                                               input,
                                               implicit_prelude));
    let metadata = metadata::metadata(&*vm.get_env(), &mut expr);
    let function = compile_script(&mut symbols, vm, filename, &expr);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    try!(vm.set_global(function.name.clone(), typ, metadata, value));
    Ok(())
}

pub fn filename_to_module(filename: &str) -> StdString {
    use std::path::Path;
    let path = Path::new(filename);
    let name = path.extension()
                   .map(|ext| {
                       ext.to_str()
                          .map(|ext| &filename[..filename.len() - ext.len() - 1])
                          .unwrap_or(filename)
                   })
                   .expect("filename");

    name.replace("/", ".")
}

/// Loads `filename` and compiles and runs its input by calling `load_script`
pub fn load_file(vm: &VM, filename: &str) -> Result<()> {
    use std::fs::File;
    use std::io::Read;
    let mut file = try!(File::open(filename));
    let mut buffer = ::std::string::String::new();
    try!(file.read_to_string(&mut buffer));
    drop(file);
    let name = filename_to_module(filename);
    load_script(vm, &name, &buffer)
}

fn parse_expr_(symbols: &mut Symbols,
               file: &str,
               input: &str)
               -> StdResult<ast::LExpr<ast::TcIdent<Symbol>>, ::parser::Error> {
    Ok(try!(::parser::parse_tc(&mut SymbolModule::new(file.into(), symbols), input)))
}

pub fn parse_expr(file: &str,
                  input: &str)
                  -> StdResult<ast::LExpr<ast::TcIdent<Symbol>>, ::parser::Error> {
    let mut symbols = Symbols::new();
    parse_expr_(&mut symbols, file, input)
}

fn typecheck_expr_(symbols: &mut Symbols,
                   vm: &VM,
                   file: &str,
                   expr_str: &str,
                   implicit_prelude: bool)
                   -> Result<(ast::LExpr<ast::TcIdent<Symbol>>, TcType)> {
    use check::typecheck::Typecheck;
    use base::error;
    let mut expr = try!(parse_expr_(symbols, file, expr_str));
    if implicit_prelude {
        include_implicit_prelude(symbols, file, &mut expr);
    }
    try!(vm.get_macros().run(vm, &mut expr));
    let env = vm.get_env();
    let mut tc = Typecheck::new(file.into(), symbols, &*env);
    let typ = try!(tc.typecheck_expr(&mut expr)
                     .map_err(|err| error::InFile::new(StdString::from(file), expr_str, err)));
    Ok((expr, typ))
}

pub fn typecheck_expr(vm: &VM,
                      file: &str,
                      expr_str: &str,
                      implicit_prelude: bool)
                      -> Result<(ast::LExpr<ast::TcIdent<Symbol>>, TcType)> {
    let mut symbols = Symbols::new();
    typecheck_expr_(&mut symbols, vm, file, expr_str, implicit_prelude)
}

/// Compiles and runs the expression in `expr_str`. If successful the value from running the
/// expression is returned
pub fn run_expr<'vm>(vm: &'vm VM, name: &str, expr_str: &str) -> Result<RootedValue<'vm>> {
    run_expr2(vm, name, expr_str, true)
}

pub fn run_expr2<'vm>(vm: &'vm VM,
                      name: &str,
                      expr_str: &str,
                      implicit_prelude: bool)
                      -> Result<RootedValue<'vm>> {
    let mut symbols = Symbols::new();
    let (expr, typ) = try!(typecheck_expr_(&mut symbols, vm, name, expr_str, implicit_prelude));
    let mut function = compile_script(&mut symbols, vm, name, &expr);
    function.id = Symbol::new(name);
    let function = vm.new_function(function);
    let closure = {
        let stack = vm.current_frame();
        vm.alloc(&stack.stack, ClosureDataDef(function, &[]))
    };
    let value = try!(vm.call_module(&typ, closure));
    Ok(vm.root_value(value))
}

/// Creates a new virtual machine with support for importing other modules and with all primitives
/// loaded.
pub fn new_vm() -> VM {
    let vm = VM::new();
    vm.get_macros().insert(String::from("import"), ::import::Import::new());
    run_expr2(&vm, "", r#" import "std/types.hs" "#, false).unwrap();
    ::vm::primitives::load(&vm).expect("Loaded primitives library");
    ::vm::channel::load(&vm).expect("Loaded channel library");
    ::io::load(&vm).expect("Loaded IO library");
    vm
}
<|endoftext|>


<commit_before>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;
extern crate byteorder;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write, Error, ErrorKind};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll, Async};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

use byteorder::*;

#[derive(Copy,Clone)]
pub enum PacketType {
    ComSleep = 0x00,
    ComQuit = 0x01,
    ComInitDb = 0x02,
    ComQuery = 0x03,
    ComFieldList = 0x04,
    ComCreateDb = 0x05,
    ComDropDb = 0x06,
    ComRefresh = 0x07,
    ComShutdown = 0x08,
    ComStatistics = 0x09,
    ComProcessInfo = 0x0a,
    ComConnect = 0x0b,
    ComProcessKill= 0x0c,
    ComDebug = 0x0d,
    ComPing = 0x0e,
    ComTime = 0x0f,
    ComDelayedInsert = 0x10,
    ComChangeUser = 0x11,
    ComBinlogDump = 0x12,
    ComTableDump = 0x13,
    ComConnectOut = 0x14,
    ComRegisterSlave = 0x15,
    ComStmtPrepare = 0x16,
    ComStmtExecute = 0x17,
    ComStmtSendLongData = 0x18,
    ComStmtClose = 0x19,
    ComStmtReset = 0x1a,
    ComDaemon= 0x1d,
    ComBinlogDumpGtid = 0x1e,
    ComResetConnection = 0x1f,
}

pub struct Packet {
    pub bytes: Vec<u8>
}

impl Packet {

    pub fn error_packet(code: u16, state: [u8; 5], msg: String) -> Self {
        let mut err_header: Vec<u8> = vec![];
        let mut err_wtr: Vec<u8> = vec![];

        // start building payload
        err_wtr.push(0xff);  // packet type
        err_wtr.write_u16::<LittleEndian>(code).unwrap(); // error code
        err_wtr.extend_from_slice("#".as_bytes()); // sql_state_marker
        err_wtr.extend_from_slice(&state); // SQL STATE
        err_wtr.extend_from_slice(msg.as_bytes());

        // create header with length and sequence id
        err_header.write_u32::<LittleEndian>(err_wtr.len() as u32).unwrap();
        err_header.pop(); // we need 3 byte length, so discard last byte
        err_header.push(1); // sequence_id

        let mut write_buf: Vec<u8> = Vec::new();
        write_buf.extend_from_slice(&err_header);
        write_buf.extend_from_slice(&err_wtr);

        Packet { bytes: write_buf }
    }

    pub fn sequence_id(&self) -> u8 {
        self.bytes[3]
    }

    //TODO: should return Result<PacketType, ?>
    pub fn packet_type(&self) -> PacketType {
        match self.bytes[4] {
            0x00 => PacketType::ComSleep,
            0x01 => PacketType::ComQuit,
            0x02 => PacketType::ComInitDb,
            0x03 => PacketType::ComQuery,
            0x04 => PacketType::ComFieldList,
            0x05 => PacketType::ComCreateDb,
            0x06 => PacketType::ComDropDb,
            0x07 => PacketType::ComRefresh,
            0x08 => PacketType::ComShutdown,
            0x09 => PacketType::ComStatistics,
            0x0a => PacketType::ComProcessInfo,
            0x0b => PacketType::ComConnect,
            0x0c => PacketType::ComProcessKill,
            0x0d => PacketType::ComDebug,
            0x0e => PacketType::ComPing,
            0x0f => PacketType::ComTime,
            0x10 => PacketType::ComDelayedInsert,
            0x11 => PacketType::ComChangeUser,
            0x12 => PacketType::ComBinlogDump,
            0x13 => PacketType::ComTableDump,
            0x14 => PacketType::ComConnectOut,
            0x15 => PacketType::ComRegisterSlave,
            0x16 => PacketType::ComStmtPrepare,
            0x17 => PacketType::ComStmtExecute,
            0x18 => PacketType::ComStmtSendLongData,
            0x19 => PacketType::ComStmtClose,
            0x1a => PacketType::ComStmtReset,
            0x1d => PacketType::ComDaemon,
            0x1e => PacketType::ComBinlogDumpGtid,
            0x1f => PacketType::ComResetConnection,
            _ => panic!("Unsupported packet type")
        }
    }

}

pub enum Action {
    Forward,                // forward the packet unmodified
    Mutate(Packet),         // mutate the packet
    Respond(Vec<Packet>)    // handle directly and optionally return some packets
}

pub trait PacketHandler {
    fn handle_request(&self, p: &Packet) -> Action;
    fn handle_response(&self, p: &Packet) -> Action;
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve<H: PacketHandler + 'static>(self, conn: TcpStream,
                                             handler: H,
                                        ) -> Box<Future<Item = (u64, u64), Error = Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        let pair = connected.and_then(move |server| Ok((conn,server)));

        Box::new(pair.and_then(move |(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);
            Pipe::new(c1, c2, handler)
        }))
    }
}

#[derive(Debug)]
enum Direction {
    Client,
    Server
}

struct ConnReader {
    direction: Direction,
    stream: Rc<TcpStream>,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_amt: u64,
}

struct ConnWriter {
    direction: Direction,
    stream: Rc<TcpStream>,
    write_buf: Vec<u8>,
    write_pos: usize,
    write_amt: u64,
}

impl ConnReader {

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnReader {
            stream: stream,
            direction: direction,
            read_buf: vec![0u8; 4096],
            read_pos: 0,
            read_amt: 0,
        }
    }

    /// Read from the socket until the status is NotReady
    fn read(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} read()", self.direction);
        loop {
//            println!("{:?} before poll_read()", self.direction);
            try_ready!(self.stream.poll_read());
//            println!("{:?} before try_nb()", self.direction);
            //TODO: ensure capacity first
            let n = try_nb!((&*self.stream).read(&mut self.read_buf[self.read_pos..]));
            if n == 0 {
//                println!("{:?} Detected connection closed", self.direction);
                return Err(Error::new(ErrorKind::Other, "connection closed"));
            }
//            println!("{:?} read() read {} bytes", self.direction, n);
            self.read_amt += n as u64;
            self.read_pos += n;
        }
    }

    fn next(&mut self) -> Option<Packet> {
        // do we have a header
        if self.read_pos > 3 {
            let l = parse_packet_length(&self.read_buf);
            // do we have the whole packet?
            let s = 4 + l;
            if self.read_pos >= s {

                //TODO: clean up this hack
                let mut temp : Vec<u8> = vec![];
                temp.extend_from_slice( &self.read_buf[0..s]);
                let p = Packet { bytes: temp };

                // shift data down
                let mut j = 0;
                for i in s .. self.read_buf.len() {
                    self.read_buf[j] = self.read_buf[i];
                    j += 1;
                }
                self.read_pos -= s;

//                println!("{:?} parse_packet(): read_pos={}, returning packet:", self.direction, self.read_pos);
//                print_packet_bytes(&p.bytes);
//                print_packet_chars(&p.bytes);

                Some(p)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl ConnWriter{

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnWriter{
            stream: stream,
            direction: direction,
            write_buf: vec![0u8; 4096],
            write_pos: 0,
            write_amt: 0
        }
    }

    /// Write a packet to the write buffer
    fn push(&mut self, p: &Packet) {
        for i in 0 .. p.bytes.len() {
            self.write_buf[self.write_pos + i] = p.bytes[i];
        }
        self.write_pos += p.bytes.len();

//        self.write_buf.truncate(self.write_pos);
//        self.write_buf.extend_from_slice(&p.bytes);
//        self.write_pos += p.bytes.len();
//        println!("{:?} extended write buffer by {} bytes", self.direction, p.bytes.len());
    }

    /// Writes the contents of the write buffer to the socket
    fn write(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} write()", self.direction);
        while self.write_pos > 0 {
            try_ready!(self.stream.poll_write());
            let s = try!((&*self.stream).write(&self.write_buf[0..self.write_pos]));
//            println!("{:?} Wrote {} bytes", self.direction, s);

            let mut j = 0;
            for i in s .. self.write_buf.len() {
                self.write_buf[j] = self.write_buf[i];
                j += 1;
            }
            self.write_pos -= s;

        }
        return Ok(Async::Ready(()));
    }
}

struct Pipe<H: PacketHandler + 'static> {
    client_reader: ConnReader,
    client_writer: ConnWriter,
    server_reader: ConnReader,
    server_writer: ConnWriter,
    handler: H,
}

impl<H> Pipe<H> where H: PacketHandler + 'static {
    fn new(client: Rc<TcpStream>,
           server: Rc<TcpStream>,
           handler: H
           ) -> Pipe<H> {

        Pipe {
            client_reader: ConnReader::new(client.clone(), Direction::Client),
            client_writer: ConnWriter::new(client, Direction::Client),
            server_reader: ConnReader::new(server.clone(), Direction::Server),
            server_writer: ConnWriter::new(server, Direction::Server),
            handler: handler,
        }
    }
}

impl<H> Future for Pipe<H> where H: PacketHandler + 'static {
    type Item = (u64, u64);
    type Error = Error;

    fn poll(&mut self) -> Poll<(u64, u64), io::Error> {
        //println!("poll()");

        loop {
            // try reading from client
//            println!("CLIENT READ");
            let client_read = self.client_reader.read();

            // if the client connection has closed, close the server connection too
            match &client_read {
                &Err(ref e) => { self.server_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered requests
            while let Some(request) = self.client_reader.next() {
                match self.handler.handle_request(&request) {
                    Action::Forward => self.server_writer.push(&request),
                    Action::Mutate(ref p2) => self.server_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.client_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to server
//            println!("SERVER WRITE");
            let server_write = self.server_writer.write();

            // try reading from server
//            println!("SERVER READ");
            let server_read = self.server_reader.read();

            // if the server connection has closed, close the client connection too
            match &server_read {
                &Err(ref e) => { self.client_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered responses
            while let Some(response) = self.server_reader.next() {
                match self.handler.handle_response(&response) {
                    Action::Forward => self.client_writer.push(&response),
                    Action::Mutate(ref p2) => self.client_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.server_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to client
//            println!("CLIENT WRITE");
            let client_write = self.client_writer.write();

//            println!("client_read = {:?}", client_read);
//            println!("client_write = {:?}", client_write);
//            println!("server_read = {:?}", server_read);
//            println!("server_write = {:?}", server_write);

            try_ready!(client_read);
            try_ready!(client_write);
            try_ready!(server_read);
            try_ready!(server_write);
        }

    }

}

#[allow(dead_code)]
pub fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
pub fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<commit_msg>optimize error packet construction<commit_after>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;
extern crate byteorder;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write, Error, ErrorKind};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll, Async};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

use byteorder::*;

#[derive(Copy,Clone)]
pub enum PacketType {
    ComSleep = 0x00,
    ComQuit = 0x01,
    ComInitDb = 0x02,
    ComQuery = 0x03,
    ComFieldList = 0x04,
    ComCreateDb = 0x05,
    ComDropDb = 0x06,
    ComRefresh = 0x07,
    ComShutdown = 0x08,
    ComStatistics = 0x09,
    ComProcessInfo = 0x0a,
    ComConnect = 0x0b,
    ComProcessKill= 0x0c,
    ComDebug = 0x0d,
    ComPing = 0x0e,
    ComTime = 0x0f,
    ComDelayedInsert = 0x10,
    ComChangeUser = 0x11,
    ComBinlogDump = 0x12,
    ComTableDump = 0x13,
    ComConnectOut = 0x14,
    ComRegisterSlave = 0x15,
    ComStmtPrepare = 0x16,
    ComStmtExecute = 0x17,
    ComStmtSendLongData = 0x18,
    ComStmtClose = 0x19,
    ComStmtReset = 0x1a,
    ComDaemon= 0x1d,
    ComBinlogDumpGtid = 0x1e,
    ComResetConnection = 0x1f,
}

pub struct Packet {
    pub bytes: Vec<u8>
}

impl Packet {

    pub fn error_packet(code: u16, state: [u8; 5], msg: String) -> Self {

        // start building payload
        let mut payload: Vec<u8> = Vec::with_capacity(9 + msg.len());
        payload.push(0xff);  // packet type
        payload.write_u16::<LittleEndian>(code).unwrap(); // error code
        payload.extend_from_slice("#".as_bytes()); // sql_state_marker
        payload.extend_from_slice(&state); // SQL STATE
        payload.extend_from_slice(msg.as_bytes());

        // create header with length and sequence id
        let mut header: Vec<u8> = vec![0_u8; 4];
        header.write_u32::<LittleEndian>(payload.len() as u32).unwrap();
        header.pop(); // we need 3 byte length, so discard last byte
        header.push(1); // sequence_id

        // combine the vectors
        header.extend_from_slice(&payload);

        // now move the vector into the packet
        Packet { bytes: header }
    }

    pub fn sequence_id(&self) -> u8 {
        self.bytes[3]
    }

    //TODO: should return Result<PacketType, ?>
    pub fn packet_type(&self) -> PacketType {
        match self.bytes[4] {
            0x00 => PacketType::ComSleep,
            0x01 => PacketType::ComQuit,
            0x02 => PacketType::ComInitDb,
            0x03 => PacketType::ComQuery,
            0x04 => PacketType::ComFieldList,
            0x05 => PacketType::ComCreateDb,
            0x06 => PacketType::ComDropDb,
            0x07 => PacketType::ComRefresh,
            0x08 => PacketType::ComShutdown,
            0x09 => PacketType::ComStatistics,
            0x0a => PacketType::ComProcessInfo,
            0x0b => PacketType::ComConnect,
            0x0c => PacketType::ComProcessKill,
            0x0d => PacketType::ComDebug,
            0x0e => PacketType::ComPing,
            0x0f => PacketType::ComTime,
            0x10 => PacketType::ComDelayedInsert,
            0x11 => PacketType::ComChangeUser,
            0x12 => PacketType::ComBinlogDump,
            0x13 => PacketType::ComTableDump,
            0x14 => PacketType::ComConnectOut,
            0x15 => PacketType::ComRegisterSlave,
            0x16 => PacketType::ComStmtPrepare,
            0x17 => PacketType::ComStmtExecute,
            0x18 => PacketType::ComStmtSendLongData,
            0x19 => PacketType::ComStmtClose,
            0x1a => PacketType::ComStmtReset,
            0x1d => PacketType::ComDaemon,
            0x1e => PacketType::ComBinlogDumpGtid,
            0x1f => PacketType::ComResetConnection,
            _ => panic!("Unsupported packet type")
        }
    }

}

pub enum Action {
    Forward,                // forward the packet unmodified
    Mutate(Packet),         // mutate the packet
    Respond(Vec<Packet>)    // handle directly and optionally return some packets
}

pub trait PacketHandler {
    fn handle_request(&self, p: &Packet) -> Action;
    fn handle_response(&self, p: &Packet) -> Action;
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve<H: PacketHandler + 'static>(self, conn: TcpStream,
                                             handler: H,
                                        ) -> Box<Future<Item = (u64, u64), Error = Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        let pair = connected.and_then(move |server| Ok((conn,server)));

        Box::new(pair.and_then(move |(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);
            Pipe::new(c1, c2, handler)
        }))
    }
}

#[derive(Debug)]
enum Direction {
    Client,
    Server
}

struct ConnReader {
    direction: Direction,
    stream: Rc<TcpStream>,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_amt: u64,
}

struct ConnWriter {
    direction: Direction,
    stream: Rc<TcpStream>,
    write_buf: Vec<u8>,
    write_pos: usize,
    write_amt: u64,
}

impl ConnReader {

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnReader {
            stream: stream,
            direction: direction,
            read_buf: vec![0u8; 4096],
            read_pos: 0,
            read_amt: 0,
        }
    }

    /// Read from the socket until the status is NotReady
    fn read(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} read()", self.direction);
        loop {
//            println!("{:?} before poll_read()", self.direction);
            try_ready!(self.stream.poll_read());
//            println!("{:?} before try_nb()", self.direction);
            //TODO: ensure capacity first
            let n = try_nb!((&*self.stream).read(&mut self.read_buf[self.read_pos..]));
            if n == 0 {
//                println!("{:?} Detected connection closed", self.direction);
                return Err(Error::new(ErrorKind::Other, "connection closed"));
            }
//            println!("{:?} read() read {} bytes", self.direction, n);
            self.read_amt += n as u64;
            self.read_pos += n;
        }
    }

    fn next(&mut self) -> Option<Packet> {
        // do we have a header
        if self.read_pos > 3 {
            let l = parse_packet_length(&self.read_buf);
            // do we have the whole packet?
            let s = 4 + l;
            if self.read_pos >= s {

                //TODO: clean up this hack
                let mut temp : Vec<u8> = vec![];
                temp.extend_from_slice( &self.read_buf[0..s]);
                let p = Packet { bytes: temp };

                // shift data down
                let mut j = 0;
                for i in s .. self.read_buf.len() {
                    self.read_buf[j] = self.read_buf[i];
                    j += 1;
                }
                self.read_pos -= s;

//                println!("{:?} parse_packet(): read_pos={}, returning packet:", self.direction, self.read_pos);
//                print_packet_bytes(&p.bytes);
//                print_packet_chars(&p.bytes);

                Some(p)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl ConnWriter{

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnWriter{
            stream: stream,
            direction: direction,
            write_buf: vec![0u8; 4096],
            write_pos: 0,
            write_amt: 0
        }
    }

    /// Write a packet to the write buffer
    fn push(&mut self, p: &Packet) {
        for i in 0 .. p.bytes.len() {
            self.write_buf[self.write_pos + i] = p.bytes[i];
        }
        self.write_pos += p.bytes.len();

//        self.write_buf.truncate(self.write_pos);
//        self.write_buf.extend_from_slice(&p.bytes);
//        self.write_pos += p.bytes.len();
//        println!("{:?} extended write buffer by {} bytes", self.direction, p.bytes.len());
    }

    /// Writes the contents of the write buffer to the socket
    fn write(&mut self) -> Poll<(), io::Error> {
//        println!("{:?} write()", self.direction);
        while self.write_pos > 0 {
            try_ready!(self.stream.poll_write());
            let s = try!((&*self.stream).write(&self.write_buf[0..self.write_pos]));
//            println!("{:?} Wrote {} bytes", self.direction, s);

            let mut j = 0;
            for i in s .. self.write_buf.len() {
                self.write_buf[j] = self.write_buf[i];
                j += 1;
            }
            self.write_pos -= s;

        }
        return Ok(Async::Ready(()));
    }
}

struct Pipe<H: PacketHandler + 'static> {
    client_reader: ConnReader,
    client_writer: ConnWriter,
    server_reader: ConnReader,
    server_writer: ConnWriter,
    handler: H,
}

impl<H> Pipe<H> where H: PacketHandler + 'static {
    fn new(client: Rc<TcpStream>,
           server: Rc<TcpStream>,
           handler: H
           ) -> Pipe<H> {

        Pipe {
            client_reader: ConnReader::new(client.clone(), Direction::Client),
            client_writer: ConnWriter::new(client, Direction::Client),
            server_reader: ConnReader::new(server.clone(), Direction::Server),
            server_writer: ConnWriter::new(server, Direction::Server),
            handler: handler,
        }
    }
}

impl<H> Future for Pipe<H> where H: PacketHandler + 'static {
    type Item = (u64, u64);
    type Error = Error;

    fn poll(&mut self) -> Poll<(u64, u64), io::Error> {
        //println!("poll()");

        loop {
            // try reading from client
//            println!("CLIENT READ");
            let client_read = self.client_reader.read();

            // if the client connection has closed, close the server connection too
            match &client_read {
                &Err(ref e) => { self.server_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered requests
            while let Some(request) = self.client_reader.next() {
                match self.handler.handle_request(&request) {
                    Action::Forward => self.server_writer.push(&request),
                    Action::Mutate(ref p2) => self.server_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.client_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to server
//            println!("SERVER WRITE");
            let server_write = self.server_writer.write();

            // try reading from server
//            println!("SERVER READ");
            let server_read = self.server_reader.read();

            // if the server connection has closed, close the client connection too
            match &server_read {
                &Err(ref e) => { self.client_writer.stream.shutdown(Shutdown::Write); },
                _ => {}
            }

            // process buffered responses
            while let Some(response) = self.server_reader.next() {
                match self.handler.handle_response(&response) {
                    Action::Forward => self.client_writer.push(&response),
                    Action::Mutate(ref p2) => self.client_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.server_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to client
//            println!("CLIENT WRITE");
            let client_write = self.client_writer.write();

//            println!("client_read = {:?}", client_read);
//            println!("client_write = {:?}", client_write);
//            println!("server_read = {:?}", server_read);
//            println!("server_write = {:?}", server_write);

            try_ready!(client_read);
            try_ready!(client_write);
            try_ready!(server_read);
            try_ready!(server_write);
        }

    }

}

#[allow(dead_code)]
pub fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
pub fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<|endoftext|>


<commit_before>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     spawn(proc()
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

extern crate rustrt;

use std::sync::atomic::{AtomicBool, SeqCst};
use std::cell::UnsafeCell;
use rustrt::local::Local;
use rustrt::task::Task;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

impl<T: Send> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: AtomicBool::new(false),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline(always)]
    fn lock_check(&self) -> bool
    {
        self.lock.compare_and_swap(false, true, SeqCst) != false
    }

    fn obtain_lock(&self)
    {
        if Local::exists(None::<Task>)
        {
            self.obtain_lock_with_runtime();
        }
        else
        {
            self.obtain_lock_without_runtime();
        }
    }

    fn obtain_lock_with_runtime(&self)
    {
        while self.lock_check()
        {
            std::task::deschedule();
        }
    }

    fn obtain_lock_without_runtime(&self)
    {
        while self.lock_check()
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T: Send> Deref<T> for SpinlockGuard<'a, T>
{
    fn deref<'a>(&'a self) -> &'a T { &*self.data }
}

impl<'a, T: Send> DerefMut<T> for SpinlockGuard<'a, T>
{
    fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T: Send> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, SeqCst);
    }
}
<commit_msg>proc() -> move||<commit_after>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in range(0, numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

extern crate rustrt;

use std::sync::atomic::{AtomicBool, SeqCst};
use std::cell::UnsafeCell;
use rustrt::local::Local;
use rustrt::task::Task;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

impl<T: Send> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: AtomicBool::new(false),
            data: UnsafeCell::new(user_data),
        }
    }

    #[inline(always)]
    fn lock_check(&self) -> bool
    {
        self.lock.compare_and_swap(false, true, SeqCst) != false
    }

    fn obtain_lock(&self)
    {
        if Local::exists(None::<Task>)
        {
            self.obtain_lock_with_runtime();
        }
        else
        {
            self.obtain_lock_without_runtime();
        }
    }

    fn obtain_lock_with_runtime(&self)
    {
        while self.lock_check()
        {
            std::task::deschedule();
        }
    }

    fn obtain_lock_without_runtime(&self)
    {
        while self.lock_check()
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T: Send> Deref<T> for SpinlockGuard<'a, T>
{
    fn deref<'a>(&'a self) -> &'a T { &*self.data }
}

impl<'a, T: Send> DerefMut<T> for SpinlockGuard<'a, T>
{
    fn deref_mut<'a>(&'a mut self) -> &'a mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T: Send> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, SeqCst);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::hash::Hash;

/// A type containing the full specification for an L-system.
pub struct LSystem<T, P> where P: LRules<T> {
    rules: P,
    pub axiom: Vec<T>,
    state: Vec<T>,
}

impl<T, P> LSystem<T, P> where P: LRules<T>, T: Clone {
    /// create a new L-System from rules and an axiom
    pub fn new(rules: P, axiom: Vec<T>) -> LSystem<T, P> {
        LSystem {
            rules: rules,
            state: axiom.clone(),
            axiom: axiom,
        }
    }

    /// reset the L-System state back to its axiom
    pub fn reset(&mut self) {
        self.state = self.axiom.clone();
    }
}

impl<T, P> Iterator for LSystem<T, P> where P: LRules<T>, T: Clone {
    type Item = Vec<T>;

    /// Get the next iteration of the L-System by evaluating its associated
    /// production rules on its current states.
    fn next(&mut self) -> Option<Vec<T>> {
        let mut i: usize = 0;
        let mut expanded = false;
        while i < self.state.len() {
            let atom = self.state[i].clone();
            let production = self.rules.map(&atom);
            match production {
                Some(atoms) => {
                    self.state.remove(i);
                    for a in atoms.into_iter() {
                        self.state.insert(i, a);
                        i += 1;
                    }
                    expanded = true;
                },
                None => {
                    i += 1;
                }
            }
        }
        if expanded {
            Some(self.state.clone())
        } else {
            None
        }

    }
}

/// A set of production rule for an L-system, which maps an item to a list of
/// items which will replace it in the L-system state.
pub trait LRules<T> {
    /// perform a mapping of one atom to a string.
    fn map(&self, input: &T) -> Option<Vec<T>>;
}

pub struct MapRules<T: Hash + Eq> {
    productions: HashMap<T, Vec<T>>,
}

impl<T> MapRules<T> where T: Hash + Eq {
    pub fn new() -> MapRules<T> {
        MapRules {
            productions: HashMap::new(),
        }
    }

    pub fn set(&mut self, k: T, v: Vec<T>) -> Option<Vec<T>> {
        self.productions.insert(k, v)
    }
}

impl MapRules<char> {
    pub fn set_str(&mut self, k: char, v: &str) -> Option<Vec<char>> {
        let mut rule = Vec::new();
        for c in v.chars() {
            rule.push(c);
        }
        self.set(k, rule)
    }
}

impl<T: ?Sized> LRules<T> for MapRules<T> where T: Clone + Hash + Eq {
    fn map(&self, input: &T) -> Option<Vec<T>> {
        match self.productions.get(input) {
            Some(v) => Some(v.clone()),
            None => None,
        }
    }
}

/// A convenience function to print out the String representation of a char
/// vector.
pub fn show(v: &Vec<char>) -> String {
    let mut out = String::with_capacity(v.len());
    for c in v.iter() {
        out.push(*c);
    }
    out
}

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

    #[test]
    fn test_algae_str() {
        let mut rules: MapRules<char> = MapRules::new();
        rules.set_str('A', "AB");
        rules.set_str('B', "A");
        let axiom = "A".chars().collect();
        let mut system = LSystem::new(rules, axiom);

        let out = system.next().unwrap();
        let expected: Vec<char> = "AB".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABA".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAAB".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABA".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABAABAAB".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABAABAABABAABABA".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABAABAABABAABABAABAABABAABAAB".chars().collect();
        assert_eq!(expected, out);
    }

    #[test]
    fn test_pythagoras_tree() {
        let mut rules: MapRules<char> = MapRules::new();
        rules.set_str('1', "11");
        rules.set_str('0', "1[0]0");
        let axiom = "0".chars().collect();
        let mut system = LSystem::new(rules, axiom);

        let out = system.next().unwrap();
        let expected: Vec<char> = "1[0]0".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "11[1[0]0]1[0]0".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "1111[11[1[0]0]1[0]0]11[1[0]0]1[0]0".chars().collect();
        assert_eq!(expected, out);
    }
}
<commit_msg>write some documentation<commit_after>//! A Library for specifying an L-System.  Formally, [L-system
//! formulations](https://en.wikipedia.org/wiki/L-system#L-system_structure)
//! consist of a vocabulary set, a starting axiom, and a set of production
//! rules.
//!
//! In this implementation, `LSystem<T>` is a fully formulated L-system on the
//! alphabet of all instances of type T.  Rule sets are any type that
//! implements the trait `LRules<T>`.
//!
//! # Examples
//!
//! Here is how you would write the original
//! [algae system](https://en.wikipedia.org/wiki/L-system#Example_1:_Algae)
//! used by Lindenmayer:
//!
//! ```
//! use lsystem::{LSystem, LRules, MapRules};
//!
//! let mut rules = MapRules::new();
//! rules.set_str('A', "AB");
//! rules.set_str('B', "A");
//! let axiom = "A".chars().collect();
//! let mut system = LSystem::new(rules, axiom);
//!
//! let out = system.next().unwrap();
//! let expected: Vec<char> = "AB".chars().collect();
//! assert_eq!(expected, out);
//!
//! let out = system.next().unwrap();
//! let expected: Vec<char> = "ABA".chars().collect();
//! assert_eq!(expected, out);
//!
//! let out = system.next().unwrap();
//! let expected: Vec<char> = "ABAAB".chars().collect();
//! assert_eq!(expected, out);
//! ```
//!
//! This is how you can write the
//! [Pythagoras Tree](https://en.wikipedia.org/wiki/L-system#Example_2:_Pythagoras_tree)
//! system:
//!
//! ```
//! use lsystem::{LSystem, LRules, MapRules};
//!
//! let mut rules = MapRules::new();
//! rules.set_str('1', "11");
//! rules.set_str('0', "1[0]0");
//! let axiom = "0".chars().collect();
//! let mut system = LSystem::new(rules, axiom);
//!
//! let out = system.next().unwrap();
//! let expected: Vec<char> = "1[0]0".chars().collect();
//! assert_eq!(expected, out);
//!
//! let out = system.next().unwrap();
//! let expected: Vec<char> = "11[1[0]0]1[0]0".chars().collect();
//! assert_eq!(expected, out);
//!
//! let out = system.next().unwrap();
//! let expected: Vec<char> = "1111[11[1[0]0]1[0]0]11[1[0]0]1[0]0".chars().collect();
//! assert_eq!(expected, out);
//! ```
//!
//! The MapRules struct is not restricted to strings. You can just as easily
//! use any type that can be stored in a hashmap.
//!
//! ```
//! use lsystem::{LSystem, LRules, MapRules};
//!
//! let mut rules = MapRules::new();
//! rules.set(0, vec![1, 0]);
//! rules.set(1, vec![0, 1, 1]);
//! let axiom = vec![0];
//! let mut system = LSystem::new(rules, axiom);
//!
//! let out = system.next().unwrap();
//! let expected = vec![1, 0];
//! assert_eq!(expected, out);
//!
//! let out = system.next().unwrap();
//! let expected = vec![0, 1, 1, 1, 0];
//! assert_eq!(expected, out);
//! ```

use std::collections::HashMap;
use std::hash::Hash;

/// A type containing the full specification for an L-system.
///
/// # Examples
///
/// Here is how you would write the original
/// [algae system](https://en.wikipedia.org/wiki/L-system#Example_1:_Algae)
/// used by Lindenmayer:
///
/// ```
/// use lsystem::{LSystem, LRules, MapRules};
///
/// let mut rules = MapRules::new();
/// rules.set_str('A', "AB");
/// rules.set_str('B', "A");
/// let axiom = "A".chars().collect();
/// let mut system = LSystem::new(rules, axiom);
///
/// let out = system.next().unwrap();
/// let expected: Vec<char> = "AB".chars().collect();
/// assert_eq!(expected, out);
///
/// let out = system.next().unwrap();
/// let expected: Vec<char> = "ABA".chars().collect();
/// assert_eq!(expected, out);
///
/// let out = system.next().unwrap();
/// let expected: Vec<char> = "ABAAB".chars().collect();
/// assert_eq!(expected, out);
/// ```
///
/// This is how you can write the
/// [Pythagoras Tree](https://en.wikipedia.org/wiki/L-system#Example_2:_Pythagoras_tree)
/// system:
///
/// ```
/// use lsystem::{LSystem, LRules, MapRules};
///
/// let mut rules = MapRules::new();
/// rules.set_str('1', "11");
/// rules.set_str('0', "1[0]0");
/// let axiom = "0".chars().collect();
/// let mut system = LSystem::new(rules, axiom);
///
/// let out = system.next().unwrap();
/// let expected: Vec<char> = "1[0]0".chars().collect();
/// assert_eq!(expected, out);
///
/// let out = system.next().unwrap();
/// let expected: Vec<char> = "11[1[0]0]1[0]0".chars().collect();
/// assert_eq!(expected, out);
///
/// let out = system.next().unwrap();
/// let expected: Vec<char> = "1111[11[1[0]0]1[0]0]11[1[0]0]1[0]0".chars().collect();
/// assert_eq!(expected, out);
/// ```
///
/// The MapRules struct is not restricted to strings. You can just as easily
/// use any type that can be stored in a hashmap.
///
/// ```
/// use lsystem::{LSystem, LRules, MapRules};
///
/// let mut rules = MapRules::new();
/// rules.set(0, vec![1, 0]);
/// rules.set(1, vec![0, 1, 1]);
/// let axiom = vec![0];
/// let mut system = LSystem::new(rules, axiom);
///
/// let out = system.next().unwrap();
/// let expected = vec![1, 0];
/// assert_eq!(expected, out);
///
/// let out = system.next().unwrap();
/// let expected = vec![0, 1, 1, 1, 0];
/// assert_eq!(expected, out);
/// ```
///
///
pub struct LSystem<T, P> where P: LRules<T> {
    rules: P,
    pub axiom: Vec<T>,
    state: Vec<T>,
}

impl<T, P> LSystem<T, P> where P: LRules<T>, T: Clone {
    /// create a new L-System from rules and an axiom
    pub fn new(rules: P, axiom: Vec<T>) -> LSystem<T, P> {
        LSystem {
            rules: rules,
            state: axiom.clone(),
            axiom: axiom,
        }
    }

    /// reset the L-System state back to its axiom
    pub fn reset(&mut self) {
        self.state = self.axiom.clone();
    }
}

impl<T, P> Iterator for LSystem<T, P> where P: LRules<T>, T: Clone {
    type Item = Vec<T>;

    /// Get the next iteration of the L-System by evaluating its associated
    /// production rules on its current states.
    fn next(&mut self) -> Option<Vec<T>> {
        let mut i: usize = 0;
        let mut expanded = false;
        while i < self.state.len() {
            let atom = self.state[i].clone();
            let production = self.rules.map(&atom);
            match production {
                Some(atoms) => {
                    self.state.remove(i);
                    for a in atoms.into_iter() {
                        self.state.insert(i, a);
                        i += 1;
                    }
                    expanded = true;
                },
                None => {
                    i += 1;
                }
            }
        }
        if expanded {
            Some(self.state.clone())
        } else {
            None
        }

    }
}

/// A set of production rule for an L-system, which maps an item to a list of
/// items which will replace it in the L-system state.
pub trait LRules<T> {
    /// perform a mapping of one atom to a string.  It returns `Some(Vec<T>)`
    /// if the atom is a variable with an existing production rule, or `None`
    /// if the atom should be considered terminal.
    fn map(&self, input: &T) -> Option<Vec<T>>;
}

/// A simple production ruleset that maps an atom to an atom string using a
/// lookup table.
///
/// # Examples
///
/// MapRules can be used to create L-system rules for any hashable type.
///
/// ```
/// use lsystem::{MapRules, LRules};
///
/// let mut rules = MapRules::new();
/// rules.set(0, vec![0, 1]);
/// rules.set(1, vec![1, 1, 2]);
///
/// assert_eq!(Some(vec![0, 1]), rules.map(&0));
/// assert_eq!(Some(vec![1, 1, 2]), rules.map(&1));
/// assert_eq!(None, rules.map(&3));
///
/// ```
///
/// If you are working with characters, MapRules has the `set_str` convenience
/// function to make it easier to work with strings.
///
/// ```
/// use lsystem::{MapRules, LRules};
///
/// let mut rules = MapRules::new();
/// rules.set_str('A', "AB");
/// rules.set_str('B', "A");
///
/// assert_eq!(Some("AB".chars().collect()), rules.map(&'A'));
/// ```
pub struct MapRules<T: Hash + Eq> {
    productions: HashMap<T, Vec<T>>,
}

impl<T> MapRules<T> where T: Hash + Eq {
    /// Create a new, empty ruleset.
    pub fn new() -> MapRules<T> {
        MapRules {
            productions: HashMap::new(),
        }
    }

    /// Set an atom to produce a vector
    pub fn set(&mut self, k: T, v: Vec<T>) -> Option<Vec<T>> {
        self.productions.insert(k, v)
    }
}

impl MapRules<char> {
    /// Set an atom to produce the Vec<char> corresponding to a string
    pub fn set_str(&mut self, k: char, v: &str) -> Option<Vec<char>> {
        let mut rule = Vec::new();
        for c in v.chars() {
            rule.push(c);
        }
        self.set(k, rule)
    }
}

impl<T: ?Sized> LRules<T> for MapRules<T> where T: Clone + Hash + Eq {
    fn map(&self, input: &T) -> Option<Vec<T>> {
        match self.productions.get(input) {
            Some(v) => Some(v.clone()),
            None => None,
        }
    }
}

/// A convenience function to print out the String representation of a char
/// vector.
pub fn show(v: &Vec<char>) -> String {
    let mut out = String::with_capacity(v.len());
    for c in v.iter() {
        out.push(*c);
    }
    out
}

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

    #[test]
    fn test_algae_str() {
        let mut rules = MapRules::new();
        rules.set_str('A', "AB");
        rules.set_str('B', "A");
        let axiom = "A".chars().collect();
        let mut system = LSystem::new(rules, axiom);

        let out = system.next().unwrap();
        let expected: Vec<char> = "AB".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABA".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAAB".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABA".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABAABAAB".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABAABAABABAABABA".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "ABAABABAABAABABAABABAABAABABAABAAB".chars().collect();
        assert_eq!(expected, out);
    }

    #[test]
    fn test_pythagoras_tree() {
        let mut rules: MapRules<char> = MapRules::new();
        rules.set_str('1', "11");
        rules.set_str('0', "1[0]0");
        let axiom = "0".chars().collect();
        let mut system = LSystem::new(rules, axiom);

        let out = system.next().unwrap();
        let expected: Vec<char> = "1[0]0".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "11[1[0]0]1[0]0".chars().collect();
        assert_eq!(expected, out);

        let out = system.next().unwrap();
        let expected: Vec<char> = "1111[11[1[0]0]1[0]0]11[1[0]0]1[0]0".chars().collect();
        assert_eq!(expected, out);
    }
}
<|endoftext|>


<commit_before>//! Fancy pure Rust crypto and hash library.
//!
//! The main reason this exists is so I can learn about cryptography.
//!
//! If you're asking "We have rust-crypto, why the hell do we need a new
//! library?"), `rust-crypto` was (at the time of Octavio's creation) big pile of… mess. To be honest
//! I doesn't hate `rust-crypto` but I wanted something that will be organized in fancy way, not
//! another OpenSSL (but written in Rust, so probably less buggy).
//!
//! Anther reason is that I want Octavo to became highly configurable via Cargo features. Each
//! cipher, hash family, MAC, etc. should be behind a feature.
//!
//! Oh… one more thing. I want to create C wrapper for Octavo (maybe even OpenSSL compatible), so
//! that you could use this beautiful peace of crap.
//!
//! Happy coding!
//!
//! ## Examples
//!
//!

extern crate byteorder;
#[cfg(feature = "num")] extern crate num;
#[cfg(feature = "rand")] extern crate rand;

pub mod crypto;
pub mod digest;
pub mod mac;

mod utils;
<commit_msg>Enable more lints<commit_after>//! Fancy pure Rust crypto and hash library.
//!
//! The main reason this exists is so I can learn about cryptography.
//!
//! If you're asking "We have rust-crypto, why the hell do we need a new
//! library?"), `rust-crypto` was (at the time of Octavio's creation) big pile of… mess. To be honest
//! I doesn't hate `rust-crypto` but I wanted something that will be organized in fancy way, not
//! another OpenSSL (but written in Rust, so probably less buggy).
//!
//! Anther reason is that I want Octavo to became highly configurable via Cargo features. Each
//! cipher, hash family, MAC, etc. should be behind a feature.
//!
//! Oh… one more thing. I want to create C wrapper for Octavo (maybe even OpenSSL compatible), so
//! that you could use this beautiful peace of crap.
//!
//! Happy coding!
//!
//! ## Examples
//!
//!

#![deny(trivial_casts, unreachable_code, while_true)]
#![warn(unused_qualifications)]

extern crate byteorder;
#[cfg(feature = "num")] extern crate num;
#[cfg(feature = "rand")] extern crate rand;

pub mod crypto;
pub mod digest;
pub mod mac;

mod utils;
<|endoftext|>