<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 std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::thread;
use std::thread::{JoinHandle, sleep_ms, Thread};
use std::sync::{Mutex, Condvar, Arc};
use std::sync::mpsc::channel;
use std::sync::mpsc::{Receiver, Sender};

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);
}

#[test]
fn bcs_constructor() {
    let bcs = BaseClientServer::new("clientid".to_string().into_bytes());
}

#[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.");
        };
        self.echo_conditions.remove(&data);
        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;

            cond.notify_one();
        }
    }
}

struct BaseClientServer<'a> {
    client_id: Vec<u8>,
    running: bool,
    active_connections: HashMap<&'a String, Arc<Mutex<Box<Connection>>>>,
    host_io: (Sender<Arc<Mutex<Box<&'a String>>>>, Receiver<Arc<Mutex<Box<&'a String>>>>),
}

impl <'a>BaseClientServer<'a> {

    fn new(client_id: Vec<u8>) -> BaseClientServer<'a> {
        BaseClientServer {
            client_id: client_id,
            running: true,
            active_connections: HashMap::new(),
            host_io: channel(),
        }
    }

    /*
    fn start(mut self) {
        let mut bcs_poll_handle = Arc::new(Mutex::new(&mut self));
        let mut bcs_conn_handle = bcs_poll_handle.clone();
        let poll_join_handle = Some(thread::scoped(move || BaseClientServer::_doPollLoop(bcs_poll_handle)));
        let connect_join_handle = Some(thread::scoped(move || BaseClientServer::_doConnectLoop(bcs_conn_handle)));
        // implicit join
    }
    */

    fn connectionManager(&'a mut self) {
        /* Run as a dedicated thread to manage the list of active/inactive connections */
        let (_, ref mut rx) = self.host_io;
        let ac = &mut self.active_connections;
        while self.running {
            let container = rx.recv().unwrap();
            let host = **container.lock().unwrap();
            let mut insert = false;
            let conn = match ac.get(host) {
                Some(conn) => {
                    let mut real_conn = conn.lock().unwrap();
                    real_conn.reconnect();
                    conn.clone()
                },
                None => {
                    let conn: Arc<Mutex<Box<Connection>>> = Arc::new(Mutex::new(Box::new(Connection::new(&host, 4730)))).clone();
                    {
                        let mut real_conn = conn.lock().unwrap();
                        real_conn.connect();
                    }
                    insert = true;
                    conn
                }
            };
            if insert {
                ac.insert(host, conn.clone());
            }
        }
        for (_, conn) in ac.iter() {
            let mut conn = conn.lock().unwrap();
            conn.disconnect();
        }
    }

    fn addServer(&'a self, host: &'a String) {
        let (ref tx, _) = self.host_io;
        tx.send(Arc::new(Mutex::new(Box::new(host))));
    }
}

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>Add polling manager which polls active connections<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::thread;
use std::thread::{JoinHandle, sleep_ms, Thread};
use std::sync::{Mutex, Condvar, Arc};
use std::sync::mpsc::channel;
use std::sync::mpsc::{Receiver, Sender};

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);
}

#[test]
fn bcs_constructor() {
    let bcs = BaseClientServer::new("clientid".to_string().into_bytes());
}

#[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.");
        };
        self.echo_conditions.remove(&data);
        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;

            cond.notify_one();
        }
    }
}

struct BaseClientServer<'a> {
    client_id: Vec<u8>,
    running: bool,
    active_connections: HashMap<&'a String, Arc<Mutex<Box<Connection>>>>,
    host_io: (Sender<Arc<Mutex<Box<&'a String>>>>, Receiver<Arc<Mutex<Box<&'a String>>>>),
    conn_io: (Sender<Arc<Mutex<Box<Connection>>>>, Receiver<Arc<Mutex<Box<Connection>>>>),
}

impl <'a>BaseClientServer<'a> {

    fn new(client_id: Vec<u8>) -> BaseClientServer<'a> {
        BaseClientServer {
            client_id: client_id,
            running: true,
            active_connections: HashMap::new(),
            host_io: channel(),
            conn_io: channel(),
        }
    }

    /*
    fn start(mut self) {
        let mut bcs_poll_handle = Arc::new(Mutex::new(&mut self));
        let mut bcs_conn_handle = bcs_poll_handle.clone();
        let poll_join_handle = Some(thread::scoped(move || BaseClientServer::_doPollLoop(bcs_poll_handle)));
        let connect_join_handle = Some(thread::scoped(move || BaseClientServer::_doConnectLoop(bcs_conn_handle)));
        // implicit join
    }
    */

    fn connectionManager(&'a mut self) {
        /* Run as a dedicated thread to manage the list of active/inactive connections */
        let (_, ref mut rx) = self.host_io;
        let ac = &mut self.active_connections;
        while self.running {
            let container = rx.recv().unwrap();
            let host = **container.lock().unwrap();
            let mut insert = false;
            let conn = match ac.get(host) {
                Some(conn) => {
                    let mut real_conn = conn.lock().unwrap();
                    real_conn.reconnect();
                    conn.clone()
                },
                None => {
                    let conn: Arc<Mutex<Box<Connection>>> = Arc::new(Mutex::new(Box::new(Connection::new(&host, 4730)))).clone();
                    {
                        let mut real_conn = conn.lock().unwrap();
                        real_conn.connect();
                    }
                    insert = true;
                    conn
                }
            };
            if insert {
                ac.insert(host, conn.clone());
            }
        }
        for (_, conn) in ac.iter() {
            let mut conn = conn.lock().unwrap();
            conn.disconnect();
        }
    }

    fn addServer(&'a self, host: &'a String) {
        let (ref tx, _) = self.host_io;
        tx.send(Arc::new(Mutex::new(Box::new(host))));
    }

    fn pollingManager(&'a self) {
        let (_, ref rx) = self.conn_io;
        let (ref tx, _) = self.host_io;
        let mut threads: Vec<JoinHandle<()>> = Vec::new();
        while self.running {
            let conn = rx.recv().unwrap();
            // poll this conn
            threads.push(thread::spawn(move || {
                let mut conn = conn.lock().unwrap();
                let p = conn.readPacket();
                // handle packet
            }));
        };
        // scoped threads all joined here
        for mut thread in threads {
            thread.join();
        }
    }
}

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>#[macro_use]
extern crate nom;

use std::str;
use std::str::FromStr;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;

#[derive(Debug, Clone)]
pub struct Sexp {
    element:Element,
    meta:Meta,
}

#[derive(Debug, Clone)]
pub enum Element {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

#[derive(Debug, Clone)]
pub struct Meta {
    indent:String,
    nl:usize,
}

pub type ERes<T> = Result<T, String>;

impl Sexp {

    fn new_empty() -> Sexp {
        Sexp { element:Element::Empty, meta:Meta { indent:String::from(""), nl:0,} }
    }

    fn new(element:Element, indent:String, nl:usize) -> Sexp {
        Sexp { element:element, meta:Meta { indent:indent, nl:nl, } }
    }

    pub fn list(&self) -> ERes<&Vec<Sexp> > {
        match self.element {
            Element::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> ERes<&String> {
        match self.element {
            Element::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> ERes<f64> {
        let s = try!(self.string());
        match f64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing float"))
        }
    }

    pub fn i(&self) -> ERes<i64> {
        let s = try!(self.string());
        match i64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing int"))
        }
    }

    pub fn list_name(&self) -> ERes<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> ERes<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st))
        };
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{}", self.meta.indent));
        try!(match self.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                let mut prev_nl = 0;
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 || x.meta.indent.len() > 0 || prev_nl > 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, x));
                    prev_nl = x.meta.nl;
                }
                write!(f, ")")
            },
            Element::Empty => Ok(())
        });
        for _ in 0..self.meta.nl {
            try!(writeln!(f,""));
        }
        Ok(())
    }
}

