<commit_before>use bip_metainfo::MetainfoFile;
use bip_bencode::Bencode;
use bip_utracker::contact::CompactPeersV4;
use errors::*;
use futures::sync::mpsc::{self, Sender, Receiver};
use hyper::Client;
use hyper::header::Connection;
use tokio_core::io::{read, write_all};
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use url::Url;

use std::collections::HashMap;
use std::io::Read;
use std::fs;
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
use std::thread;
use std::str;
use std::string::String;

use packet::peer_pkt::{MutablePeerHandshakePacket, MutablePeerMessagePacket};

pub struct BTClient {
    torrents: HashMap<usize, Arc<RwLock<Torrent>>>,
    id: String, // peer_id or client id
    next_id: usize,
    channels: HashMap<usize, Sender<Message>>,
}

fn torrent_loop(rx: Receiver<Message>, torrent: Arc<RwLock<Torrent>>) {
    let mut core = Core::new().unwrap();
}

impl BTClient {
    pub fn new() -> BTClient {
        let now = SystemTime::now();
        let duration = now.duration_since(UNIX_EPOCH).unwrap();
        let client_id = "-bittorrent-rs-".to_owned() + &format!("{}", duration.as_secs() % 100_000);
        BTClient {
            torrents: HashMap::new(),
            id: client_id,
            next_id: 0,
            channels: HashMap::new(),
        }
    }

    pub fn add(self: &mut BTClient, file: fs::File) -> Result<()> {
        let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel(1);
        let torrent = Arc::new(RwLock::new(Torrent::new(file)));
        let t_clone = torrent.clone();
        self.torrents.insert(self.next_id, torrent);
        self.channels.insert(self.next_id, tx);
        self.next_id += 1;

        thread::spawn(move || torrent_loop(rx, t_clone));
        Ok(())
    }

    pub fn remove(self: &mut BTClient, id: usize) -> Result<usize> {
        self.torrents.remove(&id);
        Ok(self.torrents.len())
    }

    pub fn list(self: &BTClient) -> Vec<(usize, String)> {
        self.torrents
            .iter()
            .map(|(id, torrent)| {
                let torrent = &(*(torrent.read().unwrap()));
                let root_name: String;
                if let Some(dir) = torrent.metainfo
                    .info()
                    .directory() {
                    root_name = dir.to_owned();
                } else {
                    root_name = torrent.metainfo
                        .info()
                        .files()
                        .next()
                        .unwrap()
                        .paths()
                        .next()
                        .unwrap()
                        .to_owned();
                }
                (*id, root_name)
            })
            .collect()
    }

    pub fn get_id(self: &BTClient) -> String {
        self.id.clone()
    }
}

pub struct Torrent {
    metainfo: MetainfoFile,

    // From/For tracker
    pub peers: Vec<Peer>,
    pub uploaded: usize,
    pub downloaded: usize,
    pub left: usize,
    pub interval: usize, // in seconds
    pub tracker_id: String,
    pub num_seeders: usize,
    pub num_leachers: usize,
    pub bitmap: Vec<u8>,
}

pub enum Message {
    StartDownload,
    StartSeed,
    StopDownload,
    StopSeed,
    Exit,
}

impl Torrent {
    pub fn new(mut tfile: fs::File) -> Torrent {
        // parse metainfo file
        let mut bytes: Vec<u8> = Vec::new();
        tfile.read_to_end(&mut bytes).unwrap();

        let metainfo = MetainfoFile::from_bytes(bytes).unwrap();
        let pieces = metainfo.info().pieces().count();
        Torrent {
            metainfo: metainfo,

            peers: Vec::new(),
            uploaded: 0,
            downloaded: 0,
            left: 0,
            interval: 0, // in seconds
            tracker_id: String::new(),
            num_seeders: 0,
            num_leachers: 0,
            bitmap: vec![0; pieces],
        }
    }
    fn send_bitmap(self: Torrent, mut stream: &TcpStream) -> Result<()> {
        let mut buf = vec![0u8; self.bitmap.len()+2];
        let mut bitmap_pkt = MutablePeerMessagePacket::new(&mut buf).unwrap();
        bitmap_pkt.set_len((self.bitmap.len() + 1) as u32);
        bitmap_pkt.set_id(5);
        bitmap_pkt.set_payload(&self.bitmap);
        Ok(())
    }

    fn connect_to_tracker(self: Torrent,
                          peer_id: String,
                          port: u16)
                          -> Result<(Vec<String>, String)> {
        debug!("connecting to tracker: {:?}", self.metainfo.main_tracker());

        let info_hash = self.metainfo.info_hash();
        // TODO figure can this conversion to url-encoded form be done safely?
        let info_hash_str = unsafe { str::from_utf8_unchecked(info_hash.as_ref()) };

        // TODO this needs to be calculated based on what we have
        let total_len = self.metainfo.info().files().fold(0, |acc, nex| acc + nex.length());

        let mut url = Url::parse(self.metainfo.main_tracker().unwrap()).unwrap();
        url.query_pairs_mut()
		.append_pair("info_hash", info_hash_str)
		.append_pair("peer_id", &peer_id)
	        .append_pair("port", &(port.to_string()))
		 // TODO parametrize this
		.append_pair("uploaded", "0")
		// TODO parametrize this
		.append_pair("downloaded", "0")
		// TODO see note on total_len above
		.append_pair("left", &(total_len.to_string()))
		.append_pair("compact", "1")
		.append_pair("event", "started")
		.append_pair("supportcrypto", "0");
        trace!("URL {:?}", url);

        let client = Client::new();
        let mut res = client.get(url).header(Connection::close()).send().unwrap();
        let mut buffer = Vec::new();
        res.read_to_end(&mut buffer).unwrap();
        debug!("{:?}", res);
        let bencode = Bencode::decode(&buffer).unwrap();
        trace!("{:?}", bencode);
        let (_, peers) = CompactPeersV4::from_bytes(bencode.dict()
                .unwrap()
                .lookup("peers")
                .unwrap()
                .bytes()
                .unwrap())
            .unwrap();
        trace!("{:?}", peers);
        let mut ip_ports: Vec<String> = Vec::new();
        debug!("Peer list received:");
        for peer in peers.iter() {
            debug!("{:?}", peer);
            ip_ports.push(peer.to_string());
        }
        Ok((ip_ports, info_hash_str.to_string()))
    }
}

pub struct Peer {
    id: String, // peer_id
    ip_port: String,

    am_choking: bool,
    peer_choking: bool,
    am_interested: bool,
    peer_interested: bool,
}

impl Peer {
    pub fn new(id: String, ip_port: String) -> Peer {
        Peer {
            id: id,
            ip_port: ip_port,
            am_choking: true,
            am_interested: false,
            peer_choking: true,
            peer_interested: false,
        }
    }
}

struct TrackerRequest {
    info_hash: String,
    peer_id: String,
    port: usize, // port client is listening on, between 6881-6889
    uploaded: usize,
    downloaded: usize,
    left: usize,
    event: EventType, // TODO think about adding optional fields
}

enum EventType {
    Started,
    Stopped,
    Completed,
}
<commit_msg>Porting functions from main to btclient<commit_after>use bip_metainfo::MetainfoFile;
use bip_bencode::Bencode;
use bip_utracker::contact::CompactPeersV4;
use errors::*;
use futures::sync::mpsc::{self, Sender, Receiver};
use hyper::Client;
use hyper::header::Connection;
use tokio_core::io::{read, write_all};
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use url::Url;

use std::collections::HashMap;
use std::io::Read;
use std::fs;
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
use std::thread;
use std::str;
use std::string::String;
use std::net::SocketAddr;

use packet::peer_pkt::{MutablePeerHandshakePacket, MutablePeerMessagePacket};
use pnet::packet::Packet;

const PEER_HANDSHAKE_STRUCT_SZ: usize = 68;
const PEER_REQ_PKT_SZ: usize = 14;

pub struct BTClient {
    torrents: HashMap<usize, Arc<RwLock<Torrent>>>,
    id: String, // peer_id or client id
    next_id: usize,
    channels: HashMap<usize, Sender<Message>>,
}

fn torrent_loop(rx: Receiver<Message>, torrent: Arc<RwLock<Torrent>>) {
    let mut core = Core::new().unwrap();
}

impl BTClient {
    pub fn new() -> BTClient {
        let now = SystemTime::now();
        let duration = now.duration_since(UNIX_EPOCH).unwrap();
        let client_id = "-bittorrent-rs-".to_owned() + &format!("{}", duration.as_secs() % 100_000);
        BTClient {
            torrents: HashMap::new(),
            id: client_id,
            next_id: 0,
            channels: HashMap::new(),
        }
    }

    pub fn add(self: &mut BTClient, file: fs::File) -> Result<()> {
        let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel(1);
        let torrent = Arc::new(RwLock::new(Torrent::new(file)));
        let t_clone = torrent.clone();
        self.torrents.insert(self.next_id, torrent);
        self.channels.insert(self.next_id, tx);
        self.next_id += 1;

        thread::spawn(move || torrent_loop(rx, t_clone));
        Ok(())
    }

