<commit_before>#![feature(mpsc_select)]
#![feature(scoped)]
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::io;
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, RecvError};

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);
    match conn.sendPacket(p) {
        Ok(_) => {},
        Err(_) => panic!("Error in sendPacket."),
    }
}

#[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) -> io::Result<()> {
        match self.conn {
            None => {
                self.conn = Some(try!(TcpStream::connect((&self.host as &str, self.port))));
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
        return Ok(());
    }

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

    fn reconnect(&mut self) -> io::Result<()> {
        self.disconnect();
        try!(self.connect());
        return Ok(());
    }

    fn sendPacket(&mut self, packet: Packet) -> io::Result<()> {
        match self.conn {
            Some(ref mut c) => {
                match packet.code {
                    PacketCode::REQ => { try!(c.write(&REQ)); }
                    PacketCode::RES => { try!(c.write(&RES)); }
                }
                try!(c.write_u32::<BigEndian>(packet.ptype));
                try!(c.write_u32::<BigEndian>(packet.data.len() as u32));
                try!(c.write_all(&packet.data));
                Ok(())
            },
            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) -> io::Result<Packet> {
        match self.conn {
            Some(ref mut c) => {
                let mut code: Vec<u8> = Vec::new();
                {
                    let mut codestream = c.take(4);
                    try!(codestream.read_to_end(&mut code));
                }
                let code: PacketCode = Connection::_code_from_vec(code).unwrap();
                let ptype   = try!(c.read_u32::<BigEndian>());
                let datalen = try!(c.read_u32::<BigEndian>());
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                try!(datastream.read_to_end(&mut buf));
                Ok(
                    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>) -> io::Result<()> {
        let p = Packet::new(PacketCode::REQ, ECHO_REQ, data.into_boxed_slice());
        try!(self.sendPacket(p));
        Ok(())
    }

    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 {
    client_id: Vec<u8>,
    running: bool,
    active_connections: HashMap<(String, u16), Arc<Mutex<Box<Connection>>>>,
    host_io: (Sender<Arc<Mutex<Box<(String, u16)>>>>, Receiver<Arc<Mutex<Box<(String, u16)>>>>),
    conn_io: (Sender<Arc<Mutex<Box<Connection>>>>, Receiver<Arc<Mutex<Box<Connection>>>>),
    hosts: Vec<String>,
}

impl BaseClientServer {

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

    /*
    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
    }
    */

    #[allow(unstable)]
    fn connectionManager(&mut self) {
        /* Run as a dedicated thread to manage the list of active/inactive connections */
        let (_, ref mut rx) = self.host_io;
        let (ref mut tx, _) = self.conn_io;
        let (new_tx, new_rx) = channel();
        let ac = &mut self.active_connections;
        while self.running {
            let container: Result<Arc<Mutex<Box<Connection>>>, RecvError>;
            /* either a new conn is requested, or a new conn is connected */
            select!(
                container = rx.recv() => {
                    let container = match container {
                        Ok(container) => container,
                        Err(_) => panic!("Could not receive in connection manager"),
                    };
                    let (ref host, port) = **container.lock().unwrap();
                    let mut insert = false;
                    let tx = tx.clone();
                    let new_tx = new_tx.clone();
                    match ac.get(&(host.clone(), port)) {
                        Some(conn) => {
                            thread::scoped(move || {
                                let mut real_conn = conn.lock().unwrap();
                                while true {
                                    match real_conn.reconnect() {
                                        Ok(_) => break,
                                        Err(_) => {
                                            /* log warning about reconnecting */
                                            thread::sleep_ms(1000);
                                        },
                                    }
                                };
                                tx.send(conn.clone());
                            });
                        },
                        None => {
                            thread::scoped(move || {
                                let conn: Arc<Mutex<Box<Connection>>> = Arc::new(Mutex::new(Box::new(Connection::new(&host, port)))).clone();
                                {
                                    let mut real_conn = conn.lock().unwrap();
                                    while true {
                                        match real_conn.connect() {
                                            Ok(_) => break,
                                            Err(_) => {
                                                /* log warning */
                                                thread::sleep_ms(1000);
                                            }
                                        }
                                    };
                                }
                                new_tx.send(conn.clone());
                            });
                        }
                    };
                },
                conn = new_rx.recv() => {
                    let conn = match conn {
                        Ok(conn) => conn,
                        Err(_) => panic!("Could not receive in connection manager"),
                    };
                    {
                        let ref real_conn = **conn.lock().unwrap();
                        let host = real_conn.host.clone();
                        ac.insert((host, real_conn.port), conn.clone());
                    }
                    tx.send(conn.clone());
                }
            )
        }
        for (_, conn) in ac.iter() {
            let mut conn = conn.lock().unwrap();
            conn.disconnect();
        }
    }

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

    fn pollingManager(&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();
            let tx = tx.clone();
            // poll this conn
            threads.push(thread::spawn(move || {
                while true {
                    let mut conn = conn.lock().unwrap();
                    match conn.readPacket() {
                        Ok(p) => { /* handle packet */ },
                        Err(e) => {
                            /* Log failure */
                            tx.send(Arc::new(Mutex::new(Box::new((conn.host.clone(), conn.port)))));
                            break;
                        }
                    }
                }
            }));
        };
        // 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,
        }
    }
}
<commit_msg>Add test for connectionManager and pollingManager<commit_after>#![feature(mpsc_select)]
#![feature(scoped)]
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::io;
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, RwLock, Condvar, Arc};
use std::sync::mpsc::channel;
use std::sync::mpsc::{Receiver, Sender, RecvError};

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);
    match conn.sendPacket(p) {
        Ok(_) => {},
        Err(_) => panic!("Error in sendPacket."),
    }
}

#[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());
}

#[test]
fn bcs_run() {
    println!("Begin");
    let mut bcs = BaseClientServer::new("clientid".to_string().into_bytes());
    let mut bcs: Arc<RwLock<BaseClientServer>> = Arc::new(RwLock::new(bcs));
    let (host_tx, host_rx) = channel();
    let (conn_tx, conn_rx) = channel();
    let (stop_cm_tx, stop_cm_rx) = channel();
    let (stop_pm_tx, stop_pm_rx) = channel();
    let bcs0 = bcs.clone();
    let bcs1 = bcs.clone();
    println!("Starting threads");
    let tc = thread::spawn(move || {
        BaseClientServer::connectionManager(bcs0, stop_cm_rx, host_rx, conn_tx.clone());
    });
    println!("Started connection manager");
    let tp = thread::spawn(move || {
        BaseClientServer::pollingManager(bcs1, stop_pm_rx, host_tx.clone(), conn_rx);
    });
    println!("Started polling manager");
    // scoped join
    thread::sleep_ms(100);
    (*bcs).write().unwrap().running = false;
    println!("Sending connection manager stop");
    stop_cm_tx.send(());
    println!("Sending polling manager stop");
    stop_pm_tx.send(());
    println!("Joining polling manager...");
    tp.join();
    println!("Joining connection manager...");
    tc.join();
}