pub fn display_string(s:&String) -> String {
    if s.contains("(") || s.contains(" ") || s.len() == 0 {
        format!("\"{}\"", s)
    } else {
        s.clone()
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp, String> {
    if sexp.len() == 0 {
        return Ok(Sexp::new_empty())
    }
    match parse_sexp(&sexp.as_bytes()[..]) {
        nom::IResult::Done(_, c) => Ok(c),
        nom::IResult::Error(err) => {
            match err {
                nom::Err::Position(kind,p) =>
                    Err(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => Err(format!("parse error"))
            }
        },
        nom::IResult::Incomplete(x) => Err(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> Result<String, std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_file(name: &str) -> ERes<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("{:?}", x))
    });
    parse_str(&s[..])
}

named!(parse_qstring<String>,
       map_res!(
           map_res!(
               delimited!(char!('\"'), is_not!("\""), char!('\"')),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_bare_string<String>,
       map_res!(
           map_res!(
               is_not!(b")( \r\n"),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_string<String>,
       alt!(parse_qstring | parse_bare_string)
       );

named!(parse_list<Vec<Sexp> >,
       chain!(
           char!('(') ~
           v: many0!(parse_sexp) ~
           char!(')'),
           || v)
       );

// TODO: consider lines with just spaces and a nl as also nl
named!(line_ending<usize>,
       chain!(
           opt!(nom::space) ~
               c: opt!(is_a!(b"\r\n"))
               , || match c { None => 0, Some(ref x) => x.len(), }
               )
       );

named!(parse_sexp<Sexp>,
           chain!(
               indent: opt!(nom::space) ~
                   s: alt!(map!(parse_list,Element::List) | map!(parse_string,Element::String)) ~
                   nl: line_ending
                   ,
               || {
                   let indent = match indent {
                       None => String::new(),
                       Some(x) => String::from(str::from_utf8(x).unwrap()),
                   };
                   Sexp::new(s, indent, nl)
               })
       );

// internal tests
#[test]
fn test_qstring1() {
    assert_eq!(parse_string(&b"\"hello world\""[..]), nom::IResult::Done(&b""[..], String::from("hello world")));
}

#[test]
#[should_panic(expected="assertion failed: `(left == right)` (left: `Incomplete(Size(1))`, right: `Done([], \"hello\")`)")]
fn test_qstring2() {
    assert_eq!(parse_string(&b"\"hello"[..]), nom::IResult::Done(&b""[..], String::from("hello")));
}

#[test]
fn test_string1() {
    assert_eq!(parse_string(&b"hello world"[..]), nom::IResult::Done(&b" world"[..], String::from("hello")));
}

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

    #[allow(dead_code)]
    fn check_parse_res(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(o, t)
    }
    #[allow(dead_code)]
    fn check_parse(s: &str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(s, t)
    }

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }

    #[test]
    fn test_empty() { check_parse("") }

    #[test]
    fn test_empty_qstring() { check_parse("(hello \"\")") }

    #[test]
    fn test_minimal() { check_parse("()") }

    #[test]
    fn test_string() { check_parse("hello") }

    #[test]
    fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

    #[test]
    fn test_qstring_a2() { check_parse("\"hello world\"") }

    #[test]
    fn test_qstring_a3() { check_parse("\"hello(world)\"") }

    #[test]
    fn test_number() { check_parse("1.3") }

    #[test]
    fn test_float_vs_int() { check_parse("2.0") }

    #[test]
    fn test_double() { check_parse("(())") }

    #[test]
    fn test_br_string() { check_parse("(world)") }

    #[test]
    fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

    #[test]
    fn test_br_int() { check_parse("(42)") }

    #[test]
    fn test_br_float() { check_parse("(12.7)") }

    #[test]
    fn test_br_qbrstring() { check_parse("(\"(()\")") }

    #[test]
    fn test_number_string() { check_parse("567A_WZ") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(2)\"")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"parse error: Alt |)|\"")]
    fn test_invalid2() { parse_fail(")") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(1)\"")]
    fn test_invalid3() { parse_fail("\"hello") }

    #[test]
    fn test_complex() { check_parse("(module SWITCH_3W_SIDE_MMP221-R (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }

    #[test]
    fn test_multiline() {
        check_parse("\
(hello \"test it\"
    (foo bar)
    (mars venus)
)
")
    }

    #[test]
    fn test_multiline2() {
        check_parse("\
(hello world
  mad
    (world)
  not)")
    }

    #[test]
    fn test_multiline_two_empty() {
        check_parse("\
(hello

world)")
    }
}

<commit_msg>introduce IntroSexp<commit_after>#[macro_use]
extern crate nom;

use std::str;
use std::str::FromStr;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;

// like Into trait but works from a ref avoiding consumption or expensive clone
pub trait IntoSexp {
    fn into_sexp(&self) -> Sexp;
}

#[derive(Debug, Clone)]
pub struct Sexp {
    element:Element,
    meta:Meta,
}

#[derive(Debug, Clone)]
pub enum Element {
    String(String),
    List(Vec<Sexp>),
    Empty,
}

#[derive(Debug, Clone)]
pub struct Meta {
    indent:String,
    nl:usize,
}

pub type ERes<T> = Result<T, String>;

impl Sexp {

    fn new_empty() -> Sexp {
        Sexp { element:Element::Empty, meta:Meta { indent:String::from(""), nl:0,} }
    }

    fn new(element:Element, indent:String, nl:usize) -> Sexp {
        Sexp { element:element, meta:Meta { indent:indent, nl:nl, } }
    }

    pub fn from<T:IntoSexp>(t:&T) -> Sexp {
        t.into_sexp()
    }

    pub fn list(&self) -> ERes<&Vec<Sexp> > {
        match self.element {
            Element::List(ref v) => Ok(v),
            _ => Err(format!("not a list: {}", self))
        }
    }

    pub fn string(&self) -> ERes<&String> {
        match self.element {
            Element::String(ref s) => Ok(s),
            _ => Err(format!("not a string: {}", self))
        }
    }

    pub fn f(&self) -> ERes<f64> {
        let s = try!(self.string());
        match f64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing float"))
        }
    }

    pub fn i(&self) -> ERes<i64> {
        let s = try!(self.string());
        match i64::from_str(&s) {
            Ok(f) => Ok(f),
            _ => Err(format!("Error parsing int"))
        }
    }

    pub fn list_name(&self) -> ERes<&String> {
        let l = try!(self.list());
        let l = &l[..];
        let a = try!(l[0].string());
        Ok(a)
    }

    pub fn slice_atom(&self, s:&str) -> ERes<&[Sexp]> {
        let v = try!(self.list());
        let v2 =&v[..];
        let st = try!(v2[0].string());
        if st != s {
            return Err(format!("list doesn't start with {}, but with {}", s, st))
        };
        Ok(&v[1..])
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "{}", self.meta.indent));
        try!(match self.element {
            Element::String(ref s) => {
                if s.contains("(") || s.contains(" ") {
                    write!(f,"\"{}\"", s)
                } else {
                    write!(f,"{}", s)
                }
            },
            Element::List(ref v) => {
                try!(write!(f, "("));
                let mut prev_nl = 0;
                for (i, x) in v.iter().enumerate() {
                    let s = if i == 0 || x.meta.indent.len() > 0 || prev_nl > 0 { "" } else { " " };
                    try!(write!(f, "{}{}", s, x));
                    prev_nl = x.meta.nl;
                }
                write!(f, ")")
            },
            Element::Empty => Ok(())
        });
        for _ in 0..self.meta.nl {
            try!(writeln!(f,""));
        }
        Ok(())
    }
}

pub fn display_string(s:&String) -> String {
    if s.contains("(") || s.contains(" ") || s.len() == 0 {
        format!("\"{}\"", s)
    } else {
        s.clone()
    }
}

pub fn parse_str(sexp: &str) -> Result<Sexp, String> {
    if sexp.len() == 0 {
        return Ok(Sexp::new_empty())
    }
    match parse_sexp(&sexp.as_bytes()[..]) {
        nom::IResult::Done(_, c) => Ok(c),
        nom::IResult::Error(err) => {
            match err {
                nom::Err::Position(kind,p) =>
                    Err(format!("parse error: {:?} |{}|", kind, str::from_utf8(p).unwrap())),
                _ => Err(format!("parse error"))
            }
        },
        nom::IResult::Incomplete(x) => Err(format!("incomplete: {:?}", x)),
    }
}

fn read_file(name: &str) -> Result<String, std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_file(name: &str) -> ERes<Sexp> {
    let s = try!(match read_file(name) {
        Ok(s) => Ok(s),
        Err(x) => Err(format!("{:?}", x))
    });
    parse_str(&s[..])
}