    pub fn remove(self: &mut BTClient, id: usize) -> Result<usize> {
        self.torrents.remove(&id);
        Ok(self.torrents.len())
    }

    pub fn list(self: &BTClient) -> Vec<(usize, String)> {
        self.torrents
            .iter()
            .map(|(id, torrent)| {
                let torrent = &(*(torrent.read().unwrap()));
                let root_name: String;
                if let Some(dir) = torrent.metainfo
                    .info()
                    .directory() {
                    root_name = dir.to_owned();
                } else {
                    root_name = torrent.metainfo
                        .info()
                        .files()
                        .next()
                        .unwrap()
                        .paths()
                        .next()
                        .unwrap()
                        .to_owned();
                }
                (*id, root_name)
            })
            .collect()
    }

    pub fn get_id(self: &BTClient) -> String {
        self.id.clone()
    }
}

pub struct Torrent {
    metainfo: MetainfoFile,

    // From/For tracker
    pub peers: Vec<Peer>,
    pub uploaded: usize,
    pub downloaded: usize,
    pub left: usize,
    pub interval: usize, // in seconds
    pub tracker_id: String,
    pub num_seeders: usize,
    pub num_leachers: usize,
    pub bitmap: Vec<u8>,
}

pub enum Message {
    StartDownload,
    StartSeed,
    StopDownload,
    StopSeed,
    Exit,
}

impl Torrent {
    pub fn new(mut tfile: fs::File) -> Torrent {
        // parse metainfo file
        let mut bytes: Vec<u8> = Vec::new();
        tfile.read_to_end(&mut bytes).unwrap();

        let metainfo = MetainfoFile::from_bytes(bytes).unwrap();
        let pieces = metainfo.info().pieces().count();
        Torrent {
            metainfo: metainfo,

            peers: Vec::new(),
            uploaded: 0,
            downloaded: 0,
            left: 0,
            interval: 0, // in seconds
            tracker_id: String::new(),
            num_seeders: 0,
            num_leachers: 0,
            bitmap: vec![0; pieces],
        }
    }
    fn send_bitmap(self: Torrent, mut stream: &TcpStream) -> Result<()> {
        let mut buf = vec![0u8; self.bitmap.len()+2];
        let mut bitmap_pkt = MutablePeerMessagePacket::new(&mut buf).unwrap();
        bitmap_pkt.set_len((self.bitmap.len() + 1) as u32);
        bitmap_pkt.set_id(5);
        bitmap_pkt.set_payload(&self.bitmap);
        Ok(())
    }

    fn connect_to_tracker(self: Torrent,
                          peer_id: String,
                          port: u16)
                          -> Result<(Vec<String>, String)> {
        debug!("connecting to tracker: {:?}", self.metainfo.main_tracker());

        let info_hash = self.metainfo.info_hash();
        // TODO figure can this conversion to url-encoded form be done safely?
        let info_hash_str = unsafe { str::from_utf8_unchecked(info_hash.as_ref()) };

        // TODO this needs to be calculated based on what we have
        let total_len = self.metainfo.info().files().fold(0, |acc, nex| acc + nex.length());

        let mut url = Url::parse(self.metainfo.main_tracker().unwrap()).unwrap();
        url.query_pairs_mut()
		.append_pair("info_hash", info_hash_str)
		.append_pair("peer_id", &peer_id)
	        .append_pair("port", &(port.to_string()))
		 // TODO parametrize this
		.append_pair("uploaded", "0")
		// TODO parametrize this
		.append_pair("downloaded", "0")
		// TODO see note on total_len above
		.append_pair("left", &(total_len.to_string()))
		.append_pair("compact", "1")
		.append_pair("event", "started")
		.append_pair("supportcrypto", "0");
        trace!("URL {:?}", url);

        let client = Client::new();
        let mut res = client.get(url).header(Connection::close()).send().unwrap();
        let mut buffer = Vec::new();
        res.read_to_end(&mut buffer).unwrap();
        debug!("{:?}", res);
        let bencode = Bencode::decode(&buffer).unwrap();
        trace!("{:?}", bencode);
        let (_, peers) = CompactPeersV4::from_bytes(bencode.dict()
                .unwrap()
                .lookup("peers")
                .unwrap()
                .bytes()
                .unwrap())
            .unwrap();
        trace!("{:?}", peers);
        let mut ip_ports: Vec<String> = Vec::new();
        debug!("Peer list received:");
        for peer in peers.iter() {
            debug!("{:?}", peer);
            ip_ports.push(peer.to_string());
        }
        Ok((ip_ports, info_hash_str.to_string()))
    }

    fn peer_connections(self: Torrent, peer_ip_ports: Vec<String>, peer_id: String) -> Result<()> {
        let info_hash = self.metainfo.info_hash();
        // TODO figure can this conversion to url-encoded form be done safely?
        let info_hash_str = unsafe { str::from_utf8_unchecked(info_hash.as_ref()) };
        for ip_port in peer_ip_ports {
            let peer_ip_port = ip_port.clone();
            let info_hash_clone = info_hash_str.to_string().clone();
            let peer_id_clone = peer_id.clone();
            thread::spawn(move || {
                fn run(pip: String, ih: String, pid: String) -> Result<()> {
                    let mut l = Core::new().unwrap();
                    // TODO setup timeout before handshake
                    // let dur = Duration::from_secs(100);
                    // let timeout = Timeout::new(dur, &l.handle()).unwrap();

                    if let Ok(client) = self.handshake_peer(&mut l, pip, ih, pid) {
                        // debug!("Communicating with peer {:?}", peer_ip_port_cl);
                        // debug!("Starting thread timer...");
                        if let Ok((_, buf, amt)) =
                               l.run(read(client, vec![0; PEER_HANDSHAKE_STRUCT_SZ]))
                            .chain_err(|| "didn't receive handshake response from peer") {
                            if buf[0] == 19 &&
                               String::from_utf8_lossy(&buf[1..20]) == "BitTorrent protocol" &&
                               amt == 68 {
                                info!("handshake successful!");
                            } else {
                                info!("not a useful peer")
                            }
                        } else {
                            bail!("");
                        }
                    } else {
                        bail!("");
                    }
                    Ok(())
                }
                if let Err(ref e) = run(peer_ip_port, info_hash_clone, peer_id_clone) {
                    println!("error: {}", e);

                    for e in e.iter().skip(1) {
                        println!("caused by: {}", e);
                    }

                    if let Some(backtrace) = e.backtrace() {
                        println!("backtrace: {:?}", backtrace);
                    }
                }

                // TODO determine the below three parameters logically
                // let index = 0;
                // let begin = 0;
                // let length = 10;
                // match request_piece(&stream, index, begin, length) {
                //     Ok(buf_read) => {
                //         trace!("buf_read: {:?}", buf_read);
                //     }
                //     Err(_) => error!("Requesting piece failed!"),
                // }
                // send_keep_alive(&stream);
            });
        }
        Ok(())
    }

    fn handshake_peer(self: Torrent,
                      core: &mut Core,
                      peer_ip_port: String,
                      peer_id: String)
                      -> Result<TcpStream> {
        let info_hash = self.metainfo.info_hash();
        // TODO figure can this conversion to url-encoded form be done safely?
        let info_hash_str = unsafe { str::from_utf8_unchecked(info_hash.as_ref()) };
        let mut buf = vec![0u8; PEER_HANDSHAKE_STRUCT_SZ];
        let mut ph = MutablePeerHandshakePacket::new(&mut buf).unwrap();
        ph.set_pstrlen("BitTorrent protocol".len() as u8);
        ph.set_pstr(&String::from("BitTorrent protocol").into_bytes());
        ph.set_reserved(&[0; 8]);
        ph.set_info_hash(info_hash_str.as_bytes());
        ph.set_peer_id(peer_id.as_bytes());
        let handle = core.handle();
        let client = TcpStream::connect(&peer_ip_port.parse::<SocketAddr>().unwrap(), &handle);
        let client = core.run(client).unwrap();
        let (client, _) = core.run(write_all(client, ph.packet())).unwrap();
        trace!("{:?}", client);
        Ok(client)
    }
}

pub struct Peer {
    id: String, // peer_id
    ip_port: String,

    am_choking: bool,
    peer_choking: bool,
    am_interested: bool,
    peer_interested: bool,
}

impl Peer {
    pub fn new(id: String, ip_port: String) -> Peer {
        Peer {
            id: id,
            ip_port: ip_port,
            am_choking: true,
            am_interested: false,
            peer_choking: true,
            peer_interested: false,
        }
    }
}

struct TrackerRequest {
    info_hash: String,
    peer_id: String,
    port: usize, // port client is listening on, between 6881-6889
    uploaded: usize,
    downloaded: usize,
    left: usize,
    event: EventType, // TODO think about adding optional fields
}

enum EventType {
    Started,
    Stopped,
    Completed,
}
<|endoftext|>