#[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) -> io::Result<()> {
        match self.conn {
            None => {
                self.conn = Some(try!(TcpStream::connect((&self.host as &str, self.port))));
                self.connect_time = Some(time::now_utc());
            },
            Some(_) => { /* log debug "already connected" */ },
        }
        return Ok(());
    }

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

    fn reconnect(&mut self) -> io::Result<()> {
        self.disconnect();
        try!(self.connect());
        return Ok(());
    }

    fn sendPacket(&mut self, packet: Packet) -> io::Result<()> {
        match self.conn {
            Some(ref mut c) => {
                match packet.code {
                    PacketCode::REQ => { try!(c.write(&REQ)); }
                    PacketCode::RES => { try!(c.write(&RES)); }
                }
                try!(c.write_u32::<BigEndian>(packet.ptype));
                try!(c.write_u32::<BigEndian>(packet.data.len() as u32));
                try!(c.write_all(&packet.data));
                Ok(())
            },
            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) -> io::Result<Packet> {
        match self.conn {
            Some(ref mut c) => {
                let mut code: Vec<u8> = Vec::new();
                {
                    let mut codestream = c.take(4);
                    try!(codestream.read_to_end(&mut code));
                }
                let code: PacketCode = Connection::_code_from_vec(code).unwrap();
                let ptype   = try!(c.read_u32::<BigEndian>());
                let datalen = try!(c.read_u32::<BigEndian>());
                let mut datastream = c.take(datalen as u64);
                let mut buf: Vec<u8> = Vec::new();
                try!(datastream.read_to_end(&mut buf));
                Ok(
                    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>) -> io::Result<()> {
        let p = Packet::new(PacketCode::REQ, ECHO_REQ, data.into_boxed_slice());
        try!(self.sendPacket(p));
        Ok(())
    }

    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 {
    client_id: Vec<u8>,
    running: bool,
    active_connections: HashMap<(String, u16), Arc<Mutex<Box<Connection>>>>,
    hosts: Vec<String>,
}

impl BaseClientServer {

    fn new(client_id: Vec<u8>) -> BaseClientServer {
        BaseClientServer {
            client_id: client_id,
            running: true,
            active_connections: HashMap::new(),
            hosts: Vec::new(),
        }
    }

    /*
    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
    }
    */

    #[allow(unstable)]
    fn connectionManager(bcs: Arc<RwLock<BaseClientServer>>,
                         stop_rx: Receiver<()>,
                         host_rx: Receiver<Arc<Mutex<Box<(String, u16)>>>>,
                         conn_tx: Sender<Arc<Mutex<Box<Connection>>>>) {
        /* Run as a dedicated thread to manage the list of active/inactive connections */
        let (new_tx, new_rx) = channel();
        while bcs.read().unwrap().running {
            let container: Result<Arc<Mutex<Box<Connection>>>, RecvError>;
            /* either a new conn is requested, or a new conn is connected */
            select!(
                container = host_rx.recv() => {
                    let container = match container {
                        Ok(container) => container,
                        Err(_) => panic!("Could not receive in connection manager"),
                    };
                    let (ref host, port) = **container.lock().unwrap();
                    let mut insert = false;
                    let conn_tx = conn_tx.clone();
                    let new_tx = new_tx.clone();
                    {
                        let ac = &bcs.read().unwrap().active_connections;
                        match ac.get(&(host.clone(), port)) {
                            Some(conn) => {
                                thread::scoped(move || {
                                    let mut real_conn = conn.lock().unwrap();
                                    while true {
                                        match real_conn.reconnect() {
                                            Ok(_) => break,
                                            Err(_) => {
                                                /* log warning about reconnecting */
                                                thread::sleep_ms(1000);
                                            },
                                        }
                                    };
                                    conn_tx.send(conn.clone());
                                });
                            },
                            None => {
                                thread::scoped(move || {
                                    let conn: Arc<Mutex<Box<Connection>>> = Arc::new(Mutex::new(Box::new(Connection::new(&host, port)))).clone();
                                    {
                                        let mut real_conn = conn.lock().unwrap();
                                        while true {
                                            match real_conn.connect() {
                                                Ok(_) => break,
                                                Err(_) => {
                                                    /* log warning */
                                                    thread::sleep_ms(1000);
                                                }
                                            }
                                        };
                                    }
                                    new_tx.send(conn.clone());
                                });
                            }
                        };
                    } // unlock bcs
                },
                conn = new_rx.recv() => {
                    let conn = match conn {
                        Ok(conn) => conn,
                        Err(_) => panic!("Could not receive in connection manager"),
                    };
                    {
                        let ref real_conn = **conn.lock().unwrap();
                        let host = real_conn.host.clone();
                        {
                            let ac = &mut bcs.write().unwrap().active_connections;
                            ac.insert((host, real_conn.port), conn.clone());
                        }
                    }
                    conn_tx.send(conn.clone());
                },
                _ = stop_rx.recv() => { break }
            )
        }
        for (_, conn) in bcs.read().unwrap().active_connections.iter() {
            let mut conn = conn.lock().unwrap();
            conn.disconnect();
        }
    }

    fn addServer(&self, host: String, port: u16, host_tx: Sender<Arc<Mutex<Box<(String, u16)>>>>) {
        host_tx.send(Arc::new(Mutex::new(Box::new((host, port)))));
    }

    fn pollingManager(bcs: Arc<RwLock<BaseClientServer>>,
                      stop_rx: Receiver<()>,
                      host_tx: Sender<Arc<Mutex<Box<(String, u16)>>>>,
                      conn_rx: Receiver<Arc<Mutex<Box<Connection>>>>) {
        let mut threads: Vec<JoinHandle<()>> = Vec::new();
        while bcs.read().unwrap().running {
            let conn: Result<Arc<Mutex<Box<Connection>>>, RecvError>;
            select!(
                conn = conn_rx.recv() => {
                    let conn = conn.unwrap();
                    let host_tx = host_tx.clone();
                    // poll this conn
                    threads.push(thread::spawn(move || {
                        while true {
                            let mut conn = conn.lock().unwrap();
                            match conn.readPacket() {
                                Ok(p) => { /* handle packet */ },
                                Err(e) => {
                                    /* Log failure */
                                    host_tx.send(Arc::new(Mutex::new(Box::new((conn.host.clone(), conn.port)))));
                                    break;
                                }
                            }
                        }
                    }));
                },
                _ = stop_rx.recv() => { break }
            );
        };
        // 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>use std::mem;
use na::{self, Cross, Dot, zero, Norm, clamp};

use ::{Vector, Point2f};
use colour::Colourf;
use intersection::Intersection;
use interaction::SurfaceInteraction;

bitflags! {
    pub flags BxDFType: u32 {
        const REFLECTION   = 0b_0000_0001,
        const TRANSMISSION = 0b_0000_0010,
        const DIFFUSE      = 0b_0000_0100,
        const GLOSSY       = 0b_0000_1000,
        const SPECULAR     = 0b_0001_0000,
    }
}

/// Represents the Bidirectional Scattering Distribution Function.
/// It represents the properties of a material at a given point.
#[derive(Copy, Clone, Debug)]
pub struct BSDF {
    /// Index of refraction of the surface
    eta: f32,
    /// Shading normal (i.e. potentially affected by bump-mapping)
    ns: Vector,
    /// Geometry normal
    ng: Vector,
    ss: Vector,
    ts: Vector, // bxdfs: BxDFType,
}

impl BSDF {
    pub fn new(isect: &Intersection, eta: f32) -> Self {
        let n = isect.dg.nhit;
        let ss = isect.dg.dpdu.normalize();
        BSDF {
            eta: eta,
            ns: n,
            ng: n,
            ss: ss,
            ts: n.cross(&ss),
        }
    }

    pub fn new2(isect: &SurfaceInteraction, eta: f32) -> Self {
        let ss = isect.dpdu.normalize();
        BSDF {
            eta: eta,
            ns: isect.shading.n,
            ng: isect.n,
            ss: ss,
            ts: isect.shading.n.cross(&ss),
        }
    }

    /// Evaluate the BSDF for the given incoming light direction and outgoing light direction.
    pub fn f(&self, _wi_w: &Vector, _wo_w: &Vector) -> Colourf {
        Colourf::black()
    }

    pub fn sample_f(&self,
                    wo_w: &Vector,
                    sample: (f32, f32),
                    flags: BxDFType)
                    -> (Colourf, Vector, f32) {
        if !flags.contains(SPECULAR) {
            unimplemented!();
        }

        if flags.contains(REFLECTION) {
            let wo = self.world_to_local(&wo_w);
            let wi = Vector::new(-wo.x, -wo.y, wo.z);
            let cos_theta_i = wi.z;
            let kr = fr_dielectric(cos_theta_i, 1.0, self.eta);
            let colour = Colourf::rgb(1.0, 1.0, 1.0) * kr / cos_theta_i.abs();

            assert!(!colour.has_nan());
            return (colour, self.local_to_world(&wi), 1.0);
        } else if flags.contains(TRANSMISSION) {
            let wo = self.world_to_local(&wo_w);
            let entering = wo.z > 0.0;
            let (eta_i, eta_t) = if entering {
                (1.0, self.eta)
            } else {
                (self.eta, 1.0)
            };
            let n = if wo.z < 0.0 {
                -Vector::z()
            } else {
                Vector::z()
            };
            return refract(&wo, &n, eta_i / eta_t)
                .map(|wi| {
                    let cos_theta_i = wi.z;
                    let kr = fr_dielectric(cos_theta_i, 1.0, self.eta);
                    let colour = Colourf::rgb(1.0, 1.0, 1.0) * (1.0 - kr) / cos_theta_i.abs();

                    assert!(!colour.has_nan());
                    (colour, self.local_to_world(&wi), 1.0)
                })
                .unwrap_or((Colourf::black(), zero(), 0.0));
        }

        (Colourf::black(), zero(), 0.0)
    }

    fn world_to_local(&self, v: &Vector) -> Vector {
        Vector::new(v.dot(&self.ss), v.dot(&self.ts), v.dot(&self.ns))
    }

    fn local_to_world(&self, v: &Vector) -> Vector {
        Vector::new(self.ss.x * v.x + self.ts.x * v.y + self.ns.x * v.z,
                    self.ss.y * v.x + self.ts.y * v.y + self.ns.y * v.z,
                    self.ss.z * v.z + self.ts.z * v.y + self.ns.z * v.z)
    }
}

// Common geometric functions
#[inline]
fn cos_theta(w: &Vector) -> f32 {
    w.z
}

#[inline]
fn cos2_theta(w: &Vector) -> f32 {
    w.z * w.z
}

#[inline]
fn abs_cos_theta(w: &Vector) -> f32 {
    w.z.abs()
}

#[inline]
fn sin2_theta(w: &Vector) -> f32 {
    (1.0 - cos2_theta(w)).max(0.0)
}

#[inline]
fn sin_theta(w: &Vector) -> f32 {
    sin2_theta(w).sqrt()
}

#[inline]
fn tan_theta(w: &Vector) -> f32 {
    sin_theta(w) / cos_theta(w)
}

#[inline]
fn tan2_theta(w: &Vector) -> f32 {
    sin2_theta(w) / cos2_theta(w)
}

#[inline]
fn cos_phi(w: &Vector) -> f32 {
    let sin_theta = sin_theta(w);
    if sin_theta == 0.0 {
        0.0
    } else {
        na::clamp(w.x / sin_theta, -1.0, 1.0)
    }
}

#[inline]
fn sin_phi(w: &Vector) -> f32 {
    let sin_theta = sin_theta(w);
    if sin_theta == 0.0 {
        0.0
    } else {
        na::clamp(w.y / sin_theta, -1.0, 1.0)
    }
}

#[inline]
fn cos2_phi(w: &Vector) -> f32 {
    cos_phi(w) / cos_phi(w)
}

#[inline]
fn sin2_phi(w: &Vector) -> f32 {
    sin_phi(w) / sin_phi(w)
}

#[inline]
fn cos_d_phi(wa: &Vector, wb: &Vector) -> f32 {
    na::clamp((wa.x * wb.x + wa.y * wa.y) /
              ((wa.x * wa.x + wa.y * wa.y) * (wb.x * wb.x + wb.y * wb.y)).sqrt(),
              -1.0,
              1.0)
}

trait BxDF {
    fn f(&self, wo: &Vector, wi: &Vector) -> Colourf;
    fn sample_f(&self, wo: &Vector, sample: &Point2f) -> (Vector, f32, BxDFType, Colourf);
    fn rho(&self, wo: &Vector, n_samples: u32) -> (Point2f, Colourf);
    fn rho_hh(&self, n_samples: u32) -> (Point2f, Point2f, Colourf);
    fn matches(&self, flags: BxDFType) -> bool;
}

struct ScaledBxDF {
    bxdf: Box<BxDF>,
    scale: Colourf,
}

impl ScaledBxDF {
    fn new(bxdf: Box<BxDF>, scale: Colourf) -> ScaledBxDF {
        ScaledBxDF {
            bxdf: bxdf,
            scale: scale,
        }
    }
}

impl BxDF for ScaledBxDF {
    fn f(&self, wo: &Vector, wi: &Vector) -> Colourf {
        self.bxdf.f(wo, wi) * self.scale
    }
    fn sample_f(&self, wo: &Vector, sample: &Point2f) -> (Vector, f32, BxDFType, Colourf) {
        let (wi, pdf, bxdftype, spectrum) = self.bxdf.sample_f(wo, sample);
        (wi, pdf, bxdftype, spectrum * self.scale)
    }
    fn rho(&self, wo: &Vector, n_samples: u32) -> (Point2f, Colourf) {
        let (sample, spectrum) = self.bxdf.rho(wo, n_samples);
        (sample, spectrum * self.scale)
    }
    fn rho_hh(&self, n_samples: u32) -> (Point2f, Point2f, Colourf) {
        let (sample1, sample2, spectrum) = self.bxdf.rho_hh(n_samples);
        (sample1, sample2, spectrum * self.scale)
    }
    fn matches(&self, flags: BxDFType) -> bool {
        self.bxdf.matches(flags)
    }
}

/// Compute the reflection direction
fn reflect(wo: &Vector, n: &Vector) -> Vector {
    (-(*wo) + *n * 2.0 * wo.dot(n)).normalize()
}

/// Compute the refraction direction
fn refract(i: &Vector, n: &Vector, eta: f32) -> Option<Vector> {
    let cos_theta_i = n.dot(i);
    let sin2theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0);
    let sin2theta_t = eta * eta * sin2theta_i;

    if sin2theta_t >= 1.0 {
        None
    } else {
        let cos_theta_t = (1.0 - sin2theta_t).sqrt();
        Some(eta * -*i + (eta * cos_theta_i - cos_theta_t) * *n)
    }
}

/// Compute the Fresnel coefficient for dielectric materials
fn fr_dielectric(cos_theta_i: f32, eta_i: f32, eta_t: f32) -> f32 {
    let mut cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let (mut eta_i, mut eta_t) = (eta_i, eta_t);
    if cos_theta_i <= 0.0 {
        // If leaving the surface, swap the indices of refraction
        mem::swap(&mut eta_i, &mut eta_t);
        cos_theta_i = cos_theta_i.abs();
    }

    let sin_theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0).sqrt();
    let sin_theta_t = eta_i / eta_t * sin_theta_i;
    if sin_theta_t >= 1.0 {
        // Total internal reflection
        1.0
    } else {
        let cos_theta_t = (1.0 - sin_theta_t * sin_theta_t).max(0.0).sqrt();
        // Reflectance for parallel polarized light
        let r_parl = ((eta_t * cos_theta_i) - (eta_i * cos_theta_t)) /
                     ((eta_t * cos_theta_i) + (eta_i * cos_theta_t));
        // Reflectance for perpendicular polarized light
        let r_perp = ((eta_i * cos_theta_i) - (eta_t * cos_theta_t)) /
                     ((eta_i * cos_theta_i) + (eta_t * cos_theta_t));
        // Total reflectance for unpolarized light
        0.5 * (r_parl * r_parl + r_perp * r_perp)
    }
}

fn fr_conductor(cos_theta_i: f32, eta_i: &Colourf, eta_t: &Colourf, k: &Colourf) -> Colourf {
    let mut cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let eta = *eta_t / *eta_i;
    let eta_k = *k / *eta_i;

    let cos2_theta_i = cos_theta_i * cos_theta_i;
    let sin2_theta_i = 1.0 - cos2_theta_i;
    let eta2 = eta * eta;
    let eta_k2 = eta_k * eta_k;

    let t0 = eta2 - eta_k2 - sin2_theta_i;
    let a2plusb2 = (t0 * t0 + 4.0 * eta2 * eta_k2).sqrt();
    let t1 = a2plusb2 + cos2_theta_i;
    let a = (0.5 * (a2plusb2 + t0)).sqrt();
    let t2 = 2.0 * cos_theta_i * a;
    let r_s = (t1 - t2) / (t1 + t2);

    let t3 = cos2_theta_i * a2plusb2 + sin2_theta_i * sin2_theta_i;
    let t4 = t2 * sin2_theta_i;
    let r_p = r_s * (t3 - t4) / (t3 + t4);

    0.5 * (r_p + r_s)
}
<commit_msg>Add Fresnel trait + impls for Conductor and Dielectric<commit_after>use std::mem;
use na::{self, Cross, Dot, zero, Norm, clamp};

use ::{Vector, Point2f};
use colour::Colourf;
use intersection::Intersection;
use interaction::SurfaceInteraction;

bitflags! {
    pub flags BxDFType: u32 {
        const REFLECTION   = 0b_0000_0001,
        const TRANSMISSION = 0b_0000_0010,
        const DIFFUSE      = 0b_0000_0100,
        const GLOSSY       = 0b_0000_1000,
        const SPECULAR     = 0b_0001_0000,
    }
}

/// Represents the Bidirectional Scattering Distribution Function.
/// It represents the properties of a material at a given point.
#[derive(Copy, Clone, Debug)]
pub struct BSDF {
    /// Index of refraction of the surface
    eta: f32,
    /// Shading normal (i.e. potentially affected by bump-mapping)
    ns: Vector,
    /// Geometry normal
    ng: Vector,
    ss: Vector,
    ts: Vector, // bxdfs: BxDFType,
}

impl BSDF {
    pub fn new(isect: &Intersection, eta: f32) -> Self {
        let n = isect.dg.nhit;
        let ss = isect.dg.dpdu.normalize();
        BSDF {
            eta: eta,
            ns: n,
            ng: n,
            ss: ss,
            ts: n.cross(&ss),
        }
    }

    pub fn new2(isect: &SurfaceInteraction, eta: f32) -> Self {
        let ss = isect.dpdu.normalize();
        BSDF {
            eta: eta,
            ns: isect.shading.n,
            ng: isect.n,
            ss: ss,
            ts: isect.shading.n.cross(&ss),
        }
    }

    /// Evaluate the BSDF for the given incoming light direction and outgoing light direction.
    pub fn f(&self, _wi_w: &Vector, _wo_w: &Vector) -> Colourf {
        Colourf::black()
    }

    pub fn sample_f(&self,
                    wo_w: &Vector,
                    sample: (f32, f32),
                    flags: BxDFType)
                    -> (Colourf, Vector, f32) {
        if !flags.contains(SPECULAR) {
            unimplemented!();
        }

        if flags.contains(REFLECTION) {
            let wo = self.world_to_local(&wo_w);
            let wi = Vector::new(-wo.x, -wo.y, wo.z);
            let cos_theta_i = wi.z;
            let kr = fr_dielectric(cos_theta_i, 1.0, self.eta);
            let colour = Colourf::rgb(1.0, 1.0, 1.0) * kr / cos_theta_i.abs();

            assert!(!colour.has_nan());
            return (colour, self.local_to_world(&wi), 1.0);
        } else if flags.contains(TRANSMISSION) {
            let wo = self.world_to_local(&wo_w);
            let entering = wo.z > 0.0;
            let (eta_i, eta_t) = if entering {
                (1.0, self.eta)
            } else {
                (self.eta, 1.0)
            };
            let n = if wo.z < 0.0 {
                -Vector::z()
            } else {
                Vector::z()
            };
            return refract(&wo, &n, eta_i / eta_t)
                .map(|wi| {
                    let cos_theta_i = wi.z;
                    let kr = fr_dielectric(cos_theta_i, 1.0, self.eta);
                    let colour = Colourf::rgb(1.0, 1.0, 1.0) * (1.0 - kr) / cos_theta_i.abs();

                    assert!(!colour.has_nan());
                    (colour, self.local_to_world(&wi), 1.0)
                })
                .unwrap_or((Colourf::black(), zero(), 0.0));
        }

        (Colourf::black(), zero(), 0.0)
    }

    fn world_to_local(&self, v: &Vector) -> Vector {
        Vector::new(v.dot(&self.ss), v.dot(&self.ts), v.dot(&self.ns))
    }

    fn local_to_world(&self, v: &Vector) -> Vector {
        Vector::new(self.ss.x * v.x + self.ts.x * v.y + self.ns.x * v.z,
                    self.ss.y * v.x + self.ts.y * v.y + self.ns.y * v.z,
                    self.ss.z * v.z + self.ts.z * v.y + self.ns.z * v.z)
    }
}

// Common geometric functions
#[inline]
fn cos_theta(w: &Vector) -> f32 {
    w.z
}

#[inline]
fn cos2_theta(w: &Vector) -> f32 {
    w.z * w.z
}

#[inline]
fn abs_cos_theta(w: &Vector) -> f32 {
    w.z.abs()
}

#[inline]
fn sin2_theta(w: &Vector) -> f32 {
    (1.0 - cos2_theta(w)).max(0.0)
}

#[inline]
fn sin_theta(w: &Vector) -> f32 {
    sin2_theta(w).sqrt()
}

#[inline]
fn tan_theta(w: &Vector) -> f32 {
    sin_theta(w) / cos_theta(w)
}

#[inline]
fn tan2_theta(w: &Vector) -> f32 {
    sin2_theta(w) / cos2_theta(w)
}

#[inline]
fn cos_phi(w: &Vector) -> f32 {
    let sin_theta = sin_theta(w);
    if sin_theta == 0.0 {
        0.0
    } else {
        na::clamp(w.x / sin_theta, -1.0, 1.0)
    }
}

#[inline]
fn sin_phi(w: &Vector) -> f32 {
    let sin_theta = sin_theta(w);
    if sin_theta == 0.0 {
        0.0
    } else {
        na::clamp(w.y / sin_theta, -1.0, 1.0)
    }
}

#[inline]
fn cos2_phi(w: &Vector) -> f32 {
    cos_phi(w) / cos_phi(w)
}

#[inline]
fn sin2_phi(w: &Vector) -> f32 {
    sin_phi(w) / sin_phi(w)
}

#[inline]
fn cos_d_phi(wa: &Vector, wb: &Vector) -> f32 {
    na::clamp((wa.x * wb.x + wa.y * wa.y) /
              ((wa.x * wa.x + wa.y * wa.y) * (wb.x * wb.x + wb.y * wb.y)).sqrt(),
              -1.0,
              1.0)
}

trait BxDF {
    fn f(&self, wo: &Vector, wi: &Vector) -> Colourf;
    fn sample_f(&self, wo: &Vector, sample: &Point2f) -> (Vector, f32, BxDFType, Colourf);
    fn rho(&self, wo: &Vector, n_samples: u32) -> (Point2f, Colourf);
    fn rho_hh(&self, n_samples: u32) -> (Point2f, Point2f, Colourf);
    fn matches(&self, flags: BxDFType) -> bool;
}

struct ScaledBxDF {
    bxdf: Box<BxDF>,
    scale: Colourf,
}

impl ScaledBxDF {
    fn new(bxdf: Box<BxDF>, scale: Colourf) -> ScaledBxDF {
        ScaledBxDF {
            bxdf: bxdf,
            scale: scale,
        }
    }
}

impl BxDF for ScaledBxDF {
    fn f(&self, wo: &Vector, wi: &Vector) -> Colourf {
        self.bxdf.f(wo, wi) * self.scale
    }
    fn sample_f(&self, wo: &Vector, sample: &Point2f) -> (Vector, f32, BxDFType, Colourf) {
        let (wi, pdf, bxdftype, spectrum) = self.bxdf.sample_f(wo, sample);
        (wi, pdf, bxdftype, spectrum * self.scale)
    }
    fn rho(&self, wo: &Vector, n_samples: u32) -> (Point2f, Colourf) {
        let (sample, spectrum) = self.bxdf.rho(wo, n_samples);
        (sample, spectrum * self.scale)
    }
    fn rho_hh(&self, n_samples: u32) -> (Point2f, Point2f, Colourf) {
        let (sample1, sample2, spectrum) = self.bxdf.rho_hh(n_samples);
        (sample1, sample2, spectrum * self.scale)
    }
    fn matches(&self, flags: BxDFType) -> bool {
        self.bxdf.matches(flags)
    }
}

/// Compute the reflection direction
fn reflect(wo: &Vector, n: &Vector) -> Vector {
    (-(*wo) + *n * 2.0 * wo.dot(n)).normalize()
}

/// Compute the refraction direction
fn refract(i: &Vector, n: &Vector, eta: f32) -> Option<Vector> {
    let cos_theta_i = n.dot(i);
    let sin2theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0);
    let sin2theta_t = eta * eta * sin2theta_i;

    if sin2theta_t >= 1.0 {
        None
    } else {
        let cos_theta_t = (1.0 - sin2theta_t).sqrt();
        Some(eta * -*i + (eta * cos_theta_i - cos_theta_t) * *n)
    }
}

/// Compute the Fresnel coefficient for dielectric materials
fn fr_dielectric(cos_theta_i: f32, eta_i: f32, eta_t: f32) -> f32 {
    let mut cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let (mut eta_i, mut eta_t) = (eta_i, eta_t);
    if cos_theta_i <= 0.0 {
        // If leaving the surface, swap the indices of refraction
        mem::swap(&mut eta_i, &mut eta_t);
        cos_theta_i = cos_theta_i.abs();
    }

    let sin_theta_i = (1.0 - cos_theta_i * cos_theta_i).max(0.0).sqrt();
    let sin_theta_t = eta_i / eta_t * sin_theta_i;
    if sin_theta_t >= 1.0 {
        // Total internal reflection
        1.0
    } else {
        let cos_theta_t = (1.0 - sin_theta_t * sin_theta_t).max(0.0).sqrt();
        // Reflectance for parallel polarized light
        let r_parl = ((eta_t * cos_theta_i) - (eta_i * cos_theta_t)) /
                     ((eta_t * cos_theta_i) + (eta_i * cos_theta_t));
        // Reflectance for perpendicular polarized light
        let r_perp = ((eta_i * cos_theta_i) - (eta_t * cos_theta_t)) /
                     ((eta_i * cos_theta_i) + (eta_t * cos_theta_t));
        // Total reflectance for unpolarized light
        0.5 * (r_parl * r_parl + r_perp * r_perp)
    }
}

fn fr_conductor(cos_theta_i: f32, eta_i: &Colourf, eta_t: &Colourf, k: &Colourf) -> Colourf {
    let mut cos_theta_i = clamp(cos_theta_i, -1.0, 1.0);
    let eta = *eta_t / *eta_i;
    let eta_k = *k / *eta_i;

    let cos2_theta_i = cos_theta_i * cos_theta_i;
    let sin2_theta_i = 1.0 - cos2_theta_i;
    let eta2 = eta * eta;
    let eta_k2 = eta_k * eta_k;

    let t0 = eta2 - eta_k2 - sin2_theta_i;
    let a2plusb2 = (t0 * t0 + 4.0 * eta2 * eta_k2).sqrt();
    let t1 = a2plusb2 + cos2_theta_i;
    let a = (0.5 * (a2plusb2 + t0)).sqrt();
    let t2 = 2.0 * cos_theta_i * a;
    let r_s = (t1 - t2) / (t1 + t2);

    let t3 = cos2_theta_i * a2plusb2 + sin2_theta_i * sin2_theta_i;
    let t4 = t2 * sin2_theta_i;
    let r_p = r_s * (t3 - t4) / (t3 + t4);

    0.5 * (r_p + r_s)
}

/// Trait for Fresnel materials
trait Fresnel {
    fn evaluate(&self, cos_theta_i: f32) -> Colourf;
}

/// Fresnel for conductor materials
struct FresnelConductor {
    eta_i: Colourf,
    eta_t: Colourf,
    k: Colourf,
}

impl Fresnel for FresnelConductor {
    fn evaluate(&self, cos_theta_i: f32) -> Colourf {
        fr_conductor(cos_theta_i.abs(), &self.eta_i, &self.eta_t, &self.k)
    }
}

/// Fresnel for dielectric materials
struct FresnelDielectric {
    eta_i: f32,
    eta_t: f32,
}

impl Fresnel for FresnelDielectric {
    fn evaluate(&self, cos_theta_i: f32) -> Colourf {
        Colourf::grey(fr_dielectric(cos_theta_i.abs(), self.eta_i, self.eta_t))
    }
}
<|endoftext|>


<commit_before>#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

use url::Url;
use std::io;
use std::io::{Buffer, Reader, Writer, IoResult, BufferedStream, standard_error};
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::get_host_addresses;
use std::fmt::{Show, Formatter, FormatError};
use std::collections::TreeMap;
use serialize::json;
use serialize::json::{Json, ToJson};
use openssl::ssl;
use openssl::ssl::{SslStream, SslContext};

enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>)
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut s) => s.read(buf),
            SslProtectedStream(ref mut s) => s.read(buf)
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.write(buf),
            SslProtectedStream(ref mut s) => s.write(buf)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.flush(),
            SslProtectedStream(ref mut s) => s.flush()
        }
    }
}