named!(parse_qstring<String>,
       map_res!(
           map_res!(
               delimited!(char!('\"'), is_not!("\""), char!('\"')),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_bare_string<String>,
       map_res!(
           map_res!(
               is_not!(b")( \r\n"),
               str::from_utf8),
           FromStr::from_str)
       );

named!(parse_string<String>,
       alt!(parse_qstring | parse_bare_string)
       );

named!(parse_list<Vec<Sexp> >,
       chain!(
           char!('(') ~
           v: many0!(parse_sexp) ~
           char!(')'),
           || v)
       );

// TODO: consider lines with just spaces and a nl as also nl
named!(line_ending<usize>,
       chain!(
           opt!(nom::space) ~
               c: opt!(is_a!(b"\r\n"))
               , || match c { None => 0, Some(ref x) => x.len(), }
               )
       );

named!(parse_sexp<Sexp>,
           chain!(
               indent: opt!(nom::space) ~
                   s: alt!(map!(parse_list,Element::List) | map!(parse_string,Element::String)) ~
                   nl: line_ending
                   ,
               || {
                   let indent = match indent {
                       None => String::new(),
                       Some(x) => String::from(str::from_utf8(x).unwrap()),
                   };
                   Sexp::new(s, indent, nl)
               })
       );

// internal tests
#[test]
fn test_qstring1() {
    assert_eq!(parse_string(&b"\"hello world\""[..]), nom::IResult::Done(&b""[..], String::from("hello world")));
}

#[test]
#[should_panic(expected="assertion failed: `(left == right)` (left: `Incomplete(Size(1))`, right: `Done([], \"hello\")`)")]
fn test_qstring2() {
    assert_eq!(parse_string(&b"\"hello"[..]), nom::IResult::Done(&b""[..], String::from("hello")));
}

#[test]
fn test_string1() {
    assert_eq!(parse_string(&b"hello world"[..]), nom::IResult::Done(&b" world"[..], String::from("hello")));
}

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

    #[allow(dead_code)]
    fn check_parse_res(s: &str, o:&str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(o, t)
    }
    #[allow(dead_code)]
    fn check_parse(s: &str) {
        let e = parse_str(s).unwrap();
        let t = format!("{}", e);
        assert_eq!(s, t)
    }

    #[allow(dead_code)]
    fn parse_fail(s: &str) {
        parse_str(s).unwrap();
    }

    #[test]
    fn test_empty() { check_parse("") }

    #[test]
    fn test_empty_qstring() { check_parse("(hello \"\")") }

    #[test]
    fn test_minimal() { check_parse("()") }

    #[test]
    fn test_string() { check_parse("hello") }

    #[test]
    fn test_qstring_a() { check_parse_res("\"hello\"", "hello") }

    #[test]
    fn test_qstring_a2() { check_parse("\"hello world\"") }

    #[test]
    fn test_qstring_a3() { check_parse("\"hello(world)\"") }

    #[test]
    fn test_number() { check_parse("1.3") }

    #[test]
    fn test_float_vs_int() { check_parse("2.0") }

    #[test]
    fn test_double() { check_parse("(())") }

    #[test]
    fn test_br_string() { check_parse("(world)") }

    #[test]
    fn test_br_qstring() { check_parse_res("(\"world\")", "(world)") }

    #[test]
    fn test_br_int() { check_parse("(42)") }

    #[test]
    fn test_br_float() { check_parse("(12.7)") }

    #[test]
    fn test_br_qbrstring() { check_parse("(\"(()\")") }

    #[test]
    fn test_number_string() { check_parse("567A_WZ") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(2)\"")]
    fn test_invalid1() { parse_fail("(") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"parse error: Alt |)|\"")]
    fn test_invalid2() { parse_fail(")") }

    #[test]
    #[should_panic(expected="called `Result::unwrap()` on an `Err` value: \"incomplete: Size(1)\"")]
    fn test_invalid3() { parse_fail("\"hello") }

    #[test]
    fn test_complex() { check_parse("(module SWITCH_3W_SIDE_MMP221-R (layer F.Cu) (descr \"\") (pad 1 thru_hole rect (size 1.2 1.2) (at -2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 2 thru_hole rect (size 1.2 1.2) (at 0.0 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 3 thru_hole rect (size 1.2 1.2) (at 2.5 -1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 5 thru_hole rect (size 1.2 1.2) (at 0.0 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 6 thru_hole rect (size 1.2 1.2) (at -2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (pad 4 thru_hole rect (size 1.2 1.2) (at 2.5 1.6 0) (layers *.Cu *.Mask) (drill 0.8)) (fp_line (start -4.5 -1.75) (end 4.5 -1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 -1.75) (end 4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start 4.5 1.75) (end -4.5 1.75) (layer F.SilkS) (width 0.127)) (fp_line (start -4.5 1.75) (end -4.5 -1.75) (layer F.SilkS) (width 0.127)))") }

    #[test]
    fn test_multiline() {
        check_parse("\
(hello \"test it\"
    (foo bar)
    (mars venus)
)
")
    }

    #[test]
    fn test_multiline2() {
        check_parse("\
(hello world
  mad
    (world)
  not)")
    }

    #[test]
    fn test_multiline_two_empty() {
        check_parse("\
(hello

world)")
    }
}

<|endoftext|>


<commit_before>//#![feature(convert)]
#![crate_type="lib"]
extern crate byteorder;
pub mod xdr;

#[test]
fn u16_writer_test() {
	let mut x = xdr::XdrWriter::new();
	let wtr = vec![0,0,2,5];

	x.pack(517u16);
	assert_eq!(x.into_buffer(),wtr);
}

#[test]
fn u16_reader_test() {
	let wtr = vec![0,0,2,5];
	let mut x = xdr::XdrReader::new(&wtr);

	let v = x.unpack::<u16>().unwrap();
	assert_eq!(v,517u16);
}

#[test]
fn r_w_primitive_test() {
	let mut wr = xdr::XdrWriter::new();
	wr.pack(0xCCu8);
	wr.pack(0xAAAAu16);
	wr.pack(0xDEADBEEFu32);
	wr.pack(-1i8);
	wr.pack(-256i16);
	wr.pack(-20i32);
	wr.pack(100.500f32);
	wr.pack(-100.500e10f64);

	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	assert_eq!(0xCCu8,rdr.unpack::<u8>().unwrap());
	assert_eq!(0xAAAAu16,rdr.unpack::<u16>().unwrap());
	assert_eq!(0xDEADBEEFu32,rdr.unpack::<u32>().unwrap());
	assert_eq!(-1i8,rdr.unpack::<i8>().unwrap());
	assert_eq!(-256i16,rdr.unpack::<i16>().unwrap());
	assert_eq!(-20i32,rdr.unpack::<i32>().unwrap());
	assert_eq!(100.500f32,rdr.unpack::<f32>().unwrap());
	assert_eq!(-100.500e10f64,rdr.unpack::<f64>().unwrap());
}

#[test]
fn variable_length_array_test() {
	let mut wr = xdr::XdrWriter::new();
	let vec = vec![0u32,1,2,3,4,5];

	wr.pack(vec);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack::<Vec<u32>>().unwrap();

	assert_eq!(vec![0u32,1,2,3,4,5], res)
}

#[test]
fn fixed_length_array_test() {
	let mut wr = xdr::XdrWriter::new();
	let vec = vec![0u32,1,2,3,4,5];

	wr.pack_array(vec);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack_array::<u32>(6).unwrap();

	assert_eq!(vec![0u32,1,2,3,4,5], res)
}

#[test]
fn ascii_string_test() {
	let mut wr = xdr::XdrWriter::new();
	let str = "abcdefABCDEFGH".to_owned();

	wr.pack(str);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack::<String>().unwrap();

	assert_eq!("abcdefABCDEFGH", res)
}