<commit_before>//! Defines the BxDF interface implemented by BRDF/BTDFs to describe
//! material properties. Also provides the BSDF type which composes
//! various BRDF/BTDFs to describe materials

use std::mem;
use std::f32;
use enum_set::{EnumSet, CLike};

use linalg::{self, Vector};
use film::Colorf;
use mc;

pub use self::bsdf::BSDF;
pub use self::lambertian::Lambertian;
pub use self::oren_nayar::OrenNayar;
pub use self::specular_reflection::SpecularReflection;
pub use self::specular_transmission::SpecularTransmission;
pub use self::merl::Merl;
pub use self::torrance_sparrow::TorranceSparrow;
pub use self::microfacet_transmission::MicrofacetTransmission;

pub mod bsdf;
pub mod lambertian;
pub mod oren_nayar;
pub mod fresnel;
pub mod specular_reflection;
pub mod specular_transmission;
pub mod merl;
pub mod microfacet;
pub mod torrance_sparrow;
pub mod microfacet_transmission;

/// Various types of BxDFs that can be selected to specify which
/// types of surface functions should be evaluated
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum BxDFType {
    Reflection, Transmission, Diffuse, Glossy, Specular,
}

impl BxDFType {
    /// Get an EnumSet containing all flags for the different types of
    /// BxDFs: Diffuse, Glossy, Specular
    pub fn all_types() -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Diffuse);
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Specular);
        e
    }
    /// Get an EnumSet containing all flags for reflective BxDFs (eg. BRDFs)
    pub fn all_brdf() -> EnumSet<BxDFType> {
        let mut e = BxDFType::all_types();
        e.insert(BxDFType::Reflection);
        e
    }
    /// Get an EnumSet containing all flags for transmissive BxDFs (eg. BTDFs)
    pub fn all_btdf() -> EnumSet<BxDFType> {
        let mut e = BxDFType::all_types();
        e.insert(BxDFType::Transmission);
        e
    }
    /// Get an EnumSet containing all flags for all BxDFs. This would be all
    /// types of BRDFs and BTDFs
    pub fn all() -> EnumSet<BxDFType> { BxDFType::all_brdf().union(BxDFType::all_btdf()) }
    /// Get an EnumSet containing flags for all types of specular BxDFs
    pub fn specular() -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Specular);
        e.insert(BxDFType::Reflection);
        e.insert(BxDFType::Transmission);
        e
    }
    /// Get an EnumSet containing flags for all non-specular BxDFs
    pub fn non_specular() -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Diffuse);
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Reflection);
        e.insert(BxDFType::Transmission);
        e
    }
}

impl CLike for BxDFType {
    fn to_u32(&self) -> u32 { *self as u32 }
    unsafe fn from_u32(v: u32) -> BxDFType { mem::transmute(v) }
}

/// Trait implemented by BRDF/BTDFs in `tray_rust`. Provides methods for
/// evaluating and sampling the function
pub trait BxDF {
    /// Get the type of this BxDF
    fn bxdf_type(&self) -> EnumSet<BxDFType>;
    /// Evaluate the BxDF for the pair of incident and outgoing light directions,
    /// `w_i` and `w_o`.
    fn eval(&self, w_o: &Vector, w_i: &Vector) -> Colorf;
    /// Sample an incident light direction for an outgoing light direction `w_o`.
    /// `samples` will be used to randomly sample a direction for the outgoing light
    /// Returns the color of the material for the pair of directions, the incident
    /// light direction and pdf
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Colorf, Vector, f32) {
        let mut w_i = mc::cos_sample_hemisphere(samples);
        // We may need to flip the sampled direction to be on the same hemisphere as w_o
        if w_o.z < 0.0 {
            w_i.z *= -1.0;
        }
        (self.eval(w_o, &w_i), w_i, self.pdf(w_o, &w_i))
    }
    /// Check if this BxDF matches the type flags passed
    fn matches(&self, flags: EnumSet<BxDFType>) -> bool {
        self.bxdf_type().is_subset(&flags)
    }
    /// Compute the pdf of sampling the pair of directions passed for this BxDF
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        if same_hemisphere(w_o, w_i) {
            f32::abs(cos_theta(w_i)) * f32::consts::FRAC_1_PI
        } else {
            0.0
        }
    }
}

/// Compute the value of cosine theta for a vector in shading space
pub fn cos_theta(v: &Vector) -> f32 { v.z }
/// Compute the value of (sine theta)^2  for a vector in shading space
pub fn sin_theta_sqr(v: &Vector) -> f32 { f32::max(0.0, 1.0 - v.z * v.z) }
/// Compute the value of sine theta for a vector in shading space
pub fn sin_theta(v: &Vector) -> f32 { f32::sqrt(sin_theta_sqr(v)) }
/// Compute the value of tan theta for a vector in shading space
pub fn tan_theta(v: &Vector) -> f32 {
    let sin_theta_2 = sin_theta_sqr(v);
    if sin_theta_2 <= 0.0 {
        0.0
    } else {
        f32::sqrt(sin_theta_2) / cos_theta(v)
    }
}
/// Compute the value of arctan theta for a vector in shading space
pub fn arctan_theta(v: &Vector) -> f32 { cos_theta(v) / sin_theta(v) }
/// Compute the value of cosine phi for a vector in shading space
pub fn cos_phi(v: &Vector) -> f32 {
    let sin_theta = sin_theta(v);
    if sin_theta == 0.0 {
        1.0
    } else {
        linalg::clamp(v.x / sin_theta, -1.0, 1.0)
    }
}
/// Compute the value of sine phi for a vector in shading space
pub fn sin_phi(v: &Vector) -> f32 {
    let sin_theta = sin_theta(v);
    if sin_theta == 0.0 {
        0.0
    } else {
        linalg::clamp(v.y / sin_theta, -1.0, 1.0)
    }
}
/// Check if two vectors are in the same hemisphere in shading space
pub fn same_hemisphere(a: &Vector, b: &Vector) -> bool { a.z * b.z > 0.0 }

<commit_msg>Add some other bxdf trig utils<commit_after>//! Defines the BxDF interface implemented by BRDF/BTDFs to describe
//! material properties. Also provides the BSDF type which composes
//! various BRDF/BTDFs to describe materials

use std::mem;
use std::f32;
use enum_set::{EnumSet, CLike};

use linalg::{self, Vector};
use film::Colorf;
use mc;

pub use self::bsdf::BSDF;
pub use self::lambertian::Lambertian;
pub use self::oren_nayar::OrenNayar;
pub use self::specular_reflection::SpecularReflection;
pub use self::specular_transmission::SpecularTransmission;
pub use self::merl::Merl;
pub use self::torrance_sparrow::TorranceSparrow;
pub use self::microfacet_transmission::MicrofacetTransmission;

pub mod bsdf;
pub mod lambertian;
pub mod oren_nayar;
pub mod fresnel;
pub mod specular_reflection;
pub mod specular_transmission;
pub mod merl;
pub mod microfacet;
pub mod torrance_sparrow;
pub mod microfacet_transmission;

/// Various types of BxDFs that can be selected to specify which
/// types of surface functions should be evaluated
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum BxDFType {
    Reflection, Transmission, Diffuse, Glossy, Specular,
}

impl BxDFType {
    /// Get an EnumSet containing all flags for the different types of
    /// BxDFs: Diffuse, Glossy, Specular
    pub fn all_types() -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Diffuse);
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Specular);
        e
    }
    /// Get an EnumSet containing all flags for reflective BxDFs (eg. BRDFs)
    pub fn all_brdf() -> EnumSet<BxDFType> {
        let mut e = BxDFType::all_types();
        e.insert(BxDFType::Reflection);
        e
    }
    /// Get an EnumSet containing all flags for transmissive BxDFs (eg. BTDFs)
    pub fn all_btdf() -> EnumSet<BxDFType> {
        let mut e = BxDFType::all_types();
        e.insert(BxDFType::Transmission);
        e
    }
    /// Get an EnumSet containing all flags for all BxDFs. This would be all
    /// types of BRDFs and BTDFs
    pub fn all() -> EnumSet<BxDFType> { BxDFType::all_brdf().union(BxDFType::all_btdf()) }
    /// Get an EnumSet containing flags for all types of specular BxDFs
    pub fn specular() -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Specular);
        e.insert(BxDFType::Reflection);
        e.insert(BxDFType::Transmission);
        e
    }
    /// Get an EnumSet containing flags for all non-specular BxDFs
    pub fn non_specular() -> EnumSet<BxDFType> {
        let mut e = EnumSet::new();
        e.insert(BxDFType::Diffuse);
        e.insert(BxDFType::Glossy);
        e.insert(BxDFType::Reflection);
        e.insert(BxDFType::Transmission);
        e
    }
}

impl CLike for BxDFType {
    fn to_u32(&self) -> u32 { *self as u32 }
    unsafe fn from_u32(v: u32) -> BxDFType { mem::transmute(v) }
}