static WEBSOCKET_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

bitflags! {
    #[deriving(Show)] flags WSHeader: u16 {
        static WS_FIN     = 0b1000000000000000,
        static WS_OPCODE  = 0b0000111100000000,
        static WS_MASK    = 0b0000000010000000,
        static WS_LEN     = 0b0000000001111111,

        static WS_LEN16   = 0b0000000001111110,
        static WS_LEN64   = 0b0000000001111111,

        static WS_OPCONT  = 0b0000000000000000,
        static WS_OPTEXT  = 0b0000000100000000,
        static WS_OPBIN   = 0b0000001000000000,
        static WS_OPTERM  = 0b0000100000000000,
        static WS_OPPING  = 0b0000100100000000,
        static WS_OPPONG  = 0b0000101000000000,
    }
}

#[allow(visible_private_types)]
#[allow(dead_code)]
pub struct WebSocket<S = NetworkStream> {
    stream: Option<BufferedStream<S>>,
    handshake_finished: bool,
    pub remote_addr: Option<SocketAddr>,
    pub url: Url,
    use_ssl: bool,
}

#[allow(dead_code)]
impl WebSocket {
    fn new(url: Url) -> IoResult<WebSocket> {
        let addr = match try!(url.domain()
            .map(|h| get_host_addresses(h)
                 .map(|v| v.move_iter().find(|&a| {
                     match a {
                         Ipv4Addr(..) => true,
                         _ => false
                     }
                 })))
            .unwrap_or(Err(standard_error(io::InvalidInput)))) {
                Some(a) => a,
                None => return Err(standard_error(io::FileNotFound))
            };

        let use_ssl = url.scheme.as_slice() == "wss";

        let port = match url.port() {
            Some(p) => p,
            None if use_ssl => 443,
            _ => 80
        };

        Ok(WebSocket {
            stream: None,
            handshake_finished: false,
            remote_addr: Some(SocketAddr{ ip: addr, port: port }),
            url: url,
            use_ssl: use_ssl
        })
    }