#[test]
fn utf_8_string_test() {
	let mut wr = xdr::XdrWriter::new();
	let str = "abcdefABCDEFGHАБВГДЕЁ".to_owned();

	wr.pack(str);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack::<String>().unwrap();

	assert_eq!("abcdefABCDEFGHАБВГДЕЁ", res)
}
<commit_msg>Add initial rustdoc to xdr module<commit_after>/*!
  This crate provides External Data Representation(XDR) encoding and decoding functions.

  The XDR format RFC at https://tools.ietf.org/html/rfc4507

  Usage
  -----

## Encoding

```rust
extern crate xdr;

let mut wr = xdr::xdr::XdrWriter::new();
let str = "abcdefABCDEFGH".to_owned();

wr.pack(str);
let buf = wr.into_buffer();
```

## Decoding

```rust
extern crate xdr;
let buf = vec![0u8,0,0,0xB, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0];
let mut rdr = xdr::xdr::XdrReader::new(&buf);

match rdr.unpack::<String>() {
	Ok(v) => println!("{}", v),
	Err(_) => println!("fail")
}
```
 */

extern crate byteorder;
pub mod xdr;

#[test]
fn u16_writer_test() {
	let mut x = xdr::XdrWriter::new();
	let wtr = vec![0,0,2,5];

	x.pack(517u16);
	assert_eq!(x.into_buffer(),wtr);
}

#[test]
fn u16_reader_test() {
	let wtr = vec![0,0,2,5];
	let mut x = xdr::XdrReader::new(&wtr);

	let v = x.unpack::<u16>().unwrap();
	assert_eq!(v,517u16);
}

#[test]
fn r_w_primitive_test() {
	let mut wr = xdr::XdrWriter::new();
	wr.pack(0xCCu8);
	wr.pack(0xAAAAu16);
	wr.pack(0xDEADBEEFu32);
	wr.pack(-1i8);
	wr.pack(-256i16);
	wr.pack(-20i32);
	wr.pack(100.500f32);
	wr.pack(-100.500e10f64);

	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	assert_eq!(0xCCu8,rdr.unpack::<u8>().unwrap());
	assert_eq!(0xAAAAu16,rdr.unpack::<u16>().unwrap());
	assert_eq!(0xDEADBEEFu32,rdr.unpack::<u32>().unwrap());
	assert_eq!(-1i8,rdr.unpack::<i8>().unwrap());
	assert_eq!(-256i16,rdr.unpack::<i16>().unwrap());
	assert_eq!(-20i32,rdr.unpack::<i32>().unwrap());
	assert_eq!(100.500f32,rdr.unpack::<f32>().unwrap());
	assert_eq!(-100.500e10f64,rdr.unpack::<f64>().unwrap());
}

#[test]
fn variable_length_array_test() {
	let mut wr = xdr::XdrWriter::new();
	let vec = vec![0u32,1,2,3,4,5];

	wr.pack(vec);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack::<Vec<u32>>().unwrap();

	assert_eq!(vec![0u32,1,2,3,4,5], res)
}

#[test]
fn fixed_length_array_test() {
	let mut wr = xdr::XdrWriter::new();
	let vec = vec![0u32,1,2,3,4,5];

	wr.pack_array(vec);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack_array::<u32>(6).unwrap();

	assert_eq!(vec![0u32,1,2,3,4,5], res)
}

#[test]
fn ascii_string_test() {
	let mut wr = xdr::XdrWriter::new();
	let str = "abcdefABCDEFGH".to_owned();

	wr.pack(str);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack::<String>().unwrap();

	assert_eq!("abcdefABCDEFGH", res)
}

#[test]
fn utf_8_string_test() {
	let mut wr = xdr::XdrWriter::new();
	let str = "abcdefABCDEFGHАБВГДЕЁ".to_owned();

	wr.pack(str);
	let buf = &wr.into_buffer();
	let mut rdr = xdr::XdrReader::new(buf);

	let res = rdr.unpack::<String>().unwrap();

	assert_eq!("abcdefABCDEFGHАБВГДЕЁ", res)
}
<|endoftext|>


<commit_before>#![feature(macro_rules, globs)]

extern crate conduit;
extern crate "conduit-middleware" as conduit_middleware;
extern crate cookie;
extern crate serialize;
#[cfg(test)] extern crate "conduit-test" as test;

use std::fmt::Show;
use std::collections::hash_map::{Occupied, Vacant};
use conduit::{Request, Response};
use cookie::{CookieJar, Cookie};

pub use session::{RequestSession, SessionMiddleware};

mod session;

pub struct Middleware {
    key: Vec<u8>,
}

impl Middleware {
    pub fn new(key: &[u8]) -> Middleware {
        Middleware { key: key.to_vec() }
    }
}

impl conduit_middleware::Middleware for Middleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show + 'static>> {
        let jar = {
            let headers = req.headers();
            let mut jar = CookieJar::new(self.key.as_slice());
            match headers.find("Cookie") {
                Some(cookies) => {
                    for cookie in cookies.iter() {
                        match Cookie::parse(*cookie) {
                            Ok(c) => jar.add_original(c),
                            Err(..) => {}
                        }
                    }
                }
                None => {}
            }
            jar
        };
        req.mut_extensions().insert(jar);
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Show + 'static>>)
        -> Result<Response, Box<Show + 'static>>
    {
        let mut res = try!(res);
        {
            let jar = req.cookies();
            let cookies = match res.headers.entry("Set-Cookie".to_string()) {
                Occupied(e) => e.into_mut(),
                Vacant(e) => e.set(Vec::new()),
            };
            for delta in jar.delta().into_iter() {
                cookies.push(delta);
            }
        }
        Ok(res)
    }
}

pub trait RequestCookies<'a> {
    fn cookies(self) -> &'a CookieJar<'static>;
}

impl<'a> RequestCookies<'a> for &'a Request + 'a {
    fn cookies(self) -> &'a CookieJar<'static> {
        self.extensions().find::<CookieJar<'static>>()
            .expect("Missing cookie jar")
    }
}

#[cfg(test)]
mod tests {

    use conduit::{Request, Response, Handler, Post};
    use conduit_middleware::MiddlewareBuilder;
    use cookie::Cookie;
    use test::MockRequest;
    use std::collections::HashMap;
    use std::io::MemReader;

    use super::{RequestCookies, Middleware};

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(Post, "/articles");
        req.header("Cookie", "foo=bar");

        let mut app = MiddlewareBuilder::new(test);
        app.add(Middleware::new(b"foo"));
        assert!(app.call(&mut req).is_ok());

        fn test(req: &mut Request) -> Result<Response, String> {
            assert!(req.cookies().find("foo").is_some());
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }

    #[test]
    fn set_cookie() {
        let mut req = MockRequest::new(Post, "/articles");
        let mut app = MiddlewareBuilder::new(test);
        app.add(Middleware::new(b"foo"));
        let response = app.call(&mut req).ok().unwrap();
        let v = response.headers["Set-Cookie".to_string()].as_slice();
        assert_eq!(v, ["foo=bar; Path=/".to_string()].as_slice());

        fn test(req: &mut Request) -> Result<Response, String> {
            let c = Cookie::new("foo".to_string(), "bar".to_string());
            req.cookies().add(c);
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }
}
<commit_msg>Update to cookie master<commit_after>#![feature(macro_rules, globs)]

extern crate conduit;
extern crate "conduit-middleware" as conduit_middleware;
extern crate cookie;
extern crate serialize;
#[cfg(test)] extern crate "conduit-test" as test;

use std::fmt::Show;
use std::collections::hash_map::{Occupied, Vacant};
use conduit::{Request, Response};
use cookie::{CookieJar, Cookie};

pub use session::{RequestSession, SessionMiddleware};

mod session;

pub struct Middleware {
    key: Vec<u8>,
}

impl Middleware {
    pub fn new(key: &[u8]) -> Middleware {
        Middleware { key: key.to_vec() }
    }
}

impl conduit_middleware::Middleware for Middleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show + 'static>> {
        let jar = {
            let headers = req.headers();
            let mut jar = CookieJar::new(self.key.as_slice());
            match headers.find("Cookie") {
                Some(cookies) => {
                    for cookie in cookies.iter() {
                        match Cookie::parse(*cookie) {
                            Ok(c) => jar.add_original(c),
                            Err(..) => {}
                        }
                    }
                }
                None => {}
            }
            jar
        };
        req.mut_extensions().insert(jar);
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Show + 'static>>)
        -> Result<Response, Box<Show + 'static>>
    {
        let mut res = try!(res);
        {
            let jar = req.cookies();
            let cookies = match res.headers.entry("Set-Cookie".to_string()) {
                Occupied(e) => e.into_mut(),
                Vacant(e) => e.set(Vec::new()),
            };
            for delta in jar.delta().into_iter() {
                cookies.push(delta.to_string());
            }
        }
        Ok(res)
    }
}