/// Trait implemented by BRDF/BTDFs in `tray_rust`. Provides methods for
/// evaluating and sampling the function
pub trait BxDF {
    /// Get the type of this BxDF
    fn bxdf_type(&self) -> EnumSet<BxDFType>;
    /// Evaluate the BxDF for the pair of incident and outgoing light directions,
    /// `w_i` and `w_o`.
    fn eval(&self, w_o: &Vector, w_i: &Vector) -> Colorf;
    /// Sample an incident light direction for an outgoing light direction `w_o`.
    /// `samples` will be used to randomly sample a direction for the outgoing light
    /// Returns the color of the material for the pair of directions, the incident
    /// light direction and pdf
    fn sample(&self, w_o: &Vector, samples: &(f32, f32)) -> (Colorf, Vector, f32) {
        let mut w_i = mc::cos_sample_hemisphere(samples);
        // We may need to flip the sampled direction to be on the same hemisphere as w_o
        if w_o.z < 0.0 {
            w_i.z *= -1.0;
        }
        (self.eval(w_o, &w_i), w_i, self.pdf(w_o, &w_i))
    }
    /// Check if this BxDF matches the type flags passed
    fn matches(&self, flags: EnumSet<BxDFType>) -> bool {
        self.bxdf_type().is_subset(&flags)
    }
    /// Compute the pdf of sampling the pair of directions passed for this BxDF
    fn pdf(&self, w_o: &Vector, w_i: &Vector) -> f32 {
        if same_hemisphere(w_o, w_i) {
            f32::abs(cos_theta(w_i)) * f32::consts::FRAC_1_PI
        } else {
            0.0
        }
    }
}

/// Compute the value of cosine theta for a vector in shading space
pub fn cos_theta(v: &Vector) -> f32 { v.z }
/// Compute the value of cosine^2 theta for a vector in shading space
pub fn cos_theta_sqr(v: &Vector) -> f32 { v.z * v.z }
/// Compute the value of (sine theta)^2  for a vector in shading space
pub fn sin_theta_sqr(v: &Vector) -> f32 { f32::max(0.0, 1.0 - v.z * v.z) }
/// Compute the value of sine theta for a vector in shading space
pub fn sin_theta(v: &Vector) -> f32 { f32::sqrt(sin_theta_sqr(v)) }
/// Compute the value of tan theta for a vector in shading space
pub fn tan_theta(v: &Vector) -> f32 {
    let sin_theta_2 = sin_theta_sqr(v);
    if sin_theta_2 <= 0.0 {
        0.0
    } else {
        f32::sqrt(sin_theta_2) / cos_theta(v)
    }
}
/// Compute the value of tan theta^2 for a vector in shading space
pub fn tan_theta_sqr(v: &Vector) -> f32 {
    sin_theta_sqr(v) / cos_theta_sqr(v)
}
/// Compute the value of arctan theta for a vector in shading space
pub fn arctan_theta(v: &Vector) -> f32 { cos_theta(v) / sin_theta(v) }
/// Compute the value of cosine phi for a vector in shading space
pub fn cos_phi(v: &Vector) -> f32 {
    let sin_theta = sin_theta(v);
    if sin_theta == 0.0 {
        1.0
    } else {
        linalg::clamp(v.x / sin_theta, -1.0, 1.0)
    }
}
/// Compute the value of sine phi for a vector in shading space
pub fn sin_phi(v: &Vector) -> f32 {
    let sin_theta = sin_theta(v);
    if sin_theta == 0.0 {
        0.0
    } else {
        linalg::clamp(v.y / sin_theta, -1.0, 1.0)
    }
}
/// Check if two vectors are in the same hemisphere in shading space
pub fn same_hemisphere(a: &Vector, b: &Vector) -> bool { a.z * b.z > 0.0 }

<|endoftext|>


<commit_before>
/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_clear_rgba(&self) -> bool { false }

    /// Clears background with a color.
    fn clear_rgba(&mut self, _r: f64, _g: f64, _b: f64, _a: f64) {}

    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba_f64(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba_f64(&mut self, _vertices: &[f64], _colors: &[f64]) {}

    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba_f32(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba_f32(&mut self, _vertices: &[f32], _colors: &[f32]) {}
}
<commit_msg>Changed to f32 for clear_rgba<commit_after>
/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_clear_rgba(&self) -> bool { false }

    /// Clears background with a color.
    fn clear_rgba(&mut self, _r: f32, _g: f32, _b: f32, _a: f32) {}

    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba_f64(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba_f64(&mut self, _vertices: &[f64], _colors: &[f64]) {}

    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba_f32(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba_f32(&mut self, _vertices: &[f32], _colors: &[f32]) {}
}
<|endoftext|>


<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

#[derive(Debug)]
pub struct Block { data: Vec<u8>, }

impl Block {

    pub fn from_bytes(bytes: &[u8]) -> Block {
        Block { data: Vec::from(bytes) }
    }

    pub fn is_bin_header(&self) -> bool {
        self.data.len() >= 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() {
            let name = &self.data[10..16];
            let mut last = 6;
            for i in (0..6).rev() {
                if name[i] == 0 { last = i }
            }
            from_utf8(&name[..last]).ok()
        }
        else { None }
    }
}

#[derive(Debug, PartialEq)]
pub enum File<'a> {
	Bin(String, usize, usize, usize, &'a[u8]),
    Custom(&'a[u8])
}

pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {

    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, data));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(&block.data[..]));
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

impl Tape {

	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, IoError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Ok(Tape::from_bytes(&bytes[..]))
	}

	pub fn from_bytes(bytes: &[u8]) -> Tape {
		Tape { blocks: Tape::parse_blocks(bytes) }
	}

    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block::from_bytes(&bytes[from..to]);
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_detect_bin_header_block() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let block = Block::from_bytes(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_block_with_short_name() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let block = Block::from_bytes(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOO", block.file_name().unwrap());
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert_eq!(None, tape.files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes);
        for f in tape.files() {
            assert_bin!(&f,
                "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        }
    }
}
<commit_msg>Add doc comments to `tape` module<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

/// A block of data contained in a tape.
///
/// A tape file is comprised by a sequence of blocks. Each block starts with the prefix bytes
/// `1fa6debacc137d74` followed by the block data. The `Block` type stores the block data
/// without the prefix bytes.
///
#[derive(Debug)]
pub struct Block {
    data: Vec<u8>,
}

impl Block {

    /// Generates a new block from the data bytes (without the prefix bytes).
    pub fn from_data(bytes: &[u8]) -> Block {
        Block { data: Vec::from(bytes) }
    }

    /// Returns the block data (without the prefix bytes).
    pub fn data(&self) -> &[u8] { &self.data[..] }

    /// Returns `true` if the block is detected as a binary header.
    ///
    /// A bin header is comprised by `0xd0d0d0d0d0d0d0d0d0d0` followed by six bytes for
    /// the name of the binary file. This function returns `true` if the block data match
    /// this pattern, `false` otherwise.
    pub fn is_bin_header(&self) -> bool {
        self.data.len() == 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    /// Returns the file name in case of a binary, ascii or basic header, `None` otherwise.
    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() {
            let name = &self.data[10..16];
            let mut last = 6;
            for i in (0..6).rev() {
                if name[i] == 0 { last = i }
            }
            from_utf8(&name[..last]).ok()
        }
        else { None }
    }
}

/// A file contained in a tape
///
/// Files stored in a tape can be one of:
/// * Binary files. They contain binary code and/or data. They are loaded using `BLOAD`
///   instruction from Basic.
/// * ASCII files. They contain text, typically corresponding to Basic source code. They are
///   loaded using `LOAD` instruction from Basic.
/// * Basic files. They contain tokenized Basic, a compact form of Basic source code. They are
///   loaded using `CLOAD` instruction from Basic.
/// * Custom files. They contain arbitrary data generated by a program using direct calls to
///   casette IO addresses. Its contents cannot be processed from Basic but loaded from the
///   program that generates them in a custom way.
///
/// `File` instances are generated in iteration from `files()` function of `Tape` type.
///
#[derive(Debug, PartialEq)]
pub enum File<'a> {
	Bin(String, usize, usize, usize, &'a[u8]),
    Custom(&'a[u8])
}

/// An iterator over the files of a `Tape`
pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {

    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, data));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(&block.data[..]));
            }
        }
        None
    }
}

/// An MSX tape.
///
/// A tape is a sequence of byte blocks (see `Blocks` for more details). The blocks may be
/// grouped such as the tape is seen as a sequence of files through `files()` method.
///
#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

impl Tape {