    fn connect(&mut self) -> IoResult<()> {
        let s = try!(self.remote_addr.map(|ref a| TcpStream::connect(format!("{}", a.ip).as_slice(), a.port)).unwrap_or_else(|| Err(standard_error(io::InvalidInput))));
        self.stream = Some(BufferedStream::new(
            if self.use_ssl {
                SslProtectedStream(try!(SslStream::new(&try!(SslContext::new(ssl::Sslv23).map_err(|e| standard_error(io::OtherIoError))), s)
                                        .map_err(|e| standard_error(io::OtherIoError))))
            } else {
                NormalStream(s)
            }));
        Ok(())
    }

    fn send_headers(&mut self) -> IoResult<()> {
        let mut s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        try!(s.write(format!("GET {} HTTP/1.1\r\n", self.url.serialize_path().unwrap_or("/".to_string())).as_bytes()));
        try!(s.write(format!("Host: {}\r\n", self.url.host().unwrap()).as_bytes()));
        try!(s.write("Upgrade: websocket\r\n".as_bytes()));
        try!(s.write("Connection: Upgrade\r\n".as_bytes()));
        try!(s.write(format!("Origin: {}\r\n", self.url.serialize_no_fragment()).as_bytes()));
        try!(s.write("Sec-WebSocket-Protocol: char, superchat\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Version: 13\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Key: {}\r\n".as_bytes()));
        try!(s.write("\r\n".as_bytes()));
        s.flush()
    }