pub trait RequestCookies<'a> {
    fn cookies(self) -> &'a CookieJar<'static>;
}

impl<'a> RequestCookies<'a> for &'a Request + 'a {
    fn cookies(self) -> &'a CookieJar<'static> {
        self.extensions().find::<CookieJar<'static>>()
            .expect("Missing cookie jar")
    }
}

#[cfg(test)]
mod tests {

    use conduit::{Request, Response, Handler, Post};
    use conduit_middleware::MiddlewareBuilder;
    use cookie::Cookie;
    use test::MockRequest;
    use std::collections::HashMap;
    use std::io::MemReader;

    use super::{RequestCookies, Middleware};

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(Post, "/articles");
        req.header("Cookie", "foo=bar");

        let mut app = MiddlewareBuilder::new(test);
        app.add(Middleware::new(b"foo"));
        assert!(app.call(&mut req).is_ok());

        fn test(req: &mut Request) -> Result<Response, String> {
            assert!(req.cookies().find("foo").is_some());
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }

    #[test]
    fn set_cookie() {
        let mut req = MockRequest::new(Post, "/articles");
        let mut app = MiddlewareBuilder::new(test);
        app.add(Middleware::new(b"foo"));
        let response = app.call(&mut req).ok().unwrap();
        let v = response.headers["Set-Cookie".to_string()].as_slice();
        assert_eq!(v, ["foo=bar; Path=/".to_string()].as_slice());

        fn test(req: &mut Request) -> Result<Response, String> {
            let c = Cookie::new("foo".to_string(), "bar".to_string());
            req.cookies().add(c);
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]
#![allow(dead_code)]
#![allow(missing_copy_implementations)]
#![feature(io)]

pub mod score;
pub mod search;
pub mod configuration;
pub mod renderer;

pub mod tty;
pub mod fake_tty;

pub mod ansi;
pub mod text;

pub mod screen;
<commit_msg>Silence a whole bunch more warnings<commit_after>#![allow(unstable)]
#![allow(dead_code)]
#![allow(missing_copy_implementations)]
#![feature(io, std_misc, core, collections, libc, path)]

pub mod score;
pub mod search;
pub mod configuration;
pub mod renderer;

pub mod tty;
pub mod fake_tty;

pub mod ansi;
pub mod text;

pub mod screen;
<|endoftext|>


<commit_before>mod travis;
mod circle;

use std::env;

#[derive(PartialEq, Debug)]
enum CiService {
    Travis,
    Circle,
    Unknown,
}

macro_rules! err {
    ($expr:expr) => {
        match $expr {
            Ok(val) => Some(val),
            Err(e) => match e {
                ::std::env::VarError::NotPresent => None,
                _ => panic!(e),
            }
        }
    }
}

struct Ci {
    service: CiService,
}
impl Ci {
    fn new() -> Option<Self> {
        let s = Ci::which_ci();
        match s {
            CiService::Travis | CiService::Circle => Some(Ci { service: s }),
            _ => None,
        }
    }

    fn which_ci() -> CiService {
        match (err!(env::var("TRAVIS")), err!(env::var("CIRCLECI"))) {
            (Some(_), None) => CiService::Travis,
            (None, Some(_)) => CiService::Circle,
            _ => CiService::Unknown,
        }
    }

    /// Returns the locale setting, g.e. `en_US.UTF-8`.
    fn lang() -> Option<String> {
        err!(env::var("LANG"))
    }

    /// Returns the search path.
    fn path() -> Option<String> {
        err!(env::var("PATH"))
    }

    /// Returns the path to the users home directory.
    fn home() -> Option<String> {
        err!(env::var("HOME"))
    }

    fn is_travis(&self) -> bool {
        match self.service {
            CiService::Travis => true,
            _ => false,
        }
    }

    fn is_circle(&self) -> bool {
        match self.service {
            CiService::Circle => true,
            _ => false,
        }
    }
}

fn ci() -> bool {
    err!(env::var("CI")).is_some() || err!(env::var("CONTINUOUS_INTEGRATION")).is_some()
}

#[test]
fn ci_test_unknown() {
    let ci = Ci::new();
    if ci.is_some() {
        return;
    }
    assert_eq!(Ci::which_ci(), CiService::Unknown);
}
<commit_msg>Add more CI agnostic methods<commit_after>mod travis;
mod circle;

use std::env;

#[derive(PartialEq, Debug)]
enum CiService {
    Travis,
    Circle,
    Unknown,
}

macro_rules! err {
    ($expr:expr) => {
        match $expr {
            Ok(val) => Some(val),
            Err(e) => match e {
                ::std::env::VarError::NotPresent => None,
                _ => panic!(e),
            }
        }
    }
}

struct Ci {
    service: CiService,
}
impl Ci {
    fn new() -> Option<Self> {
        let s = Ci::which_ci();
        match s {
            CiService::Travis | CiService::Circle => Some(Ci { service: s }),
            _ => None,
        }
    }

    fn which_ci() -> CiService {
        match (err!(env::var("TRAVIS")), err!(env::var("CIRCLECI"))) {
            (Some(_), None) => CiService::Travis,
            (None, Some(_)) => CiService::Circle,
            _ => CiService::Unknown,
        }
    }

    /// Returns the locale setting, g.e. `en_US.UTF-8`.
    fn lang() -> Option<String> {
        err!(env::var("LANG"))
    }

    /// Returns the search path.
    fn path() -> Option<String> {
        err!(env::var("PATH"))
    }

    /// Returns the path to the users home directory.
    fn home() -> Option<String> {
        err!(env::var("HOME"))
    }

    fn is_travis(&self) -> bool {
        match self.service {
            CiService::Travis => true,
            _ => false,
        }
    }

    fn is_circle(&self) -> bool {
        match self.service {
            CiService::Circle => true,
            _ => false,
        }
    }

    fn branch(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BRANCH")),
            CiService::Travis => err!(env::var("TRAVIS_BRANCH")),
            _ => None,
        }
    }

    /// Returns the build number.
    /// TODO: convert this to a number.
    fn build_id(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_BUILD_NUM")),
            CiService::Travis => err!(env::var("TRAVIS_BUILD_NUMBER")),
            _ => None,
        }
    }

    /// The sha1 hash of the commit being tested.
    fn commit(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_SHA1")),
            CiService::Travis => err!(env::var("TRAVIS_COMMIT")),
            _ => None,
        }
    }

    /// The number of the pull request this build forms part of.
    /// If this build is not part of a pull request, `None` is returned.
    /// TODO: convert this to a number.
    fn pull_request(&self) -> Option<String> {
        match self.service {
            CiService::Circle => err!(env::var("CIRCLE_PR_NUMBER")),
            CiService::Travis => {
                let pr = err!(env::var("TRAVIS_PULL_REQUEST")).unwrap_or("false".to_string());
                if pr == "false" {
                    None
                } else {
                    Some(pr)
                }
            }
            _ => None,
        }
    }

}

fn ci() -> bool {
    err!(env::var("CI")).is_some() || err!(env::var("CONTINUOUS_INTEGRATION")).is_some()
}

#[test]
fn ci_test_unknown() {
    let ci = Ci::new();
    if ci.is_some() {
        return;
    }
    assert_eq!(Ci::which_ci(), CiService::Unknown);
}
<|endoftext|>


<commit_before>//! # urlshortener
//!
//! An easy library for retrieving short urls.
//!
//! ## Installation
//!
//! Add the following dependency to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! urlshortener = "0.4"
//! ```
//!
//! And add this to your root file:
//!
//! ```no_run
//! extern crate urlshortener;
//! ```
//!
//! ## Usage
//!
//! Creating a short URL via a specified provider is very simple:
//!
//! ```no_run
//! use urlshortener::{Provider, UrlShortener};
//!
//! let us = UrlShortener::new();
//! let short_url = us.generate("https://my-long-url.com", Provider::IsGd);
//! assert!(short_url.is_ok());
//! ```
//!
//! Or attempting all URL shorteners until one is successfully generated:
//!
//! ```no_run
//! use urlshortener::UrlShortener;
//!
//! let us = UrlShortener::new();
//! let short_url = us.try_generate("https://my-long-url.com");
//! assert!(short_url.is_ok());
//! ```