    /// Read a `Tape` instance from the given `Read` object.
    ///
    /// This function returns a new `Tape` instance as result of processing the
    /// contents of the `Read` passed as argument (e.g., a file), or an `std::io::Error`
    /// if there is an error while reading.
    ///
	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, IoError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Ok(Tape::from_bytes(&bytes[..]))
	}

    /// Read a `Tape` instance from the given bytes.
    ///
    /// This function returns a new `Tape` instance as result of processing the bytes passed
    /// as argument.
	pub fn from_bytes(bytes: &[u8]) -> Tape {
		Tape { blocks: Tape::parse_blocks(bytes) }
	}

    /// Return the files contained in the tape.
    ///
    /// This function returns an `Iterator` over the files found in the tape blocks.
    ///
    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block::from_data(&bytes[from..to]);
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_detect_bin_header_block() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_block_with_short_name() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
        ];
        let block = Block::from_data(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOO", block.file_name().unwrap());
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert_eq!(None, tape.files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes);
        for f in tape.files() {
            assert_bin!(&f,
                "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::time::Duration;

use disque::Disque;
use redis::{RedisResult, Iter, Value};

/// Helper to add a new job
///
/// # Examples
///
/// ```
/// # use disque::Disque;
/// # use disque::AddJobBuilder;
///
/// let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
/// let jobid = AddJobBuilder::new(b"example queue", b"my job", 10000
///     ).delay(1440).run(&disque).unwrap();
/// ```
pub struct AddJobBuilder<'a> {
    queue_name: &'a [u8],
    job: &'a [u8],
    timeout: Duration,
    replicate: Option<usize>,
    delay: Option<Duration>,
    retry: Option<Duration>,
    ttl: Option<Duration>,
    maxlen: Option<usize>,
    async: bool,
}

impl<'a> AddJobBuilder<'a> {
    /// Creates a new builder for `queue_name`.
    /// Timeout is specified in milliseconds.
    pub fn new(queue_name: &'a [u8], job: &'a [u8], timeout_ms: u64
            ) -> AddJobBuilder<'a> {
        AddJobBuilder {
            queue_name: queue_name,
            job: job,
            timeout: Duration::from_millis(timeout_ms),
            replicate: None,
            delay: None,
            retry: None,
            ttl: None,
            maxlen: None,
            async: false,
        }
    }

    /// Changes the queue name where the job will be added.
    pub fn queue_name(&mut self, queue_name: &'a [u8]) -> &mut Self {
        self.queue_name = queue_name; self
    }

    /// Changes the job body.
    pub fn job(&mut self, job: &'a [u8]) -> &mut Self {
        self.job = job; self
    }

    /// Changes the timeout. It must be specified in milliseconds.
    pub fn timeout(&mut self, timeout_ms: u64) -> &mut Self {
        self.timeout = Duration::from_millis(timeout_ms); self
    }

    /// The number of nodes the job should be replicated to.
    pub fn replicate(&mut self, replicate: usize) -> &mut Self {
        self.replicate = Some(replicate); self
    }

    /// The number of seconds that should elapse before the job is queued.
    pub fn delay(&mut self, delay: u64) -> &mut Self {
        self.delay = Some(Duration::from_secs(delay)); self
    }

    /// Period after which, if no ACK is received, the job is put again
    /// into the queue for delivery
    pub fn retry(&mut self, retry: u64) -> &mut Self {
        self.retry = Some(Duration::from_secs(retry)); self
    }

    /// The max job life in seconds. After this time, the job is deleted even
    /// if it was not successfully delivered.
    pub fn ttl(&mut self, ttl: u64) -> &mut Self {
        self.ttl = Some(Duration::from_secs(ttl)); self
    }

    /// If there are already count messages queued for the specified queue
    /// name, the message is refused and an error reported to the client.
    pub fn maxlen(&mut self, maxlen: usize) -> &mut Self {
        self.maxlen = Some(maxlen); self
    }

    /// If true, asks the server to let the command return ASAP and replicate
    /// the job to other nodes in the background.
    /// Otherwise, the job is put into the queue only when the client gets a
    /// positive reply.
    pub fn async(&mut self, async: bool) -> &mut Self {
        self.async = async; self
    }

    /// Executes the addjob command.
    pub fn run(&self, disque: &Disque) -> RedisResult<String> {
        disque.addjob(self.queue_name, self.job, self.timeout, self.replicate,
                self.delay, self.retry, self.ttl, self.maxlen, self.async)
    }
}

#[test]
fn add_job_builder() {
    let mut jb = AddJobBuilder::new(b"queue", b"job", 123);
    assert_eq!(jb.queue_name, b"queue");
    assert_eq!(jb.job, b"job");
    assert_eq!(jb.timeout, Duration::from_millis(123));
    assert_eq!(jb.replicate, None);
    assert_eq!(jb.delay, None);
    assert_eq!(jb.retry, None);
    assert_eq!(jb.ttl, None);
    assert_eq!(jb.maxlen, None);
    assert_eq!(jb.async, false);
    jb.replicate(3).delay(4).retry(5).ttl(6).maxlen(7).async(true);
    assert_eq!(jb.queue_name, b"queue");
    assert_eq!(jb.job, b"job");
    assert_eq!(jb.timeout, Duration::from_millis(123));
    assert_eq!(jb.replicate, Some(3));
    assert_eq!(jb.delay, Some(Duration::from_secs(4)));
    assert_eq!(jb.retry, Some(Duration::from_secs(5)));
    assert_eq!(jb.ttl, Some(Duration::from_secs(6)));
    assert_eq!(jb.maxlen, Some(7));
    assert_eq!(jb.async, true);
    jb.queue_name(b"my queue").job(b"my job").timeout(234);
    assert_eq!(jb.queue_name, b"my queue");
    assert_eq!(jb.job, b"my job");
    assert_eq!(jb.timeout, Duration::from_millis(234));
    assert_eq!(jb.replicate, Some(3));
    assert_eq!(jb.delay, Some(Duration::from_secs(4)));
    assert_eq!(jb.retry, Some(Duration::from_secs(5)));
    assert_eq!(jb.ttl, Some(Duration::from_secs(6)));
    assert_eq!(jb.maxlen, Some(7));
    assert_eq!(jb.async, true);
}

/// Helper to get a list of queues
///
/// # Examples
///
/// ```
/// # use disque::Disque;
/// # use disque::QueueQueryBuilder;
///
/// let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
/// let queues = QueueQueryBuilder::new().busyloop(true).minlen(50)
///     .iter(&disque).unwrap().collect::<Vec<_>>();
/// assert!(queues.len() >= 0);
/// ```
pub struct QueueQueryBuilder {
    count: u64,
    busyloop: bool,
    minlen: Option<u64>,
    maxlen: Option<u64>,
    importrate: Option<u64>,
}

impl QueueQueryBuilder {
    /// Creates a new builder.
    pub fn new() -> QueueQueryBuilder {
        QueueQueryBuilder {
            count: 16,
            busyloop: false,
            minlen: None,
            maxlen: None,
            importrate: None,
        }
    }

    /// A hint about how much work to do per iteration.
    pub fn count(&mut self, count: u64) -> &mut Self {
        self.count = count; self
    }

    /// If true, blocks and returns all the queues in a busy loop.
    pub fn busyloop(&mut self, busyloop: bool) -> &mut Self {
        self.busyloop = busyloop; self
    }

    /// Only return queues with at least `minlen` jobs.
    pub fn minlen(&mut self, minlen: u64) -> &mut Self {
        self.minlen = Some(minlen); self
    }

    /// Only return queues with at most `maxlen` jobs.
    pub fn maxlen(&mut self, maxlen: u64) -> &mut Self {
        self.maxlen = Some(maxlen); self
    }

    /// Only return queues with a job import rate (from other nodes) greater
    /// than or equal to  `importrate`.
    pub fn importrate(&mut self, importrate: u64) -> &mut Self {
        self.importrate = Some(importrate); self
    }

    /// Gets the queue iterator.
    pub fn iter<'a>(&'a self, disque: &'a Disque) -> RedisResult<Iter<Vec<u8>>> {
        disque.qscan(0, self.count, self.busyloop, self.minlen, self.maxlen,
                self.importrate)
    }
}

#[test]
fn queue_query_builder() {
    let mut qqb = QueueQueryBuilder::new();
    assert_eq!(qqb.count, 16);
    assert_eq!(qqb.busyloop, false);
    assert_eq!(qqb.minlen, None);
    assert_eq!(qqb.maxlen, None);
    assert_eq!(qqb.importrate, None);
    qqb.count(11).busyloop(true).minlen(1).maxlen(10).importrate(5);
    assert_eq!(qqb.count, 11);
    assert_eq!(qqb.busyloop, true);
    assert_eq!(qqb.minlen, Some(1));
    assert_eq!(qqb.maxlen, Some(10));
    assert_eq!(qqb.importrate, Some(5));
}

/// Helper to get a list of jobs
///
/// # Examples
///
/// ```
/// # use disque::Disque;
/// # use disque::JobQueryBuilder;
///
/// let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
/// let jobs = JobQueryBuilder::new().queue(b"my queue").state("queued")
///     .iter_ids(&disque).unwrap().collect::<Vec<_>>();
/// assert!(jobs.len() >= 0);
/// ```
pub struct JobQueryBuilder<'a> {
    count: u64,
    blocking: bool,
    queue: Option<&'a [u8]>,
    states: Vec<&'a str>,
}