    fn read_response(&mut self) -> IoResult<()> {
        let spaces: &[_] = &[' ', '\t', '\r', '\n'];
        let mut s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        let status = try!(s.read_line()).as_slice().splitn(2, ' ').nth(1).and_then(|s| from_str::<uint>(s));

        match status {
            Some(101) => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        println!("status: {}", status);
        let headers = s.lines().map(|r| r.unwrap_or("\r\n".to_string())) .take_while(|l| l.as_slice() != "\r\n")
            .map(|s| s.as_slice().splitn(1, ':').map(|s| s.trim_chars(spaces).to_string()).collect::<Vec<String>>())
            .map(|p| (p[0].to_string(), p[1].to_string()))
            .collect::<TreeMap<String, String>>();

        try!(s.flush());

        println!("headers: {}", headers);

        if WebSocket::check_nonce("{}", headers.find(&"Sec-WebSocket-Accept".to_string()).unwrap_or(&"".to_string()).as_slice()) {
            Ok(())
        } else {
            Err(standard_error(io::InvalidInput))
        }
    }

    fn check_nonce(nonce: &str, response: &str) -> bool {
        true
    }

    fn handshake(&mut self) -> IoResult<()> {
        try!(self.connect());
        try!(self.send_headers());
        try!(self.read_response());

        self.handshake_finished = true;
        Ok(())
    }

    fn read_header(&mut self) -> IoResult<WSHeader> {
        // XXX: this is a bug, WSHeader should accept u16
        Ok(WSHeader { bits: try!(self.read_be_u16()) as u32 })
    }

    fn read_length(&mut self, header: &WSHeader) -> IoResult<uint> {
        let len = header & WS_LEN;
        println!("hlen: {} & {} = {}", header, WS_LEN, len);
        if len == WS_LEN16 {
            println!("u16 len");
            self.read_be_u16().map(|v| v as uint)
        } else if len == WS_LEN64 {
            println!("u64 len");
            self.read_be_u64().map(|v| v as uint)
        } else {
            Ok(len.bits as uint)
        }
    }

    fn read_message(&mut self) -> IoResult<WSMessage> {
        let header = try!(self.read_header());
        let len = try!(self.read_length(&header));
        let mask = if header.contains(WS_MASK) { Some(try!(self.read_be_u32())) } else { None };
        let data = try!(self.read_exact(len));
        // TODO: unmask data
        Ok(WSMessage { header: header, data: data })
    }

    // TODO: send_message(&mut self, &WSMessage) -> IoResult<()>

    fn iter(&mut self) -> WSMessages {
        WSMessages { sock: self }
    }

    fn unmask_data(data: &mut [u8], mask: u32) -> &[u8] {
        data
    }
}

#[deriving(Show)]
struct WSMessage {
    header: WSHeader,
    data: Vec<u8>
}

//impl Show for WSMessage {
    //fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        //f.write_str("WSMessage(");
        //try!(self.header.fmt(f));
        //try!(self.data.fmt(f));
        //f.write_str(")");
        //Ok(())
    //}
//}

impl WSMessage {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data.as_slice()).into_string()
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        from_str::<Json>(self.to_string().as_slice()).unwrap()
    }
}

struct WSMessages<'a> {
    sock: &'a mut WebSocket
}

impl<'a> Iterator<WSMessage> for WSMessages<'a> {
    fn next(&mut self) -> Option<WSMessage> {
        self.sock.read_message().ok()
    }
}

impl Reader for WebSocket {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.stream {
            Some(ref mut s) => s.read(buf),
            None => Err(standard_error(io::NotConnected))
        }
    }
}

impl Buffer for WebSocket {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        match self.stream {
            Some(ref mut s) => s.fill_buf(),
            None => Err(standard_error(io::NotConnected))
        }
    }

    fn consume(&mut self, amt: uint) {
        match self.stream {
            Some(ref mut s) => s.consume(amt),
            None => ()
        }
    }
}

#[bench]
fn test_connect(b: &mut Bencher) {
    let url = Url::parse("wss://stream.pushbullet.com/websocket/").unwrap();
    let mut ws = WebSocket::new(url).unwrap();

    match ws.handshake() {
        Err(e) => fail!("error: {}", e),
        _ => ()
    }
    let msg = ws.read_message().unwrap();
    println!("received: {} {} {}", msg, msg.to_string(), msg.to_json());
    for msg in ws.iter() {
        println!("{}", msg.to_string());
    }
}
<commit_msg>better use of pattern matching + remove debug print<commit_after>#![feature(default_type_params)]

extern crate url;
extern crate openssl;
extern crate serialize;

#[cfg(test)]
extern crate test;

#[cfg(test)]
use test::Bencher;

use url::Url;
use std::io;
use std::io::{Buffer, Reader, Writer, IoResult, BufferedStream, standard_error};
use std::io::net::tcp::TcpStream;
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::get_host_addresses;
use std::fmt::{Show, Formatter, FormatError};
use std::collections::TreeMap;
use serialize::json;
use serialize::json::{Json, ToJson};
use openssl::ssl;
use openssl::ssl::{SslStream, SslContext};

enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>)
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut s) => s.read(buf),
            SslProtectedStream(ref mut s) => s.read(buf)
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.write(buf),
            SslProtectedStream(ref mut s) => s.write(buf)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut s) => s.flush(),
            SslProtectedStream(ref mut s) => s.flush()
        }
    }
}

static WEBSOCKET_GUID: &'static str = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

bitflags! {
    #[deriving(Show)] flags WSHeader: u16 {
        static WS_FIN     = 0b1000000000000000,
        static WS_OPCODE  = 0b0000111100000000,
        static WS_MASK    = 0b0000000010000000,
        static WS_LEN     = 0b0000000001111111,

        static WS_LEN16   = 0b0000000001111110,
        static WS_LEN64   = 0b0000000001111111,

        static WS_OPCONT  = 0b0000000000000000,
        static WS_OPTEXT  = 0b0000000100000000,
        static WS_OPBIN   = 0b0000001000000000,
        static WS_OPTERM  = 0b0000100000000000,
        static WS_OPPING  = 0b0000100100000000,
        static WS_OPPONG  = 0b0000101000000000,
    }
}