#[macro_use]
extern crate log;
extern crate hyper;

mod providers;

pub use providers::{Provider, providers};

use providers::{parse, request};
use hyper::Client;
use std::io::{Error, ErrorKind, Read};
use std::time::Duration;

/// Url shortener - the way to retrieve a short url.
pub struct UrlShortener {
    client: Client,
}

impl UrlShortener {
    /// Creates new `UrlShortener` with default (3 seconds) timeout.
    pub fn new() -> UrlShortener {
        UrlShortener::with_timeout(3)
    }

    /// Creates new `UrlShortener` with custom read timeout.
    pub fn with_timeout(seconds: u64) -> UrlShortener {
        let mut client = hyper::Client::new();
        client.set_read_timeout(Some(Duration::from_secs(seconds)));

        UrlShortener { client: client }
    }

    /// Try to generate a short URL from each provider, iterating over each
    /// provider until a short URL is successfully generated.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use urlshortener::UrlShortener;
    ///
    /// let us = UrlShortener::new();
    /// let long_url = "https://rust-lang.org";
    /// let _short_url = us.try_generate(long_url);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an `Error<ErrorKind::Other>` if there is an error generating a
    /// short URL from all providers.
    pub fn try_generate<S: Into<String>>(&self,
                                         url: S) -> Result<String, Error> {
        let url = &url.into()[..];
        let mut providers = providers();

        let x = 0usize;

        loop {
            if providers.len() == 0 {
                break;
            }

            // This would normally have the potential to panic, except that a
            // check to ensure there is an element at this index is performed.
            let provider = providers.remove(x);
            let res = self.generate(url, provider);

            if let Ok(s) = res {
                return Ok(s);
            } else {
                warn!("Failed to get short link from service: {}",
                      res.unwrap_err());
            }
        }
        error!("Failed to get short link from any service");
        Err(Error::new(ErrorKind::Other,
                       "Failed to get short link from any service"))
    }

    /// Attempts to get a short URL using the specified provider.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use urlshortener::{Provider, UrlShortener};
    ///
    /// let us = UrlShortener::new();
    /// let long_url = "http://rust-lang.org";
    /// let short_url = us.generate(long_url, Provider::IsGd);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an `std::io::Error` if there is an error generating a
    /// short URL from the given provider due to either:
    ///
    /// a. a decode error (ErrorKind::Other);
    /// b. the service being unavailable (ErrorKind::ConnectionAborted)
    pub fn generate<S: Into<String>>(&self,
                                     url: S,
                                     provider: Provider) -> Result<String, Error> {
        let response_opt = request(&url.into(), &self.client, provider);

        if let Some(mut response) = response_opt {
            if response.status.is_success() {
                let mut short_url = String::new();
                if try!(response.read_to_string(&mut short_url)) > 0 {
                    if let Some(s) = parse(&short_url, provider) {
                        return Ok(s);
                    } else {
                        return Err(Error::new(ErrorKind::Other, "Decode error"));
                    }
                }
            }
        }
        Err(Error::new(ErrorKind::ConnectionAborted, "Service is unavailable"))
    }
}

#[cfg(test)]
mod tests {
    use std::io::ErrorKind;

    #[test]
    fn providers() {
        let us = ::UrlShortener::with_timeout(5);
        let url = "http://stackoverflow.com";

        for provider in ::providers() {
            if let Some(err) = us.generate(url, provider).err() {
                assert!(err.kind() == ErrorKind::ConnectionAborted);
            }
        }
    }
}
<commit_msg>updated version number in lib.rs documentation<commit_after>//! # urlshortener
//!
//! An easy library for retrieving short urls.
//!
//! ## Installation
//!
//! Add the following dependency to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! urlshortener = "0.5"
//! ```
//!
//! And add this to your root file:
//!
//! ```no_run
//! extern crate urlshortener;
//! ```
//!
//! ## Usage
//!
//! Creating a short URL via a specified provider is very simple:
//!
//! ```no_run
//! use urlshortener::{Provider, UrlShortener};
//!
//! let us = UrlShortener::new();
//! let short_url = us.generate("https://my-long-url.com", Provider::IsGd);
//! assert!(short_url.is_ok());
//! ```
//!
//! Or attempting all URL shorteners until one is successfully generated:
//!
//! ```no_run
//! use urlshortener::UrlShortener;
//!
//! let us = UrlShortener::new();
//! let short_url = us.try_generate("https://my-long-url.com");
//! assert!(short_url.is_ok());
//! ```

#[macro_use]
extern crate log;
extern crate hyper;

mod providers;

pub use providers::{Provider, providers};

use providers::{parse, request};
use hyper::Client;
use std::io::{Error, ErrorKind, Read};
use std::time::Duration;

/// Url shortener - the way to retrieve a short url.
pub struct UrlShortener {
    client: Client,
}

impl UrlShortener {
    /// Creates new `UrlShortener` with default (3 seconds) timeout.
    pub fn new() -> UrlShortener {
        UrlShortener::with_timeout(3)
    }

    /// Creates new `UrlShortener` with custom read timeout.
    pub fn with_timeout(seconds: u64) -> UrlShortener {
        let mut client = hyper::Client::new();
        client.set_read_timeout(Some(Duration::from_secs(seconds)));

        UrlShortener { client: client }
    }

    /// Try to generate a short URL from each provider, iterating over each
    /// provider until a short URL is successfully generated.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use urlshortener::UrlShortener;
    ///
    /// let us = UrlShortener::new();
    /// let long_url = "https://rust-lang.org";
    /// let _short_url = us.try_generate(long_url);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an `Error<ErrorKind::Other>` if there is an error generating a
    /// short URL from all providers.
    pub fn try_generate<S: Into<String>>(&self,
                                         url: S) -> Result<String, Error> {
        let url = &url.into()[..];
        let mut providers = providers();

        let x = 0usize;

        loop {
            if providers.len() == 0 {
                break;
            }

            // This would normally have the potential to panic, except that a
            // check to ensure there is an element at this index is performed.
            let provider = providers.remove(x);
            let res = self.generate(url, provider);

            if let Ok(s) = res {
                return Ok(s);
            } else {
                warn!("Failed to get short link from service: {}",
                      res.unwrap_err());
            }
        }
        error!("Failed to get short link from any service");
        Err(Error::new(ErrorKind::Other,
                       "Failed to get short link from any service"))
    }

    /// Attempts to get a short URL using the specified provider.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use urlshortener::{Provider, UrlShortener};
    ///
    /// let us = UrlShortener::new();
    /// let long_url = "http://rust-lang.org";
    /// let short_url = us.generate(long_url, Provider::IsGd);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an `std::io::Error` if there is an error generating a
    /// short URL from the given provider due to either:
    ///
    /// a. a decode error (ErrorKind::Other);
    /// b. the service being unavailable (ErrorKind::ConnectionAborted)
    pub fn generate<S: Into<String>>(&self,
                                     url: S,
                                     provider: Provider) -> Result<String, Error> {
        let response_opt = request(&url.into(), &self.client, provider);

        if let Some(mut response) = response_opt {
            if response.status.is_success() {
                let mut short_url = String::new();
                if try!(response.read_to_string(&mut short_url)) > 0 {
                    if let Some(s) = parse(&short_url, provider) {
                        return Ok(s);
                    } else {
                        return Err(Error::new(ErrorKind::Other, "Decode error"));
                    }
                }
            }
        }
        Err(Error::new(ErrorKind::ConnectionAborted, "Service is unavailable"))
    }
}

#[cfg(test)]
mod tests {
    use std::io::ErrorKind;