impl<'a> JobQueryBuilder<'a> {
    pub fn new() -> JobQueryBuilder<'a> {
        JobQueryBuilder {
            count: 16,
            blocking: false,
            queue: None,
            states: vec![],
        }
    }

    pub fn count(&mut self, count: u64) -> &mut Self {
        self.count = count; self
    }

    pub fn blocking(&mut self, blocking: bool) -> &mut Self {
        self.blocking = blocking; self
    }

    pub fn queue(&mut self, queue: &'a [u8]) -> &mut Self {
        self.queue = Some(queue); self
    }

    pub fn state(&mut self, state: &'a str) -> &mut Self {
        self.states.push(state); self
    }

    /// Gets a job ids iterator.
    pub fn iter_ids<'b>(&'b self, disque: &'b Disque
            ) -> RedisResult<Iter<String>> {
        disque.jscan_id(0, self.count, self.blocking, self.queue,
                &*self.states)
    }

    /// Gets a job information iterator.
    pub fn iter_all<'b>(&'b self, disque: &'b Disque
            ) -> RedisResult<Iter<HashMap<String, Value>>> {
        disque.jscan_all(0, self.count, self.blocking, self.queue,
                &*self.states)
    }
}

#[test]
fn job_query_builder() {
    let mut jqb = JobQueryBuilder::new();
    assert_eq!(jqb.count, 16);
    assert_eq!(jqb.blocking, false);
    assert_eq!(jqb.queue, None);
    assert_eq!(jqb.states.len(), 0);
    jqb.count(20).blocking(true).queue(b"jqb queue").state("state1"
            ).state("state2");
    assert_eq!(jqb.count, 20);
    assert_eq!(jqb.blocking, true);
    assert_eq!(jqb.queue, Some(b"jqb queue" as &[u8]));
    assert_eq!(jqb.states, vec!["state1", "state2"]);
}
<commit_msg>Add comments<commit_after>use std::collections::HashMap;
use std::time::Duration;

use disque::Disque;
use redis::{RedisResult, Iter, Value};

/// Helper to add a new job
///
/// # Examples
///
/// ```
/// # use disque::Disque;
/// # use disque::AddJobBuilder;
///
/// let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
/// let jobid = AddJobBuilder::new(b"example queue", b"my job", 10000
///     ).delay(1440).run(&disque).unwrap();
/// ```
pub struct AddJobBuilder<'a> {
    queue_name: &'a [u8],
    job: &'a [u8],
    timeout: Duration,
    replicate: Option<usize>,
    delay: Option<Duration>,
    retry: Option<Duration>,
    ttl: Option<Duration>,
    maxlen: Option<usize>,
    async: bool,
}

impl<'a> AddJobBuilder<'a> {
    /// Creates a new builder for `queue_name`.
    /// Timeout is specified in milliseconds.
    pub fn new(queue_name: &'a [u8], job: &'a [u8], timeout_ms: u64
            ) -> AddJobBuilder<'a> {
        AddJobBuilder {
            queue_name: queue_name,
            job: job,
            timeout: Duration::from_millis(timeout_ms),
            replicate: None,
            delay: None,
            retry: None,
            ttl: None,
            maxlen: None,
            async: false,
        }
    }

    /// Changes the queue name where the job will be added.
    pub fn queue_name(&mut self, queue_name: &'a [u8]) -> &mut Self {
        self.queue_name = queue_name; self
    }

    /// Changes the job body.
    pub fn job(&mut self, job: &'a [u8]) -> &mut Self {
        self.job = job; self
    }

    /// Changes the timeout. It must be specified in milliseconds.
    pub fn timeout(&mut self, timeout_ms: u64) -> &mut Self {
        self.timeout = Duration::from_millis(timeout_ms); self
    }

    /// The number of nodes the job should be replicated to.
    pub fn replicate(&mut self, replicate: usize) -> &mut Self {
        self.replicate = Some(replicate); self
    }

    /// The number of seconds that should elapse before the job is queued.
    pub fn delay(&mut self, delay: u64) -> &mut Self {
        self.delay = Some(Duration::from_secs(delay)); self
    }

    /// Period after which, if no ACK is received, the job is put again
    /// into the queue for delivery
    pub fn retry(&mut self, retry: u64) -> &mut Self {
        self.retry = Some(Duration::from_secs(retry)); self
    }

    /// The max job life in seconds. After this time, the job is deleted even
    /// if it was not successfully delivered.
    pub fn ttl(&mut self, ttl: u64) -> &mut Self {
        self.ttl = Some(Duration::from_secs(ttl)); self
    }

    /// If there are already count messages queued for the specified queue
    /// name, the message is refused and an error reported to the client.
    pub fn maxlen(&mut self, maxlen: usize) -> &mut Self {
        self.maxlen = Some(maxlen); self
    }

    /// If true, asks the server to let the command return ASAP and replicate
    /// the job to other nodes in the background.
    /// Otherwise, the job is put into the queue only when the client gets a
    /// positive reply.
    pub fn async(&mut self, async: bool) -> &mut Self {
        self.async = async; self
    }

    /// Executes the addjob command.
    pub fn run(&self, disque: &Disque) -> RedisResult<String> {
        disque.addjob(self.queue_name, self.job, self.timeout, self.replicate,
                self.delay, self.retry, self.ttl, self.maxlen, self.async)
    }
}

#[test]
fn add_job_builder() {
    let mut jb = AddJobBuilder::new(b"queue", b"job", 123);
    assert_eq!(jb.queue_name, b"queue");
    assert_eq!(jb.job, b"job");
    assert_eq!(jb.timeout, Duration::from_millis(123));
    assert_eq!(jb.replicate, None);
    assert_eq!(jb.delay, None);
    assert_eq!(jb.retry, None);
    assert_eq!(jb.ttl, None);
    assert_eq!(jb.maxlen, None);
    assert_eq!(jb.async, false);
    jb.replicate(3).delay(4).retry(5).ttl(6).maxlen(7).async(true);
    assert_eq!(jb.queue_name, b"queue");
    assert_eq!(jb.job, b"job");
    assert_eq!(jb.timeout, Duration::from_millis(123));
    assert_eq!(jb.replicate, Some(3));
    assert_eq!(jb.delay, Some(Duration::from_secs(4)));
    assert_eq!(jb.retry, Some(Duration::from_secs(5)));
    assert_eq!(jb.ttl, Some(Duration::from_secs(6)));
    assert_eq!(jb.maxlen, Some(7));
    assert_eq!(jb.async, true);
    jb.queue_name(b"my queue").job(b"my job").timeout(234);
    assert_eq!(jb.queue_name, b"my queue");
    assert_eq!(jb.job, b"my job");
    assert_eq!(jb.timeout, Duration::from_millis(234));
    assert_eq!(jb.replicate, Some(3));
    assert_eq!(jb.delay, Some(Duration::from_secs(4)));
    assert_eq!(jb.retry, Some(Duration::from_secs(5)));
    assert_eq!(jb.ttl, Some(Duration::from_secs(6)));
    assert_eq!(jb.maxlen, Some(7));
    assert_eq!(jb.async, true);
}

/// Helper to get a list of queues
///
/// # Examples
///
/// ```
/// # use disque::Disque;
/// # use disque::QueueQueryBuilder;
///
/// let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
/// let queues = QueueQueryBuilder::new().busyloop(true).minlen(50)
///     .iter(&disque).unwrap().collect::<Vec<_>>();
/// assert!(queues.len() >= 0);
/// ```
pub struct QueueQueryBuilder {
    count: u64,
    busyloop: bool,
    minlen: Option<u64>,
    maxlen: Option<u64>,
    importrate: Option<u64>,
}

impl QueueQueryBuilder {
    /// Creates a new builder.
    pub fn new() -> QueueQueryBuilder {
        QueueQueryBuilder {
            count: 16,
            busyloop: false,
            minlen: None,
            maxlen: None,
            importrate: None,
        }
    }

    /// A hint about how much work to do per iteration.
    pub fn count(&mut self, count: u64) -> &mut Self {
        self.count = count; self
    }

    /// If true, blocks and returns all the queues in a busy loop.
    pub fn busyloop(&mut self, busyloop: bool) -> &mut Self {
        self.busyloop = busyloop; self
    }

    /// Only return queues with at least `minlen` jobs.
    pub fn minlen(&mut self, minlen: u64) -> &mut Self {
        self.minlen = Some(minlen); self
    }

    /// Only return queues with at most `maxlen` jobs.
    pub fn maxlen(&mut self, maxlen: u64) -> &mut Self {
        self.maxlen = Some(maxlen); self
    }

    /// Only return queues with a job import rate (from other nodes) greater
    /// than or equal to  `importrate`.
    pub fn importrate(&mut self, importrate: u64) -> &mut Self {
        self.importrate = Some(importrate); self
    }

    /// Gets the queue iterator.
    pub fn iter<'a>(&'a self, disque: &'a Disque) -> RedisResult<Iter<Vec<u8>>> {
        disque.qscan(0, self.count, self.busyloop, self.minlen, self.maxlen,
                self.importrate)
    }
}