#[allow(visible_private_types)]
#[allow(dead_code)]
pub struct WebSocket<S = NetworkStream> {
    stream: Option<BufferedStream<S>>,
    handshake_finished: bool,
    pub remote_addr: Option<SocketAddr>,
    pub url: Url,
    use_ssl: bool,
}

#[allow(dead_code)]
impl WebSocket {
    fn new(url: Url) -> IoResult<WebSocket> {
        let addr = match try!(url.domain()
            .map(|h| get_host_addresses(h)
                 .map(|v| v.move_iter().find(|&a| {
                     match a {
                         Ipv4Addr(..) => true,
                         _ => false
                     }
                 })))
            .unwrap_or(Err(standard_error(io::InvalidInput)))) {
                Some(a) => a,
                None => return Err(standard_error(io::FileNotFound))
            };

        let use_ssl = url.scheme.as_slice() == "wss";

        let port = match url.port() {
            Some(p) => p,
            None if use_ssl => 443,
            _ => 80
        };

        Ok(WebSocket {
            stream: None,
            handshake_finished: false,
            remote_addr: Some(SocketAddr{ ip: addr, port: port }),
            url: url,
            use_ssl: use_ssl
        })
    }

    fn connect(&mut self) -> IoResult<()> {
        let s = try!(self.remote_addr.map(|ref a| TcpStream::connect(format!("{}", a.ip).as_slice(), a.port)).unwrap_or_else(|| Err(standard_error(io::InvalidInput))));
        self.stream = Some(BufferedStream::new(
            if self.use_ssl {
                SslProtectedStream(try!(SslStream::new(&try!(SslContext::new(ssl::Sslv23).map_err(|e| standard_error(io::OtherIoError))), s)
                                        .map_err(|e| standard_error(io::OtherIoError))))
            } else {
                NormalStream(s)
            }));
        Ok(())
    }

    fn send_headers(&mut self) -> IoResult<()> {
        let mut s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        try!(s.write(format!("GET {} HTTP/1.1\r\n", self.url.serialize_path().unwrap_or("/".to_string())).as_bytes()));
        try!(s.write(format!("Host: {}\r\n", self.url.host().unwrap()).as_bytes()));
        try!(s.write("Upgrade: websocket\r\n".as_bytes()));
        try!(s.write("Connection: Upgrade\r\n".as_bytes()));
        try!(s.write(format!("Origin: {}\r\n", self.url.serialize_no_fragment()).as_bytes()));
        try!(s.write("Sec-WebSocket-Protocol: char, superchat\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Version: 13\r\n".as_bytes()));
        try!(s.write("Sec-WebSocket-Key: {}\r\n".as_bytes()));
        try!(s.write("\r\n".as_bytes()));
        s.flush()
    }

    fn read_response(&mut self) -> IoResult<()> {
        let spaces: &[_] = &[' ', '\t', '\r', '\n'];
        let mut s = match self.stream { Some(ref mut s) => s, None => return Err(standard_error(io::NotConnected)) };
        let status = try!(s.read_line()).as_slice().splitn(2, ' ').nth(1).and_then(|s| from_str::<uint>(s));

        match status {
            Some(101) => (),
            _ => return Err(standard_error(io::InvalidInput))
        }

        let headers = s.lines().map(|r| r.unwrap_or("\r\n".to_string())) .take_while(|l| l.as_slice() != "\r\n")
            .map(|s| s.as_slice().splitn(1, ':').map(|s| s.trim_chars(spaces).to_string()).collect::<Vec<String>>())
            .map(|p| (p[0].to_string(), p[1].to_string()))
            .collect::<TreeMap<String, String>>();

        try!(s.flush());

        if WebSocket::check_nonce("{}", headers.find(&"Sec-WebSocket-Accept".to_string()).unwrap_or(&"".to_string()).as_slice()) {
            Ok(())
        } else {
            Err(standard_error(io::InvalidInput))
        }
    }

    fn check_nonce(nonce: &str, response: &str) -> bool {
        true
    }

    fn handshake(&mut self) -> IoResult<()> {
        try!(self.connect());
        try!(self.send_headers());
        try!(self.read_response());

        self.handshake_finished = true;
        Ok(())
    }

    fn read_header(&mut self) -> IoResult<WSHeader> {
        // XXX: this is a bug, WSHeader should accept u16
        Ok(WSHeader { bits: try!(self.read_be_u16()) as u32 })
    }

    fn read_length(&mut self, header: &WSHeader) -> IoResult<uint> {
        let len = header & WS_LEN;

        match header & WS_LEN {
            WS_LEN16 => self.read_be_u16().map(|v| v as uint),
            WS_LEN64 => self.read_be_u64().map(|v| v as uint),
            len => Ok(len.bits as uint)
        }
    }

    fn read_message(&mut self) -> IoResult<WSMessage> {
        let header = try!(self.read_header());
        let len = try!(self.read_length(&header));
        let mask = if header.contains(WS_MASK) { Some(try!(self.read_be_u32())) } else { None };
        let data = try!(self.read_exact(len));
        // TODO: unmask data
        Ok(WSMessage { header: header, data: data })
    }

    // TODO: send_message(&mut self, &WSMessage) -> IoResult<()>

    fn iter(&mut self) -> WSMessages {
        WSMessages { sock: self }
    }

    fn unmask_data(data: &mut [u8], mask: u32) -> &[u8] {
        data
    }
}

#[deriving(Show)]
struct WSMessage {
    header: WSHeader,
    data: Vec<u8>
}

impl WSMessage {
    fn to_string(&self) -> String {
        String::from_utf8_lossy(self.data.as_slice()).into_string()
    }
}

impl ToJson for WSMessage {
    fn to_json(&self) -> Json {
        from_str::<Json>(self.to_string().as_slice()).unwrap()
    }
}

struct WSMessages<'a> {
    sock: &'a mut WebSocket
}

impl<'a> Iterator<WSMessage> for WSMessages<'a> {
    fn next(&mut self) -> Option<WSMessage> {
        self.sock.read_message().ok()
    }
}

impl Reader for WebSocket {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match self.stream {
            Some(ref mut s) => s.read(buf),
            None => Err(standard_error(io::NotConnected))
        }
    }
}

impl Buffer for WebSocket {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        match self.stream {
            Some(ref mut s) => s.fill_buf(),
            None => Err(standard_error(io::NotConnected))
        }
    }

    fn consume(&mut self, amt: uint) {
        match self.stream {
            Some(ref mut s) => s.consume(amt),
            None => ()
        }
    }
}

#[bench]
fn test_connect(b: &mut Bencher) {
    let url = Url::parse("wss://stream.pushbullet.com/websocket/").unwrap();
    let mut ws = WebSocket::new(url).unwrap();

    match ws.handshake() {
        Err(e) => fail!("error: {}", e),
        _ => ()
    }
    let msg = ws.read_message().unwrap();
    println!("received: {} {} {}", msg, msg.to_string(), msg.to_json());
    for msg in ws.iter() {
        println!("{}", msg.to_string());
    }
}
<|endoftext|>


<commit_before>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! - [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! - [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are
//! defined in this crate because they cannot be used in [syn] without "full"
//! feature.
//!
//! # Optional features
//!
//! - **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: ItemFn
//! [`syn_mid::Block`]: Block
//! [syn]: https://github.com/dtolnay/syn

#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::pedantic)]
#![allow(clippy::mixed_read_write_in_expression, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod func;
mod pat;
mod path;

pub use crate::{
    func::{Block, FnArg, ItemFn, Receiver, Signature},
    pat::{
        FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
        PatType, PatWild,
    },
};
<commit_msg>Apply some clippy restriction/nursery lints<commit_after>//! Providing the features between "full" and "derive" of syn.
//!
//! This crate provides the following two unique data structures.
//!
//! - [`syn_mid::ItemFn`] -- A function whose body is not parsed.
//!
//!   ```text
//!   fn process(n: usize) -> Result<()> { ... }
//!   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^     ^
//!   ```
//!
//! - [`syn_mid::Block`] -- A block whose body is not parsed.
//!
//!   ```text
//!   { ... }
//!   ^     ^
//!   ```
//!
//! Other data structures are the same as data structures of [syn]. These are
//! defined in this crate because they cannot be used in [syn] without "full"
//! feature.
//!
//! # Optional features
//!
//! - **`clone-impls`** — Clone impls for all syntax tree types.
//!
//! [`syn_mid::ItemFn`]: ItemFn
//! [`syn_mid::Block`]: Block
//! [syn]: https://github.com/dtolnay/syn

#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(
    clippy::pedantic,
    // lints for public library
    clippy::alloc_instead_of_core,
    // clippy::exhaustive_enums, // TODO
    // clippy::exhaustive_structs, // TODO
    clippy::std_instead_of_alloc,
    clippy::std_instead_of_core,
)]
#![allow(clippy::mixed_read_write_in_expression, clippy::large_enum_variant)]

// Many of the code contained in this crate are copies from https://github.com/dtolnay/syn.