    #[test]
    fn providers() {
        let us = ::UrlShortener::with_timeout(5);
        let url = "http://stackoverflow.com";

        for provider in ::providers() {
            if let Some(err) = us.generate(url, provider).err() {
                assert!(err.kind() == ErrorKind::ConnectionAborted);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Half Sleep -- Mutation Testing for Rust
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

#![feature(custom_derive, plugin, plugin_registrar, rustc_private)]

extern crate rustc;
extern crate syntax;

use std::mem;
use rustc::plugin::Registry;
use syntax::ext::base::Modifier;
use syntax::parse::token;
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::fold::Folder;
use syntax::ptr::P;
use syntax::visit::Visitor;

mod locator;
mod mutator;
mod test_duper;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("mutation_test"),
        Modifier(Box::new(expand_mutation_test)));
}

/// Create several mutated copies of a given function
pub fn expand_mutation_test(cx: &mut ExtCtxt, _span: Span,
                            _meta: &ast::MetaItem, item: P<ast::Item>)
                           -> P<ast::Item> {

    // Check something sane has been decorated
    let this_mod = if let ast::ItemFn(_, _, _, _, _) = item.node {
        // We do nothing directly for decorated functions; when looking at
        // a module we make a note of which ones are decorated, then consider
        // them all at once. This lets us (a) keep track of how many should-fail
        // test have been created and (b) locate all the unit tests in the
        // first place.
        return item;
    } else if let ast::ItemMod(ref this_mod) = item.node {
        this_mod
    } else {
        cx.bug("#[mutation_test] can only be applied to functions and modules")
    };

    // At this point we know we are looking at a module
    // Locate all the decorated functions
    let mut loc = locator::Locator::new();
    loc.visit_item(&*item);

    let mut this_mod = this_mod.clone();
    // Attach mutated functions to the module
    let mut fn_list = vec![];
    mem::swap(&mut loc.mutants, &mut fn_list);
    for mut_fn in fn_list {
        println!("pushing fn");
        this_mod.items.push(P(mut_fn))
    }
    // Put the module into an item struct
    let mut item = (*item).clone();
    item.node = ast::Item_::ItemMod(this_mod);

    // Add new unit tests...
    let mut test_duper = test_duper::TestDuper::new(&loc);
    // ...and replace the module in the AST
    P(test_duper.fold_item_simple(item))
}

<commit_msg>Handle decorations on all types of items to prevent compiler warnings<commit_after>// Half Sleep -- Mutation Testing for Rust
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

#![feature(custom_derive, plugin, plugin_registrar, rustc_private)]

extern crate rustc;
extern crate syntax;

use std::mem;
use rustc::plugin::Registry;
use syntax::ext::base::{Annotatable, MultiModifier};
use syntax::parse::token;
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::ExtCtxt;
use syntax::fold::Folder;
use syntax::ptr::P;
use syntax::visit::Visitor;

mod locator;
mod mutator;
mod test_duper;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("mutation_test"),
        MultiModifier(Box::new(expand_mutation_test)));
}

/// emit a warning for #[mutation_test] markers on things which don't use them
fn complain_if_useless_annotation(cx: &mut ExtCtxt, item: &Annotatable) {
    let (warn, sp) = match *item {
        Annotatable::Item(ref i) => {
            (match i.node {
                 ast::Item_::ItemMod(_) | ast::Item_::ItemFn(_, _, _, _, _) => false,
                 _ => true
             }, i.span)
        },
        Annotatable::TraitItem(ref i) => {
            (match i.node {
                 ast::TraitItem_::MethodTraitItem(_, _) => false,
                 _ => true
             }, i.span)
        },
        Annotatable::ImplItem(ref i) => {
            (match i.node {
                 ast::ImplItem_::MethodImplItem(_, _) => false,
                 _ => true
             }, i.span)
        }
    };

    if warn {
        cx.span_warn(sp, "#[mutation_test] has no effect except on modules and functions");
    }
}

/// Create several mutated copies of a given function
pub fn expand_mutation_test(cx: &mut ExtCtxt, _span: Span,
                            _meta: &ast::MetaItem, item: Annotatable)
                           -> Annotatable {

    complain_if_useless_annotation(cx, &item);

    // Check something sane has been decorated
    let this_mod = if let Annotatable::Item(ref ast_item) = item {
        if let ast::ItemMod(ref this_mod) = ast_item.node {
            this_mod
        } else {
            // We do nothing directly for decorated functions; when looking at
            // a module we make a note of which ones are decorated, then consider
            // them all at once. This lets us (a) keep track of how many should-fail
            // test have been created and (b) locate all the unit tests in the
            // first place.
            // TODO: this clone is a lazy way around lack of non-lexically scoped borrows
            return item.clone();
        }
    } else {
        // TODO: this clone is a lazy way around lack of non-lexically scoped borrows
        return item.clone();
    };

    // At this point we know we are looking at a module
    // Locate all the decorated functions
    let item = if let Annotatable::Item(i) = item { i } else { unreachable!() };
    let mut loc = locator::Locator::new();
    loc.visit_item(&*item);

    let mut this_mod = this_mod.clone();
    // Attach mutated functions to the module
    let mut fn_list = vec![];
    mem::swap(&mut loc.mutants, &mut fn_list);
    for mut_fn in fn_list {
        println!("pushing fn");
        this_mod.items.push(P(mut_fn))
    }
    // Put the module into an item struct
    let mut item = (*item).clone();
    item.node = ast::Item_::ItemMod(this_mod);

    // Add new unit tests...
    let mut test_duper = test_duper::TestDuper::new(&loc);
    // ...and replace the module in the AST
    Annotatable::Item(P(test_duper.fold_item_simple(item)))
}

<|endoftext|>


<commit_before>// pub mod bufstream;
// mod buf;
// pub mod channel;
// pub mod mio;
// pub mod stream;
mod cell;
mod slot;
mod util;

mod error;
pub use error::{PollError, PollResult, FutureError, FutureResult};

// Primitive futures
mod done;
mod empty;
mod failed;
mod finished;
mod lazy;
mod promise;
pub use done::{done, Done};
pub use empty::{empty, Empty};
pub use failed::{failed, Failed};
pub use finished::{finished, Finished};
pub use lazy::{lazy, Lazy};
pub use promise::{promise, Promise, Complete};

// combinators
mod and_then;
mod chain;
mod flatten;
mod impls;
mod join;
mod map;
mod map_err;
mod or_else;
mod select;
mod then;
pub use and_then::AndThen;
pub use flatten::Flatten;
pub use join::Join;
pub use map::Map;
pub use map_err::MapErr;
pub use or_else::OrElse;
pub use select::Select;
pub use then::Then;

// mod collect;
// pub use collect::{collect, Collect};