#[test]
fn queue_query_builder() {
    let mut qqb = QueueQueryBuilder::new();
    assert_eq!(qqb.count, 16);
    assert_eq!(qqb.busyloop, false);
    assert_eq!(qqb.minlen, None);
    assert_eq!(qqb.maxlen, None);
    assert_eq!(qqb.importrate, None);
    qqb.count(11).busyloop(true).minlen(1).maxlen(10).importrate(5);
    assert_eq!(qqb.count, 11);
    assert_eq!(qqb.busyloop, true);
    assert_eq!(qqb.minlen, Some(1));
    assert_eq!(qqb.maxlen, Some(10));
    assert_eq!(qqb.importrate, Some(5));
}

/// Helper to get a list of jobs
///
/// # Examples
///
/// ```
/// # use disque::Disque;
/// # use disque::JobQueryBuilder;
///
/// let disque = Disque::open("redis://127.0.0.1:7711/").unwrap();
/// let jobs = JobQueryBuilder::new().queue(b"my queue").state("queued")
///     .iter_ids(&disque).unwrap().collect::<Vec<_>>();
/// assert!(jobs.len() >= 0);
/// ```
pub struct JobQueryBuilder<'a> {
    count: u64,
    busyloop: bool,
    queue: Option<&'a [u8]>,
    states: Vec<&'a str>,
}

impl<'a> JobQueryBuilder<'a> {
    pub fn new() -> JobQueryBuilder<'a> {
        JobQueryBuilder {
            count: 16,
            busyloop: false,
            queue: None,
            states: vec![],
        }
    }

    /// A hint about how much work to do per iteration.
    pub fn count(&mut self, count: u64) -> &mut Self {
        self.count = count; self
    }

    /// Block and return all the elements in a busy loop.
    pub fn busyloop(&mut self, busyloop: bool) -> &mut Self {
        self.busyloop = busyloop; self
    }

    /// Only get jobs in the specified queue.
    pub fn queue(&mut self, queue: &'a [u8]) -> &mut Self {
        self.queue = Some(queue); self
    }

    /// Only return jobs in specified states. Can be called multiple times to
    /// get jobs in any of those states.
    pub fn state(&mut self, state: &'a str) -> &mut Self {
        self.states.push(state); self
    }

    /// Gets a job ids iterator.
    pub fn iter_ids<'b>(&'b self, disque: &'b Disque
            ) -> RedisResult<Iter<String>> {
        disque.jscan_id(0, self.count, self.busyloop, self.queue,
                &*self.states)
    }

    /// Gets a job information iterator.
    pub fn iter_all<'b>(&'b self, disque: &'b Disque
            ) -> RedisResult<Iter<HashMap<String, Value>>> {
        disque.jscan_all(0, self.count, self.busyloop, self.queue,
                &*self.states)
    }
}

#[test]
fn job_query_builder() {
    let mut jqb = JobQueryBuilder::new();
    assert_eq!(jqb.count, 16);
    assert_eq!(jqb.busyloop, false);
    assert_eq!(jqb.queue, None);
    assert_eq!(jqb.states.len(), 0);
    jqb.count(20).busyloop(true).queue(b"jqb queue").state("state1"
            ).state("state2");
    assert_eq!(jqb.count, 20);
    assert_eq!(jqb.busyloop, true);
    assert_eq!(jqb.queue, Some(b"jqb queue" as &[u8]));
    assert_eq!(jqb.states, vec!["state1", "state2"]);
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use capstone_rust::capstone;
use super::address::Address;
use super::instruction::Instruction;

impl Instruction for capstone::Instr {
    fn address(&self) -> Address {
        Address::new(self.address)
    }

    fn comment(&self) -> Option<String> {
        None
    }

    fn cycle_count(&self) -> Option<u32> {
        None
    }

    fn is_call(&self) -> bool {
        false
    }

    fn is_local_conditional_jump(&self) -> bool {
        false
    }

    fn is_local_jump(&self) -> bool {
        false
    }

    fn is_return(&self) -> bool {
        false
    }

    fn target_address(&self) -> Option<Address> {
        None
    }
}
<commit_msg>Implementation of x86 capstone backend for Instruction.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use capstone_rust::capstone;
use capstone_rust::capstone_sys::{x86_insn, x86_insn_group};
use super::address::Address;
use super::instruction::Instruction;

fn is_group_match<F>(i: &capstone::Instr, predicate: F) -> bool
where
    F: Fn(&&u32) -> bool,
{
    match i.detail {
        None => false,
        Some(ref detail) => {
            match i.id {
                capstone::InstrIdArch::X86(_) => {
                    match detail.groups.iter().find(predicate) {
                        Some(_) => true,
                        None => false,
                    }
                }
                _ => false, // XXX Not supported yet
            }
        }
    }
}

impl Instruction for capstone::Instr {
    fn address(&self) -> Address {
        Address::new(self.address)
    }

    fn comment(&self) -> Option<String> {
        None
    }

    fn cycle_count(&self) -> Option<u32> {
        None
    }

    fn is_call(&self) -> bool {
        is_group_match(self, |&&x| x == x86_insn_group::X86_GRP_CALL.as_int())
    }

    fn is_local_conditional_jump(&self) -> bool {
        self.is_local_jump() &&
            match self.id {
                capstone::InstrIdArch::X86(x86_insn::X86_INS_JMP) => false,
                capstone::InstrIdArch::X86(x86_insn::X86_INS_LOOP) => false,
                capstone::InstrIdArch::X86(x86_insn::X86_INS_LOOPE) => false,
                capstone::InstrIdArch::X86(x86_insn::X86_INS_LOOPNE) => false,
                capstone::InstrIdArch::X86(x86_insn::X86_INS_XBEGIN) => false,
                capstone::InstrIdArch::X86(_) => true,
                _ => false, // XXX Not supported yet
            }
    }

    fn is_local_jump(&self) -> bool {
        is_group_match(self, |&&x| x == x86_insn_group::X86_GRP_JUMP.as_int()) &&
            match self.id {
                capstone::InstrIdArch::X86(x86_insn::X86_INS_LJMP) => false,
                capstone::InstrIdArch::X86(_) => true,
                _ => false, // XXX Not supported yet
            }
    }

    fn is_return(&self) -> bool {
        is_group_match(self, |&&x| x == x86_insn_group::X86_GRP_RET.as_int())
    }

    fn target_address(&self) -> Option<Address> {
        None
    }
}
<|endoftext|>


<commit_before>use std::slice;

use binding::vm;
use class::object;
use types;

pub struct VM;

impl VM {
    pub fn init() {
        vm::init();
    }

    pub fn parse_arguments(argc: types::argc, arguments: *const types::rb_value) -> Vec<object::Object> {
        let arguments = unsafe {
            slice::from_raw_parts(arguments, argc as usize).to_vec()
        };

        arguments.iter().map(|value| object::Object::from(*value)).collect()
    }
}
<commit_msg>Create VM::parse_itself()<commit_after>use std::slice;

use binding::vm;
use class::object;
use types;

pub struct VM;

impl VM {
    pub fn init() {
        vm::init();
    }

    pub fn parse_arguments(argc: types::argc, arguments: *const types::rb_value) -> Vec<object::Object> {
        let arguments = unsafe {
            slice::from_raw_parts(arguments, argc as usize).to_vec()
        };

        arguments.iter().map(|value| object::Object::from(*value)).collect()
    }

    pub fn parse_itself(itself: types::rb_value) -> object::Object {
        object::Object::from(itself)
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<'a, HP>(&self, f: File, p: &Parser<HP>) ->
        Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let written = p.write(f.contents());
        if let Ok(string) = written {
            let path = self.build_filepath(&f);
            debug!("Writing file: {}", path);
            debug!("    contents: {}", string);
            Ok(Ok(()))
        } else {
            debug!("Error parsing : {:?}", f.contents());
            Err(written.err().unwrap())
        }
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<'a, HP>(&self, f: File, p: &Parser<HP>)
        -> Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let contents = p.write(f.contents());

        if contents.is_err() {
            debug!("Error parsing contents: {:?}", f.contents());
            return Err(contents.err().unwrap());
        }

        let content = contents.unwrap();
        debug!("Success parsing content : {}", content);

        let path = self.build_filepath(&f);
        debug!("Trying to write to file at {}", path);
        if let Err(_) = FSFile::open(&path) {
            debug!("Error opening {}", path);
            return Ok(Err(StorageBackendError::new(
                String::from("File::open()"),
                format!("Tried to open '{}'", path),
                String::from("Tried to update contents of this file, though file doesn't exist"),
                None)))
        }

        if let Ok(mut file) = FSFile::create(&path) {
            if let Err(writeerr) = file.write_all(&content.clone().into_bytes()) {
                debug!("Error writing to {}", path);
                return Ok(Err(StorageBackendError::new(
                    String::from("File::write()"),
                    format!("Tried to write '{}'", path),
                    String::from("Tried to write contents of this file, though operation did not succeed"),
                    Some(content))))
            }
        }

        debug!("Successfully written to file.");
        Ok(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, id: FileID, p: &Parser<HP>) -> Option<File>
        where HP: FileHeaderParser<'a>
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.id())
    }

    fn build_filepath_with_id(&self, id: FileID) -> String {
        debug!("Building filepath for id '{}'", id);
        self.basepath.clone() + &id[..]
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }
}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