#[macro_use]
mod macros;

mod func;
mod pat;
mod path;

pub use crate::{
    func::{Block, FnArg, ItemFn, Receiver, Signature},
    pat::{
        FieldPat, Pat, PatIdent, PatPath, PatReference, PatStruct, PatTuple, PatTupleStruct,
        PatType, PatWild,
    },
};
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_variables, dead_code)]
use super::error::ConfigError;
use anyhow::{anyhow, Result};

use serde::de::{Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::num::ParseIntError;
use std::vec::Vec;
/*
type Tasks = Vec<Task>;
type Params = Vec<Param>;
*/
type Tasks = HashMap<String, Task>;
type Params = HashMap<String, Param>;

#[derive(Debug, Clone, PartialEq)]
pub enum Nargs {
    One,
    Zero,
    OneOrZero,
    OneOrMore,
    ZeroOrMore,
    Range(usize, usize),
}

impl fmt::Display for Nargs {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Nargs::One => write!(fmtr, "Nargs::One[1]"),
            Nargs::Zero => write!(fmtr, "Nargs::Zero[0]"),
            Nargs::OneOrZero => write!(fmtr, "Nargs::OneOrZero[?]"),
            Nargs::OneOrMore => write!(fmtr, "Nargs::OneOrMore[+]"),
            Nargs::ZeroOrMore => write!(fmtr, "Nargs::ZeroOrMore[*]"),
            Nargs::Range(min, max) => write!(fmtr, "Nargs::Range[{}, {}]", min + 1, max),
        }
    }
}

impl Default for Nargs {
    fn default() -> Self {
        Nargs::One
    }
}

impl<'de> Deserialize<'de> for Nargs {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let result = match &s[..] {
            "1" => Nargs::One,
            "0" => Nargs::Zero,
            "?" => Nargs::OneOrZero,
            "+" => Nargs::OneOrMore,
            "*" => Nargs::ZeroOrMore,
            _ => {
                println!("s={}", s);
                if s.contains(':') {
                    let parts: Vec<&str> = s.split(':').collect();
                    let min = parts[0].parse::<usize>().map_err(Error::custom)?;
                    let max = parts[1].parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(min - 1, max)
                } else {
                    let num = s.parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(0, num)
                }
            }
        };
        Ok(result)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Item(String),
    List(Vec<String>),
    Dict(HashMap<String, String>),
    Empty,
}

impl fmt::Display for Value {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Item(s) => write!(fmtr, "Values::Item({})", s),
            Value::List(vs) => write!(fmtr, "Values::List([{}])", vs.join(", ")),
            Value::Dict(ds) => write!(fmtr, "Values::Dict[NOT IMPLEMENTED]"),
            Value::Empty => write!(fmtr, "Value::Empty(\"\")"),
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::Empty
    }
}

fn deserialize_value<'de, D>(deserializer: D) -> Result<Value, D::Error>
where
    D: Deserializer<'de>,
{
    struct ValueEnum;
    impl<'de> Visitor<'de> for ValueEnum {
        type Value = Value;

        fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.write_str("string or list of strings")
        }
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Ok(Value::Item(value.to_owned()))
        }
        fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            let mut vec: Vec<String> = vec![];
            while let Some(item) = visitor.next_element()? {
                vec.push(item);
            }
            Ok(Value::List(vec))
        }
    }
    deserializer.deserialize_any(ValueEnum)
}

fn default_otto() -> String {
    "otto".to_string()
}

fn default_verbosity() -> i32 {
    1
}

fn default_api() -> i32 {
    1
}

fn default_jobs() -> i32 {
    12
}
fn default_defaults() -> Defaults {
    Defaults {
        api: default_api(),
        verbosity: default_verbosity(),
        jobs: default_jobs(),
        tasks: vec![],
    }
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Spec {
    #[serde(default = "default_defaults")]
    pub defaults: Defaults,

    pub otto: Otto,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Defaults {
    #[serde(default = "default_api")]
    pub api: i32,

    #[serde(default = "default_verbosity")]
    pub verbosity: i32,

    #[serde(default = "default_jobs")]
    pub jobs: i32,

    #[serde(default)]
    pub tasks: Vec<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Otto {
    #[serde(skip_deserializing, default = "default_otto")]
    pub name: String,

    #[serde(default)]
    pub author: Option<String>,

    #[serde(default)]
    pub about: Option<String>,

    #[serde(default)]
    pub version: Option<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    #[serde(default, deserialize_with = "deserialize_task_map")]
    pub tasks: Tasks,

    pub action: Option<String>,
}

impl Otto {
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param, ConfigError> {
        self.params
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param, ConfigError> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param, ConfigError> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn get_task(&self, name: &str) -> Result<&Task, ConfigError> {
        self.tasks
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn set_task(&mut self, task: Task) -> Result<Task, ConfigError> {
        let name = task.name.to_owned();
        self.tasks
            .insert(name.to_owned(), task)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn task_names(&self) -> Vec<&str> {
        self.tasks.keys().map(AsRef::as_ref).collect()
    }
}

pub enum ParamType {
    FLG,
    OPT,
    POS,
}

// FIXME: Flag, Named and Positional Args
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Param {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(skip_deserializing)]
    pub flags: Vec<String>,

    #[serde(skip_deserializing)]
    pub value: Value,

    #[serde(default)]
    pub dest: Option<String>,

    #[serde(default)]
    pub metavar: Option<String>,

    #[serde(default)]
    pub default: Option<String>,

    #[serde(default, deserialize_with = "deserialize_value")]
    pub constant: Value,

    #[serde(default)]
    pub choices: Vec<String>,

    #[serde(default)]
    pub nargs: Nargs,

    #[serde(default)]
    pub help: Option<String>,
}

impl Param {
    pub fn param_type(&self) -> ParamType {
        match self.name.chars().next() {
            Some('-') => match self.default.as_deref() {
                Some("true") | Some("false") => ParamType::FLG,
                Some(_) | None => ParamType::OPT,
            },
            Some(_) | None => ParamType::POS,
        }
    }
}

fn deserialize_param_map<'de, D>(deserializer: D) -> Result<Params, D::Error>
where
    D: Deserializer<'de>,
{
    struct ParamMap;

    impl<'de> Visitor<'de> for ParamMap {
        type Value = Params;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Param")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut params = Params::new();
            while let Some((name, mut param)) = map.next_entry::<String, Param>()? {
                param.flags = name.split('|').map(|f| f.to_string()).collect();
                let short: Vec<String> = param
                    .flags
                    .to_owned()
                    .into_iter()
                    .filter(|i| i.starts_with('-') && i.len() == 2)
                    //.map(|i| i.to_string())
                    .collect();
                let long: Vec<String> = param
                    .flags
                    .to_owned()
                    .into_iter()
                    .filter(|i| i.starts_with("--") && i.len() > 2)
                    //.map(|i| i.to_string())
                    .collect();
                if param.dest.is_none() {
                    let dest = match long.first() {
                        Some(long) => String::from(long.trim_matches('-')),
                        None => match short.first() {
                            Some(short) => String::from(short.trim_matches('-')),
                            None => param.name,
                        },
                    };
                    param.dest = Some(dest);
                }
                param.name = name.to_owned();
                params.insert(name.to_owned(), param);
            }
            Ok(params)
        }
    }
    deserializer.deserialize_map(ParamMap)
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Task {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(default)]
    pub help: Option<String>,

    #[serde(default)]
    pub after: Vec<String>,

    #[serde(default)]
    pub before: Vec<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    pub action: Option<String>,

    #[serde(skip_deserializing)]
    pub selected: bool,
}

impl Task {
    pub fn new(
        name: String,
        help: Option<String>,
        after: Vec<String>,
        before: Vec<String>,
        params: Params,
        action: Option<String>,
        selected: bool,
    ) -> Self {
        Self {
            name,
            help,
            after,
            before,
            params,
            action,
            selected,
        }
    }
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param> {
        self.params
            .get(name)
            .ok_or_else(|| anyhow!("get_param: failed to get name={}", name))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or_else(|| anyhow!("set_param: failed to set param.name={}", name))
    }
}

fn deserialize_task_map<'de, D>(deserializer: D) -> Result<Tasks, D::Error>
where
    D: Deserializer<'de>,
{
    struct TaskMap;

    impl<'de> Visitor<'de> for TaskMap {
        type Value = Tasks;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Task")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut tasks = Tasks::new();
            while let Some((name, mut task)) = map.next_entry::<String, Task>()? {
                task.name = name.to_owned();
                tasks.insert(name.to_owned(), task);
            }
            Ok(tasks)
        }
    }
    deserializer.deserialize_map(TaskMap)
}
<commit_msg>clippy fixes<commit_after>#![allow(unused_imports, unused_variables, dead_code)]
use super::error::ConfigError;
use anyhow::{anyhow, Result};

use serde::de::{Deserializer, Error, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::collections::HashMap;
use std::fmt;
use std::num::ParseIntError;
use std::vec::Vec;
/*
type Tasks = Vec<Task>;
type Params = Vec<Param>;
*/
type Tasks = HashMap<String, Task>;
type Params = HashMap<String, Param>;

#[derive(Debug, Clone, PartialEq)]
pub enum Nargs {
    One,
    Zero,
    OneOrZero,
    OneOrMore,
    ZeroOrMore,
    Range(usize, usize),
}

impl fmt::Display for Nargs {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Nargs::One => write!(fmtr, "Nargs::One[1]"),
            Nargs::Zero => write!(fmtr, "Nargs::Zero[0]"),
            Nargs::OneOrZero => write!(fmtr, "Nargs::OneOrZero[?]"),
            Nargs::OneOrMore => write!(fmtr, "Nargs::OneOrMore[+]"),
            Nargs::ZeroOrMore => write!(fmtr, "Nargs::ZeroOrMore[*]"),
            Nargs::Range(min, max) => write!(fmtr, "Nargs::Range[{}, {}]", min + 1, max),
        }
    }
}

impl Default for Nargs {
    fn default() -> Self {
        Nargs::One
    }
}

impl<'de> Deserialize<'de> for Nargs {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let result = match &s[..] {
            "1" => Nargs::One,
            "0" => Nargs::Zero,
            "?" => Nargs::OneOrZero,
            "+" => Nargs::OneOrMore,
            "*" => Nargs::ZeroOrMore,
            _ => {
                println!("s={}", s);
                if s.contains(':') {
                    let parts: Vec<&str> = s.split(':').collect();
                    let min = parts[0].parse::<usize>().map_err(Error::custom)?;
                    let max = parts[1].parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(min - 1, max)
                } else {
                    let num = s.parse::<usize>().map_err(Error::custom)?;
                    Nargs::Range(0, num)
                }
            }
        };
        Ok(result)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    Item(String),
    List(Vec<String>),
    Dict(HashMap<String, String>),
    Empty,
}

impl fmt::Display for Value {
    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Value::Item(s) => write!(fmtr, "Values::Item({})", s),
            Value::List(vs) => write!(fmtr, "Values::List([{}])", vs.join(", ")),
            Value::Dict(ds) => write!(fmtr, "Values::Dict[NOT IMPLEMENTED]"),
            Value::Empty => write!(fmtr, "Value::Empty(\"\")"),
        }
    }
}