// TODO: Send + 'static is annoying, but required by cancel and_then, document
// TODO: not object safe
//
// FINISH CONDITIONS
//      - poll() return Some
//      - await() is called
//      - schedule() is called
//      - schedule_boxed() is called
//
// BAD:
//      - doing any finish condition after an already called finish condition
//
// WHAT HAPPENS
//      - panic?
pub trait Future: Send + 'static {
    type Item: Send + 'static;
    type Error: Send + 'static;

    fn poll(&mut self) -> Option<PollResult<Self::Item, Self::Error>>;

    // TODO: why is this not drop()
    fn cancel(&mut self);

    fn schedule<F>(&mut self, f: F)
        where F: FnOnce(PollResult<Self::Item, Self::Error>) + Send + 'static,
              Self: Sized;

    fn schedule_boxed(&mut self, f: Box<Callback<Self::Item, Self::Error>>);

    // TODO: why can't this be in this lib?
    // fn await(&mut self) -> FutureResult<Self::Item, Self::Error>;

    fn boxed(self) -> Box<Future<Item=Self::Item, Error=Self::Error>>
        where Self: Sized
    {
        Box::new(self)
    }

    // TODO: compare this to `.then(|x| x.map(f))`
    fn map<F, U>(self, f: F) -> Map<Self, F>
        where F: FnOnce(Self::Item) -> U + Send + 'static,
              Self: Sized,
    {
        map::new(self, f)
    }

    // TODO: compare this to `.then(|x| x.map_err(f))`
    fn map_err<F, E>(self, f: F) -> MapErr<Self, F>
        where F: FnOnce(Self::Error) -> E + Send + 'static,
              E: Send + 'static,
              Self: Sized,
    {
        map_err::new(self, f)
    }

    fn then<F, B>(self, f: F) -> Then<Self, B, F>
        where F: FnOnce(Result<Self::Item, Self::Error>) -> B + Send + 'static,
              B: IntoFuture,
              Self: Sized,
    {
        then::new(self, f)
    }

    // TODO: compare this to
    //  ```
    //  .then(|res| {
    //      match res {
    //          Ok(e) => Either::First(f(e).into_future()),
    //          Err(e) => Either::Second(failed(e)),
    //      }
    //  })
    // ```
    fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
        where F: FnOnce(Self::Item) -> B + Send + 'static,
              B: IntoFuture<Error = Self::Error>,
              Self: Sized,
    {
        and_then::new(self, f)
    }

    // TODO: compare this to
    //  ```
    //  .then(|res| {
    //      match res {
    //          Ok(e) => Either::First(finished(e)),
    //          Err(e) => Either::Second(f(e).into_future()),
    //      }
    //  })
    // ```
    fn or_else<F, B>(self, f: F) -> OrElse<Self, B, F>
        where F: FnOnce(Self::Error) -> B + Send + 'static,
              B: IntoFuture<Item = Self::Item>,
              Self: Sized,
    {
        or_else::new(self, f)
    }

    fn select<B>(self, other: B) -> Select<Self, B::Future>
        where B: IntoFuture<Item=Self::Item, Error=Self::Error>,
              Self: Sized,
    {
        select::new(self, other.into_future())
    }

    fn join<B>(self, other: B) -> Join<Self, B::Future>
        where B: IntoFuture<Error=Self::Error>,
              Self: Sized,
    {
        join::new(self, other.into_future())
    }

    // TODO: check this is the same as `and_then(|x| x)`
    fn flatten(self) -> Flatten<Self>
        where Self::Item: IntoFuture,
              <<Self as Future>::Item as IntoFuture>::Error:
                    From<<Self as Future>::Error>,
              Self: Sized
    {
        flatten::new(self)
    }
}

pub trait Callback<T, E>: Send + 'static {
    fn call(self: Box<Self>, result: PollResult<T, E>);
}

impl<F, T, E> Callback<T, E> for F
    where F: FnOnce(PollResult<T, E>) + Send + 'static
{
    fn call(self: Box<F>, result: PollResult<T, E>) {
        (*self)(result)
    }
}

pub trait IntoFuture: Send + 'static {
    type Future: Future<Item=Self::Item, Error=Self::Error>;
    type Item: Send + 'static;
    type Error: Send + 'static;

    fn into_future(self) -> Self::Future;
}

impl<F: Future> IntoFuture for F {
    type Future = F;
    type Item = F::Item;
    type Error = F::Error;

    fn into_future(self) -> F {
        self
    }
}
<commit_msg>That's why cancel isn't drop<commit_after>// pub mod bufstream;
// mod buf;
// pub mod channel;
// pub mod mio;
// pub mod stream;
mod cell;
mod slot;
mod util;

mod error;
pub use error::{PollError, PollResult, FutureError, FutureResult};

// Primitive futures
mod done;
mod empty;
mod failed;
mod finished;
mod lazy;
mod promise;
pub use done::{done, Done};
pub use empty::{empty, Empty};
pub use failed::{failed, Failed};
pub use finished::{finished, Finished};
pub use lazy::{lazy, Lazy};
pub use promise::{promise, Promise, Complete};

// combinators
mod and_then;
mod chain;
mod flatten;
mod impls;
mod join;
mod map;
mod map_err;
mod or_else;
mod select;
mod then;
pub use and_then::AndThen;
pub use flatten::Flatten;
pub use join::Join;
pub use map::Map;
pub use map_err::MapErr;
pub use or_else::OrElse;
pub use select::Select;
pub use then::Then;

// mod collect;
// pub use collect::{collect, Collect};

// TODO: Send + 'static is annoying, but required by cancel and_then, document
// TODO: not object safe
//
// FINISH CONDITIONS
//      - poll() return Some
//      - await() is called
//      - schedule() is called
//      - schedule_boxed() is called
//
// BAD:
//      - doing any finish condition after an already called finish condition
//
// WHAT HAPPENS
//      - panic?
pub trait Future: Send + 'static {
    type Item: Send + 'static;
    type Error: Send + 'static;

    fn poll(&mut self) -> Option<PollResult<Self::Item, Self::Error>>;

    // TODO: why is this not drop()
    //       well what if you schedule() then drop, HUH?!
    fn cancel(&mut self);

    fn schedule<F>(&mut self, f: F)
        where F: FnOnce(PollResult<Self::Item, Self::Error>) + Send + 'static,
              Self: Sized;

    fn schedule_boxed(&mut self, f: Box<Callback<Self::Item, Self::Error>>);

    // TODO: why can't this be in this lib?
    // fn await(&mut self) -> FutureResult<Self::Item, Self::Error>;

    fn boxed(self) -> Box<Future<Item=Self::Item, Error=Self::Error>>
        where Self: Sized
    {
        Box::new(self)
    }

    // TODO: compare this to `.then(|x| x.map(f))`
    fn map<F, U>(self, f: F) -> Map<Self, F>
        where F: FnOnce(Self::Item) -> U + Send + 'static,
              Self: Sized,
    {
        map::new(self, f)
    }

    // TODO: compare this to `.then(|x| x.map_err(f))`
    fn map_err<F, E>(self, f: F) -> MapErr<Self, F>
        where F: FnOnce(Self::Error) -> E + Send + 'static,
              E: Send + 'static,
              Self: Sized,
    {
        map_err::new(self, f)
    }

    fn then<F, B>(self, f: F) -> Then<Self, B, F>
        where F: FnOnce(Result<Self::Item, Self::Error>) -> B + Send + 'static,
              B: IntoFuture,
              Self: Sized,
    {
        then::new(self, f)
    }

    // TODO: compare this to
    //  ```
    //  .then(|res| {
    //      match res {
    //          Ok(e) => Either::First(f(e).into_future()),
    //          Err(e) => Either::Second(failed(e)),
    //      }
    //  })
    // ```
    fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
        where F: FnOnce(Self::Item) -> B + Send + 'static,
              B: IntoFuture<Error = Self::Error>,
              Self: Sized,
    {
        and_then::new(self, f)
    }

    // TODO: compare this to
    //  ```
    //  .then(|res| {
    //      match res {
    //          Ok(e) => Either::First(finished(e)),
    //          Err(e) => Either::Second(f(e).into_future()),
    //      }
    //  })
    // ```
    fn or_else<F, B>(self, f: F) -> OrElse<Self, B, F>
        where F: FnOnce(Self::Error) -> B + Send + 'static,
              B: IntoFuture<Item = Self::Item>,
              Self: Sized,
    {
        or_else::new(self, f)
    }

    fn select<B>(self, other: B) -> Select<Self, B::Future>
        where B: IntoFuture<Item=Self::Item, Error=Self::Error>,
              Self: Sized,
    {
        select::new(self, other.into_future())
    }

    fn join<B>(self, other: B) -> Join<Self, B::Future>
        where B: IntoFuture<Error=Self::Error>,
              Self: Sized,
    {
        join::new(self, other.into_future())
    }

    // TODO: check this is the same as `and_then(|x| x)`
    fn flatten(self) -> Flatten<Self>
        where Self::Item: IntoFuture,
              <<Self as Future>::Item as IntoFuture>::Error:
                    From<<Self as Future>::Error>,
              Self: Sized
    {
        flatten::new(self)
    }
}

pub trait Callback<T, E>: Send + 'static {
    fn call(self: Box<Self>, result: PollResult<T, E>);
}

impl<F, T, E> Callback<T, E> for F
    where F: FnOnce(PollResult<T, E>) + Send + 'static
{
    fn call(self: Box<F>, result: PollResult<T, E>) {
        (*self)(result)
    }
}

pub trait IntoFuture: Send + 'static {
    type Future: Future<Item=Self::Item, Error=Self::Error>;
    type Item: Send + 'static;
    type Error: Send + 'static;

    fn into_future(self) -> Self::Future;
}

impl<F: Future> IntoFuture for F {
    type Future = F;
    type Item = F::Item;
    type Error = F::Error;

    fn into_future(self) -> F {
        self
    }
}
<|endoftext|>