<commit_msg>Implement StorageBackendError::build() helper<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<'a, HP>(&self, f: File, p: &Parser<HP>) ->
        Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let written = p.write(f.contents());
        if let Ok(string) = written {
            let path = self.build_filepath(&f);
            debug!("Writing file: {}", path);
            debug!("    contents: {}", string);
            Ok(Ok(()))
        } else {
            debug!("Error parsing : {:?}", f.contents());
            Err(written.err().unwrap())
        }
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<'a, HP>(&self, f: File, p: &Parser<HP>)
        -> Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let contents = p.write(f.contents());

        if contents.is_err() {
            debug!("Error parsing contents: {:?}", f.contents());
            return Err(contents.err().unwrap());
        }

        let content = contents.unwrap();
        debug!("Success parsing content : {}", content);

        let path = self.build_filepath(&f);
        debug!("Trying to write to file at {}", path);
        if let Err(_) = FSFile::open(&path) {
            debug!("Error opening {}", path);
            return Ok(Err(StorageBackendError::new(
                String::from("File::open()"),
                format!("Tried to open '{}'", path),
                String::from("Tried to update contents of this file, though file doesn't exist"),
                None)))
        }

        if let Ok(mut file) = FSFile::create(&path) {
            if let Err(writeerr) = file.write_all(&content.clone().into_bytes()) {
                debug!("Error writing to {}", path);
                return Ok(Err(StorageBackendError::new(
                    String::from("File::write()"),
                    format!("Tried to write '{}'", path),
                    String::from("Tried to write contents of this file, though operation did not succeed"),
                    Some(content))))
            }
        }

        debug!("Successfully written to file.");
        Ok(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, id: FileID, p: &Parser<HP>) -> Option<File>
        where HP: FileHeaderParser<'a>
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.id())
    }

    fn build_filepath_with_id(&self, id: FileID) -> String {
        debug!("Building filepath for id '{}'", id);
        self.basepath.clone() + &id[..]
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

<|endoftext|>


<commit_before>//! Consumer implementations.
extern crate librdkafka_sys as rdkafka;
extern crate futures;

use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use std::thread;

use self::futures::Future;
use self::futures::stream;
use self::futures::stream::{Receiver, Sender};

use config::{FromClientConfig, ClientConfig};
use error::{KafkaError, KafkaResult};
use message::Message;

pub use consumer::{ConsumerClient, Consumer, Mode};

/// A Consumer with an associated polling thread. This consumer doesn't need to
/// be polled and it will return all consumed messages as a `Stream`.
#[must_use = "Consumer polling thread will stop immediately if unused"]
pub struct StreamConsumer {
    consumer: Arc<ConsumerClient>,
    should_stop: Arc<AtomicBool>,
    handle: Option<JoinHandle<()>>,
}

/// Creates a new Consumer starting from a ClientConfig.
impl FromClientConfig for StreamConsumer {
    fn from_config(config: &ClientConfig) -> KafkaResult<StreamConsumer> {
        let stream_consumer = StreamConsumer {
            consumer: Arc::new(try!(ConsumerClient::from_config(config))),
            should_stop: Arc::new(AtomicBool::new(false)),
            handle: None,
        };
        Ok(stream_consumer)
    }
}

impl Consumer for StreamConsumer {
    fn get_consumer(&self) -> &ConsumerClient {
        Arc::as_ref(&self.consumer)
    }

    fn get_consumer_mut(&mut self) -> &mut ConsumerClient {
        Arc::get_mut(&mut self.consumer).unwrap()  // TODO add check?
    }
}

impl StreamConsumer {
    pub fn start(&mut self) -> Receiver<Message, KafkaError> {
        let (sender, receiver) = stream::channel();
        let consumer = self.consumer.clone();
        let should_stop = self.should_stop.clone();
        // let mut sender = self.sender.take().expect("Sender is missing");
        let handle = thread::Builder::new()
            .name("polling thread".to_string())
            .spawn(move || {
                poll_loop(consumer, sender, should_stop);
            })
            .expect("Failed to start polling thread");
        self.handle = Some(handle);
        receiver
    }

    pub fn stop(&mut self) {
        if self.handle.is_some() {
            trace!("Stopping polling");
            self.should_stop.store(true, Ordering::Relaxed);
            trace!("Waiting for polling thread termination");
            match self.handle.take().unwrap().join() {
                Ok(()) => trace!("Polling stopped"),
                Err(e) => warn!("Failure while terminating thread: {:?}", e),
            };
        }
    }
}

impl Drop for StreamConsumer {
    fn drop(&mut self) {
        trace!("Destroy ConsumerPollingThread");
        self.stop();
    }
}

fn poll_loop(consumer: Arc<ConsumerClient>, sender: Sender<Message, KafkaError>, should_stop: Arc<AtomicBool>) {
    trace!("Polling thread loop started");
    let mut curr_sender = sender;
    while !should_stop.load(Ordering::Relaxed) {
        let future_sender = match consumer.poll(100) {
            Ok(None) => continue,
            Ok(Some(m)) => curr_sender.send(Ok(m)),
            Err(e) => curr_sender.send(Err(e)),
        };
        match future_sender.wait() {
            Ok(new_sender) => curr_sender = new_sender,
            Err(e) => {
                debug!("Sender not available: {:?}", e);
                break;
            }
        };
    }
    trace!("Polling thread loop terminated");
}
<commit_msg>Fix build after rdkakfa-sys renaming<commit_after>//! Consumer implementations.
extern crate rdkafka_sys as rdkafka;
extern crate futures;

use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use std::thread;

use self::futures::Future;
use self::futures::stream;
use self::futures::stream::{Receiver, Sender};

use config::{FromClientConfig, ClientConfig};
use error::{KafkaError, KafkaResult};
use message::Message;

pub use consumer::{ConsumerClient, Consumer, Mode};

/// A Consumer with an associated polling thread. This consumer doesn't need to
/// be polled and it will return all consumed messages as a `Stream`.
#[must_use = "Consumer polling thread will stop immediately if unused"]
pub struct StreamConsumer {
    consumer: Arc<ConsumerClient>,
    should_stop: Arc<AtomicBool>,
    handle: Option<JoinHandle<()>>,
}

/// Creates a new Consumer starting from a ClientConfig.
impl FromClientConfig for StreamConsumer {
    fn from_config(config: &ClientConfig) -> KafkaResult<StreamConsumer> {
        let stream_consumer = StreamConsumer {
            consumer: Arc::new(try!(ConsumerClient::from_config(config))),
            should_stop: Arc::new(AtomicBool::new(false)),
            handle: None,
        };
        Ok(stream_consumer)
    }
}

impl Consumer for StreamConsumer {
    fn get_consumer(&self) -> &ConsumerClient {
        Arc::as_ref(&self.consumer)
    }

    fn get_consumer_mut(&mut self) -> &mut ConsumerClient {
        Arc::get_mut(&mut self.consumer).unwrap()  // TODO add check?
    }
}

impl StreamConsumer {
    pub fn start(&mut self) -> Receiver<Message, KafkaError> {
        let (sender, receiver) = stream::channel();
        let consumer = self.consumer.clone();
        let should_stop = self.should_stop.clone();
        // let mut sender = self.sender.take().expect("Sender is missing");
        let handle = thread::Builder::new()
            .name("polling thread".to_string())
            .spawn(move || {
                poll_loop(consumer, sender, should_stop);
            })
            .expect("Failed to start polling thread");
        self.handle = Some(handle);
        receiver
    }

    pub fn stop(&mut self) {
        if self.handle.is_some() {
            trace!("Stopping polling");
            self.should_stop.store(true, Ordering::Relaxed);
            trace!("Waiting for polling thread termination");
            match self.handle.take().unwrap().join() {
                Ok(()) => trace!("Polling stopped"),
                Err(e) => warn!("Failure while terminating thread: {:?}", e),
            };
        }
    }
}

impl Drop for StreamConsumer {
    fn drop(&mut self) {
        trace!("Destroy ConsumerPollingThread");
        self.stop();
    }
}

fn poll_loop(consumer: Arc<ConsumerClient>, sender: Sender<Message, KafkaError>, should_stop: Arc<AtomicBool>) {
    trace!("Polling thread loop started");
    let mut curr_sender = sender;
    while !should_stop.load(Ordering::Relaxed) {
        let future_sender = match consumer.poll(100) {
            Ok(None) => continue,
            Ok(Some(m)) => curr_sender.send(Ok(m)),
            Err(e) => curr_sender.send(Err(e)),
        };
        match future_sender.wait() {
            Ok(new_sender) => curr_sender = new_sender,
            Err(e) => {
                debug!("Sender not available: {:?}", e);
                break;
            }
        };
    }
    trace!("Polling thread loop terminated");
}
<|endoftext|>