impl Default for Value {
    fn default() -> Self {
        Value::Empty
    }
}

fn deserialize_value<'de, D>(deserializer: D) -> Result<Value, D::Error>
where
    D: Deserializer<'de>,
{
    struct ValueEnum;
    impl<'de> Visitor<'de> for ValueEnum {
        type Value = Value;

        fn expecting(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
            fmtr.write_str("string or list of strings")
        }
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
        where
            E: Error,
        {
            Ok(Value::Item(value.to_owned()))
        }
        fn visit_seq<S>(self, mut visitor: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            let mut vec: Vec<String> = vec![];
            while let Some(item) = visitor.next_element()? {
                vec.push(item);
            }
            Ok(Value::List(vec))
        }
    }
    deserializer.deserialize_any(ValueEnum)
}

fn default_otto() -> String {
    "otto".to_string()
}

fn default_verbosity() -> i32 {
    1
}

fn default_api() -> i32 {
    1
}

fn default_jobs() -> i32 {
    12
}
fn default_defaults() -> Defaults {
    Defaults {
        api: default_api(),
        verbosity: default_verbosity(),
        jobs: default_jobs(),
        tasks: vec![],
    }
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Spec {
    #[serde(default = "default_defaults")]
    pub defaults: Defaults,

    pub otto: Otto,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Defaults {
    #[serde(default = "default_api")]
    pub api: i32,

    #[serde(default = "default_verbosity")]
    pub verbosity: i32,

    #[serde(default = "default_jobs")]
    pub jobs: i32,

    #[serde(default)]
    pub tasks: Vec<String>,
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Otto {
    #[serde(skip_deserializing, default = "default_otto")]
    pub name: String,

    #[serde(default)]
    pub author: Option<String>,

    #[serde(default)]
    pub about: Option<String>,

    #[serde(default)]
    pub version: Option<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    #[serde(default, deserialize_with = "deserialize_task_map")]
    pub tasks: Tasks,

    pub action: Option<String>,
}

impl Otto {
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param, ConfigError> {
        self.params
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param, ConfigError> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param, ConfigError> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn get_task(&self, name: &str) -> Result<&Task, ConfigError> {
        self.tasks
            .get(name)
            .ok_or_else(|| ConfigError::NameLookupError(name.to_string()))
    }
    pub fn set_task(&mut self, task: Task) -> Result<Task, ConfigError> {
        let name = task.name.to_owned();
        self.tasks
            .insert(name.to_owned(), task)
            .ok_or(ConfigError::NameLookupError(name))
    }
    pub fn task_names(&self) -> Vec<&str> {
        self.tasks.keys().map(AsRef::as_ref).collect()
    }
}

pub enum ParamType {
    FLG,
    OPT,
    POS,
}

// FIXME: Flag, Named and Positional Args
#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Param {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(skip_deserializing)]
    pub flags: Vec<String>,

    #[serde(skip_deserializing)]
    pub value: Value,

    #[serde(default)]
    pub dest: Option<String>,

    #[serde(default)]
    pub metavar: Option<String>,

    #[serde(default)]
    pub default: Option<String>,

    #[serde(default, deserialize_with = "deserialize_value")]
    pub constant: Value,

    #[serde(default)]
    pub choices: Vec<String>,

    #[serde(default)]
    pub nargs: Nargs,

    #[serde(default)]
    pub help: Option<String>,
}

impl Param {
    pub fn param_type(&self) -> ParamType {
        match self.name.chars().next() {
            Some('-') => match self.default.as_deref() {
                Some("true") | Some("false") => ParamType::FLG,
                Some(_) | None => ParamType::OPT,
            },
            Some(_) | None => ParamType::POS,
        }
    }
}

fn deserialize_param_map<'de, D>(deserializer: D) -> Result<Params, D::Error>
where
    D: Deserializer<'de>,
{
    struct ParamMap;

    impl<'de> Visitor<'de> for ParamMap {
        type Value = Params;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Param")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut params = Params::new();
            while let Some((name, mut param)) = map.next_entry::<String, Param>()? {
                param.flags = name.split('|').map(|f| f.to_string()).collect();
                let short: Vec<String> = param
                    .flags
                    .iter()
                    .cloned()
                    .filter(|i| i.starts_with('-') && i.len() == 2)
                    //.map(|i| i.to_string())
                    .collect();
                let long: Vec<String> = param
                    .flags
                    .iter()
                    .cloned()
                    .filter(|i| i.starts_with("--") && i.len() > 2)
                    //.map(|i| i.to_string())
                    .collect();
                if param.dest.is_none() {
                    let dest = match long.first() {
                        Some(long) => String::from(long.trim_matches('-')),
                        None => match short.first() {
                            Some(short) => String::from(short.trim_matches('-')),
                            None => param.name,
                        },
                    };
                    param.dest = Some(dest);
                }
                param.name = name.to_owned();
                params.insert(name.to_owned(), param);
            }
            Ok(params)
        }
    }
    deserializer.deserialize_map(ParamMap)
}

#[derive(Clone, Debug, Default, PartialEq, Deserialize)]
pub struct Task {
    #[serde(skip_deserializing)]
    pub name: String,

    #[serde(default)]
    pub help: Option<String>,

    #[serde(default)]
    pub after: Vec<String>,

    #[serde(default)]
    pub before: Vec<String>,

    #[serde(default, deserialize_with = "deserialize_param_map")]
    pub params: Params,

    pub action: Option<String>,

    #[serde(skip_deserializing)]
    pub selected: bool,
}

impl Task {
    pub fn new(
        name: String,
        help: Option<String>,
        after: Vec<String>,
        before: Vec<String>,
        params: Params,
        action: Option<String>,
        selected: bool,
    ) -> Self {
        Self {
            name,
            help,
            after,
            before,
            params,
            action,
            selected,
        }
    }
    fn get_param_key(&self, flag: &str) -> Result<&String, ConfigError> {
        for (key, param) in self.params.iter() {
            if param.flags.iter().any(|f| f == flag) {
                return Ok(key);
            }
        }
        Err(ConfigError::FlagLookupError(flag.to_string()))
    }
    pub fn get_param(&self, name: &str) -> Result<&Param> {
        self.params
            .get(name)
            .ok_or_else(|| anyhow!("get_param: failed to get name={}", name))
    }
    pub fn get_param_from_flag(&self, flag: &str) -> Result<&Param> {
        let key = self.get_param_key(flag)?;
        self.get_param(key)
    }
    pub fn set_param(&mut self, param: Param) -> Result<Param> {
        let name = param.name.to_owned();
        self.params
            .insert(name.to_owned(), param)
            .ok_or_else(|| anyhow!("set_param: failed to set param.name={}", name))
    }
}

fn deserialize_task_map<'de, D>(deserializer: D) -> Result<Tasks, D::Error>
where
    D: Deserializer<'de>,
{
    struct TaskMap;

    impl<'de> Visitor<'de> for TaskMap {
        type Value = Tasks;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a map of name to Task")
        }

        fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
        where
            M: MapAccess<'de>,
        {
            let mut tasks = Tasks::new();
            while let Some((name, mut task)) = map.next_entry::<String, Task>()? {
                task.name = name.to_owned();
                tasks.insert(name.to_owned(), task);
            }
            Ok(tasks)
        }
    }
    deserializer.deserialize_map(TaskMap)
}
<|endoftext|>