<commit_before>use byteorder::{LittleEndian, ReadBytesExt};
use rustc_serialize;
use std;
use super::error::Error;

pub struct Decoder<T>
    where T: std::io::Read
{
    input: T,
}

impl<T> Decoder<T>
    where T: std::io::Read
{
    pub fn new(data: T) -> Decoder<T> {
        Decoder { input: data }
    }

    pub fn pop_length(&mut self) -> Result<u32, std::io::Error> {
        self.input.read_u32::<LittleEndian>()
    }
}

macro_rules! match_length {
    ($s:expr, $x:expr) => (if $x != $s.pop_length()? {return Err(Error::Mismatch)});
}

impl<N> rustc_serialize::Decoder for Decoder<N>
    where N: std::io::Read
{
    type Error = Error;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        match_length!(self, 8);
        Ok(self.input.read_u64::<LittleEndian>()?)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        match_length!(self, 4);
        Ok(self.input.read_u32::<LittleEndian>()?)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        match_length!(self, 2);
        Ok(self.input.read_u16::<LittleEndian>()?)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        match_length!(self, 1);
        Ok(self.input.read_u8()?)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        match_length!(self, 8);
        Ok(self.input.read_i64::<LittleEndian>()?)
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match_length!(self, 4);
        Ok(self.input.read_i32::<LittleEndian>()?)
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match_length!(self, 2);
        Ok(self.input.read_i16::<LittleEndian>()?)
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match_length!(self, 1);
        Ok(self.input.read_i8()?)
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match_length!(self, 1);
        Ok(self.input.read_u8()? != 0)
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match_length!(self, 8);
        Ok(self.input.read_f64::<LittleEndian>()?)
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match_length!(self, 4);
        Ok(self.input.read_f32::<LittleEndian>()?)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        let length = self.pop_length()?;
        let mut buffer = vec![0; length as usize];
        self.input.read_exact(&mut buffer)?;
        String::from_utf8(buffer).or(Err(Error::UnsupportedData))
    }

    fn read_enum<T, F>(&mut self, _: &str, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_variant<T, F>(&mut self, _: &[&str], _: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_variant_arg<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], _: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            _: &str,
                                            _: usize,
                                            _: F)
                                            -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_struct<T, F>(&mut self, _: &str, len: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        self.read_tuple(len, f)
    }

    fn read_struct_field<T, F>(&mut self, _: &str, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        f(self)
    }

    fn read_tuple<T, F>(&mut self, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        self.pop_length()?;
        f(self)
    }

    fn read_tuple_arg<T, F>(&mut self, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        f(self)
    }

    fn read_tuple_struct<T, F>(&mut self, _: &str, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_option<T, F>(&mut self, _: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
        self.pop_length()?;
        let count = self.pop_length()? as usize;
        f(self, count)
    }

    fn read_seq_elt<T, F>(&mut self, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        f(self)
    }

    fn read_map<T, F>(&mut self, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_map_elt_key<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_map_elt_val<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        Error::Other(String::from(err))
    }
}
<commit_msg>Add tests to TCPROS decoder<commit_after>use byteorder::{LittleEndian, ReadBytesExt};
use rustc_serialize;
use std;
use super::error::Error;

pub struct Decoder<T>
    where T: std::io::Read
{
    input: T,
}

impl<T> Decoder<T>
    where T: std::io::Read
{
    pub fn new(data: T) -> Decoder<T> {
        Decoder { input: data }
    }

    pub fn pop_length(&mut self) -> Result<u32, std::io::Error> {
        self.input.read_u32::<LittleEndian>()
    }
}

macro_rules! match_length {
    ($s:expr, $x:expr) => (if $x != $s.pop_length()? {return Err(Error::Mismatch)});
}

impl<N> rustc_serialize::Decoder for Decoder<N>
    where N: std::io::Read
{
    type Error = Error;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        match_length!(self, 8);
        Ok(self.input.read_u64::<LittleEndian>()?)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        match_length!(self, 4);
        Ok(self.input.read_u32::<LittleEndian>()?)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        match_length!(self, 2);
        Ok(self.input.read_u16::<LittleEndian>()?)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        match_length!(self, 1);
        Ok(self.input.read_u8()?)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        match_length!(self, 8);
        Ok(self.input.read_i64::<LittleEndian>()?)
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match_length!(self, 4);
        Ok(self.input.read_i32::<LittleEndian>()?)
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match_length!(self, 2);
        Ok(self.input.read_i16::<LittleEndian>()?)
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match_length!(self, 1);
        Ok(self.input.read_i8()?)
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match_length!(self, 1);
        Ok(self.input.read_u8()? != 0)
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match_length!(self, 8);
        Ok(self.input.read_f64::<LittleEndian>()?)
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match_length!(self, 4);
        Ok(self.input.read_f32::<LittleEndian>()?)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(Error::UnsupportedData)
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        let length = self.pop_length()?;
        let mut buffer = vec![0; length as usize];
        self.input.read_exact(&mut buffer)?;
        String::from_utf8(buffer).or(Err(Error::UnsupportedData))
    }

    fn read_enum<T, F>(&mut self, _: &str, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_variant<T, F>(&mut self, _: &[&str], _: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_variant_arg<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_struct_variant<T, F>(&mut self, _: &[&str], _: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, usize) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self,
                                            _: &str,
                                            _: usize,
                                            _: F)
                                            -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_struct<T, F>(&mut self, _: &str, len: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        self.read_tuple(len, f)
    }

    fn read_struct_field<T, F>(&mut self, _: &str, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        f(self)
    }

    fn read_tuple<T, F>(&mut self, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        self.pop_length()?;
        f(self)
    }

    fn read_tuple_arg<T, F>(&mut self, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        f(self)
    }

    fn read_tuple_struct<T, F>(&mut self, _: &str, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_option<T, F>(&mut self, _: F) -> Result<T, Self::Error>
        where F: FnMut(&mut Self, bool) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
        self.pop_length()?;
        let count = self.pop_length()? as usize;
        f(self, count)
    }

    fn read_seq_elt<T, F>(&mut self, _: usize, f: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        f(self)
    }

    fn read_map<T, F>(&mut self, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_map_elt_key<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn read_map_elt_val<T, F>(&mut self, _: usize, _: F) -> Result<T, Self::Error>
        where F: FnOnce(&mut Self) -> Result<T, Self::Error>
    {
        Err(Error::UnsupportedData)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        Error::Other(String::from(err))
    }
}

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

    fn push_data(data: Vec<u8>) -> Decoder<std::io::Cursor<Vec<u8>>> {
        Decoder::new(std::io::Cursor::new(data))
    }

    #[test]
    fn pops_length_right() {
        let mut decoder = push_data(vec![4, 0, 0, 0, 2, 33, 17, 0]);
        assert_eq!(4, decoder.pop_length().unwrap());
        assert_eq!(1122562, decoder.pop_length().unwrap());
    }

    #[test]
    fn reads_u8() {
        let mut decoder = push_data(vec![1, 0, 0, 0, 150]);
        assert_eq!(150, u8::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_u16() {
        let mut decoder = push_data(vec![2, 0, 0, 0, 0x34, 0xA2]);
        assert_eq!(0xA234, u16::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_u32() {
        let mut decoder = push_data(vec![4, 0, 0, 0, 0x45, 0x23, 1, 0xCD]);
        assert_eq!(0xCD012345, u32::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_u64() {
        let mut decoder = push_data(vec![8, 0, 0, 0, 0xBB, 0xAA, 0x10, 0x32, 0x54, 0x76, 0x98,
                                         0xAB]);
        assert_eq!(0xAB9876543210AABB, u64::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_i8() {
        let mut decoder = push_data(vec![1, 0, 0, 0, 156]);
        assert_eq!(-100, i8::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_i16() {
        let mut decoder = push_data(vec![2, 0, 0, 0, 0xD0, 0x8A]);
        assert_eq!(-30000, i16::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_i32() {
        let mut decoder = push_data(vec![4, 0, 0, 0, 0x00, 0x6C, 0xCA, 0x88]);
        assert_eq!(-2000000000, i32::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_i64() {
        let mut decoder = push_data(vec![8, 0, 0, 0, 0x00, 0x00, 0x7c, 0x1d, 0xaf, 0x93, 0x19,
                                         0x83]);
        assert_eq!(-9000000000000000000, i64::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_f32() {
        let mut decoder = push_data(vec![4, 0, 0, 0, 0x00, 0x70, 0x7b, 0x44]);
        assert_eq!(1005.75, f32::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_f64() {
        let mut decoder = push_data(vec![8, 0, 0, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x8f,
                                         0x40]);
        assert_eq!(1005.75, f64::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_bool() {
        let mut decoder = push_data(vec![1, 0, 0, 0, 1]);
        assert_eq!(true, bool::decode(&mut decoder).unwrap());
        let mut decoder = push_data(vec![1, 0, 0, 0, 0]);
        assert_eq!(false, bool::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_string() {
        let mut decoder = push_data(vec![0, 0, 0, 0]);
        assert_eq!("", String::decode(&mut decoder).unwrap());
        let mut decoder = push_data(vec![13, 0, 0, 0, 72, 101, 108, 108, 111, 44, 32, 87, 111,
                                         114, 108, 100, 33]);
        assert_eq!("Hello, World!", String::decode(&mut decoder).unwrap());
    }

    #[test]
    fn reads_array() {
        let mut decoder = push_data(vec![28, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 7, 0, 2, 0, 0, 0,
                                         1, 4, 2, 0, 0, 0, 33, 0, 2, 0, 0, 0, 57, 0]);
        assert_eq!(vec![7, 1025, 33, 57],
                   Vec::<i16>::decode(&mut decoder).unwrap());
    }

    #[derive(Debug,RustcDecodable,PartialEq)]
    struct TestStructOne {
        a: i16,
        b: bool,
        c: u8,
        d: String,
        e: Vec<bool>,
    }

    #[test]
    fn reads_simple_struct() {
        let v = TestStructOne {
            a: 2050i16,
            b: true,
            c: 7u8,
            d: String::from("ABC012"),
            e: vec![true, false, false, true],
        };
        let mut decoder = push_data(vec![54, 0, 0, 0, 2, 0, 0, 0, 2, 8, 1, 0, 0, 0, 1, 1, 0, 0,
                                         0, 7, 6, 0, 0, 0, 65, 66, 67, 48, 49, 50, 24, 0, 0, 0,
                                         4, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
                                         1, 0, 0, 0, 1]);
        assert_eq!(v, TestStructOne::decode(&mut decoder).unwrap());
    }

    #[derive(Debug,RustcDecodable,PartialEq)]
    struct TestStructPart {
        a: String,
        b: bool,
    }

    #[derive(Debug,RustcDecodable,PartialEq)]
    struct TestStructBig {
        a: Vec<TestStructPart>,
        b: String,
    }

    #[test]
    fn reads_complex_struct() {
        let mut parts = Vec::new();
        parts.push(TestStructPart {
            a: String::from("ABC"),
            b: true,
        });
        parts.push(TestStructPart {
            a: String::from("1!!!!"),
            b: true,
        });
        parts.push(TestStructPart {
            a: String::from("234b"),
            b: false,
        });
        let v = TestStructBig {
            a: parts,
            b: String::from("EEe"),
        };
        let mut decoder = push_data(vec![66, 0, 0, 0, 55, 0, 0, 0, 3, 0, 0, 0, 12, 0, 0, 0, 3, 0,
                                         0, 0, 65, 66, 67, 1, 0, 0, 0, 1, 14, 0, 0, 0, 5, 0, 0,
                                         0, 49, 33, 33, 33, 33, 1, 0, 0, 0, 1, 13, 0, 0, 0, 4, 0,
                                         0, 0, 50, 51, 52, 98, 1, 0, 0, 0, 0, 3, 0, 0, 0, 69, 69,
                                         101]);
        assert_eq!(v, TestStructBig::decode(&mut decoder).unwrap());
    }
}
<|endoftext|>


<commit_before>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ (", res.commit_msg.lines().next().unwrap()).into()),
                       Link(SlackLink::new(&res.commit_url, &res.commit_id[0..6])),
                       Text(format!(") from branch *{}*", res.branch).into())]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.test || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.test {
        "Test failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else if !res.test {
        "had a mixed palate"
    } else {
        "tasted nice"
    };

    let check = |title: &str, result: bool| {
        let mut out = format!("{}: ", title);
        if result {
            out.push_str(":white_check_mark:");
        } else {
            out.push_str(":x:");
        }
        out
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .text(format!("{} {} {}",
                      check("Build", res.build),
                      check("Tests", res.test),
                      check("Benchmark", res.bench)))
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    let is_regression = |(_, v): (_, &BenchmarkResult<f64>)| match *v {
        BenchmarkResult::Regression(_, _) => true,
        _ => false,
    };

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match *v {
                            BenchmarkResult::Improvement(ref s, ref p) => (s, p),
                            BenchmarkResult::Neutral(ref s, ref p) => (s, p),
                            BenchmarkResult::Regression(ref s, ref p) => (s, p),
                        };
                        let icon = if *val.1 > 0.1 {
                            ":chart_with_upwards_trend:"
                        } else if *val.1 < -0.1 {
                            ":chart_with_downwards_trend:"
                        } else {
                            ""
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(format!("{} {} ({:+.2}%)", icon, val.0, val.1 * 100.0)),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));

                let col = if res.iter().all(&is_regression) {
                    "danger"
                } else if res.iter().any(&is_regression) {
                    "warning"
                } else {
                    "good"
                };

                let att = AttachmentBuilder::new("")
                    .color(col)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<commit_msg>Rustfmt<commit_after>use slack_hook::{Attachment, AttachmentBuilder, Field, PayloadBuilder, Slack, SlackText, SlackLink};
use slack_hook::SlackTextContent::{Text, Link};

use taste::{BenchmarkResult, TastingResult};

pub struct SlackNotifier {
    conn: Slack,
    channel: String,
    github_repo: String,
}

impl SlackNotifier {
    pub fn new(hook_url: &str, channel: &str, repo_url: &str) -> SlackNotifier {
        SlackNotifier {
            conn: Slack::new(hook_url).unwrap(),
            channel: String::from(channel),
            github_repo: String::from(repo_url),
        }
    }

    pub fn notify(&self, res: &TastingResult) -> Result<(), String> {
        let payload = PayloadBuilder::new()
            .text(vec![Text("I've tasted commit _".into()),
                       Text(format!("\"{}\"_ (", res.commit_msg.lines().next().unwrap()).into()),
                       Link(SlackLink::new(&res.commit_url, &res.commit_id[0..6])),
                       Text(format!(") from branch *{}*", res.branch).into())]
                .as_slice())
            .attachments(result_to_attachments(&res))
            .channel(self.channel.clone())
            .username("taster")
            .icon_emoji(":tea:")
            .build()
            .unwrap();

        match self.conn.send(&payload) {
            Ok(_) => Ok(()),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}

fn result_to_attachments(res: &TastingResult) -> Vec<Attachment> {
    let color = if !res.build || !res.test || !res.bench {
        "danger"
    } else {
        "good"
    };

    let title = if !res.build {
        "Build failure!"
    } else if !res.test {
        "Test failure!"
    } else if !res.bench {
        "Benchmark failure!"
    } else {
        "Performance results:"
    };

    let taste = if !res.build || !res.bench {
        "was inedible"
    } else if !res.test {
        "had a mixed palate"
    } else {
        "tasted nice"
    };

    let check = |title: &str, result: bool| {
        let mut out = format!("{}: ", title);
        if result {
            out.push_str(":white_check_mark:");
        } else {
            out.push_str(":x:");
        }
        out
    };

    let mut attachments = Vec::new();
    let build_att = AttachmentBuilder::new("")
        .title(format!("It {}.", taste))
        .text(format!("{} {} {}",
                      check("Build", res.build),
                      check("Tests", res.test),
                      check("Benchmark", res.bench)))
        .color(color)
        .build()
        .unwrap();
    attachments.push(build_att);

    let is_regression = |(_, v): (_, &BenchmarkResult<f64>)| match *v {
        BenchmarkResult::Regression(_, _) => true,
        _ => false,
    };

    match res.results {
        None => (),
        Some(ref r) => {
            for res in r {
                let mut nv = res.iter()
                    .map(|(k, v)| {
                        let val = match *v {
                            BenchmarkResult::Improvement(ref s, ref p) => (s, p),
                            BenchmarkResult::Neutral(ref s, ref p) => (s, p),
                            BenchmarkResult::Regression(ref s, ref p) => (s, p),
                        };
                        let icon = if *val.1 > 0.1 {
                            ":chart_with_upwards_trend:"
                        } else if *val.1 < -0.1 {
                            ":chart_with_downwards_trend:"
                        } else {
                            ""
                        };
                        Field {
                            title: k.clone(),
                            value: SlackText::new(format!("{} {} ({:+.2}%)",
                                                          icon,
                                                          val.0,
                                                          val.1 * 100.0)),
                            short: Some(true),
                        }
                    })
                    .collect::<Vec<_>>();
                nv.sort_by(|a, b| b.title.cmp(&a.title));

                let col = if res.iter().all(&is_regression) {
                    "danger"
                } else if res.iter().any(&is_regression) {
                    "warning"
                } else {
                    "good"
                };

                let att = AttachmentBuilder::new("")
                    .color(col)
                    .fields(nv)
                    .build()
                    .unwrap();
                attachments.push(att);
            }
        }
    }
    attachments
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::{VecDeque, HashMap};

pub fn rtg_1(file: &str) -> usize {
    process(file)
}

pub fn rtg_2(file: &str) -> usize {
    process(file)
}

fn process(file: &str) -> usize {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let lines: Vec<String> = reader.lines()
        .filter_map(Result::ok)
        .collect();

    let mut state = HashMap::new();
    let mut non_floor_entity_count = 0;
    for tokens in lines.iter().map(|line| {
        let mut words = line.split_whitespace().rev();
        let mut tokens = Vec::new();
        loop {
            if let Some(w) = words.next() {
                let w = w.trim_matches(|c: char| !c.is_alphabetic());
                match w {
                    "floor" => {
                        if let Some(f) = words.next() {
                            match f {
                                "first" => tokens.push(Entity::Floor(1)),
                                "second" => tokens.push(Entity::Floor(2)),
                                "third" => tokens.push(Entity::Floor(3)),
                                "fourth" => tokens.push(Entity::Floor(4)),
                                _ => {},
                            }
                        }
                    },
                    "microchip" => {
                        if let Some(m) = words.next() {
                            if let Some(i) = m.find('-') {
                                let (compatibility, _) = m.split_at(i);
                                tokens.push(Entity::Microchip(compatibility));
                                non_floor_entity_count += 1;
                            }
                        }
                    },
                    "generator" => {
                        if let Some(g) = words.next() {
                            tokens.push(Entity::Generator(g));
                            non_floor_entity_count += 1;
                        }
                    },
                    _ => {},
                }
            } else {
                break;
            }
        }
        tokens
    })
    {
        let mut floor_id = None;
        let mut floor_inventory = VecDeque::new();
        for token in tokens {
            match token {
                Entity::Floor(n) => floor_id = Some(n),
                e @ _ => floor_inventory.push_back(e),
            }
        }
        if let Some(f) = floor_id {
            state.insert(f, floor_inventory);
        }
    }

    if let Some(top_floor) = state.iter().map(|s| {
        let (f, _): (&usize, &VecDeque<Entity>) = s;
        *f
    }).max() {
        let mut elevator = Elevator {
            holding: (None, None),
            current_floor: 1,
            top_floor: top_floor,
        };
        println!("{:?}", elevator);

        loop {
            {
                let inventory = state.entry(elevator.current_floor).or_insert(VecDeque::new());
                println!("Floor {}: {:?}", elevator.current_floor, inventory);
                if let Some(item_a) = elevator.unload_left() {
                    inventory.push_back(item_a);
                }
                if let Some(item_b) = elevator.unload_right() {
                    inventory.push_back(item_b);
                }
                loop {
                    if let Some(item) = inventory.pop_front() {
                        elevator.load_item(item);
                        if elevator.is_full() {
                            break;
                        }
                    } else {
                        panic!("the elevator will only function if it contains at least one RTG or microchip");
                    }
                }

                elevator.inc_floor();
            }
            println!("{:?}", state);
            if state.entry(elevator.top_floor).or_insert(VecDeque::new()).len() == non_floor_entity_count {
                break;
            }
        }
    }
    42
}

#[derive(Debug, Clone)]
enum Entity<'e> {
    Floor(usize),
    Generator(&'e str),
    Microchip(&'e str),
}

#[derive(Debug)]
struct Elevator<'e> {
    holding: (Option<Entity<'e>>, Option<Entity<'e>>),
    current_floor: usize,
    top_floor: usize,
}

impl<'e> Elevator<'e> {
    fn inc_floor(&mut self) {
        if self.current_floor < self.top_floor {
            self.current_floor += 1;
        }
    }

    fn dec_floor(&mut self) {
        if self.current_floor > 0 {
            self.current_floor -= 1;
        }
    }

    fn load_item(&mut self, e: Entity<'e>) {
        if !self.holding.0.is_some() {
            self.holding.0 = Some(e);
        } else if !self.holding.1.is_some() {
            self.holding.1 = Some(e);
        }
    }

    fn is_full(&self) -> bool {
        self.holding.0.is_some() && self.holding.1.is_some()
    }

    fn unload_left(&mut self) -> Option<Entity<'e>> {
        let out = self.holding.0.clone();
        self.holding.0 = None;
        out
    }

    fn unload_right(&mut self) -> Option<Entity<'e>> {
        let out = self.holding.1.clone();
        self.holding.1 = None;
        out
    }
}

// Interesting syntax usage here but I used a method instead
//fn unload_left<'e>(&mut Elevator { holding: (ref mut left, _), .. }: &'e mut Elevator) -> Option<Entity<'e>> {
//    let out = left.clone();
//    *left = None;
//    out
//}
<commit_msg>Add commit about algorithm idea.<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::{VecDeque, HashMap};

pub fn rtg_1(file: &str) -> usize {
    process(file)
}

pub fn rtg_2(file: &str) -> usize {
    process(file)
}

fn process(file: &str) -> usize {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let lines: Vec<String> = reader.lines()
        .filter_map(Result::ok)
        .collect();

    let mut state = HashMap::new();
    let mut non_floor_entity_count = 0;
    for tokens in lines.iter().map(|line| {
        let mut words = line.split_whitespace().rev();
        let mut tokens = Vec::new();
        loop {
            if let Some(w) = words.next() {
                let w = w.trim_matches(|c: char| !c.is_alphabetic());
                match w {
                    "floor" => {
                        if let Some(f) = words.next() {
                            match f {
                                "first" => tokens.push(Entity::Floor(1)),
                                "second" => tokens.push(Entity::Floor(2)),
                                "third" => tokens.push(Entity::Floor(3)),
                                "fourth" => tokens.push(Entity::Floor(4)),
                                _ => {},
                            }
                        }
                    },
                    "microchip" => {
                        if let Some(m) = words.next() {
                            if let Some(i) = m.find('-') {
                                let (compatibility, _) = m.split_at(i);
                                tokens.push(Entity::Microchip(compatibility));
                                non_floor_entity_count += 1;
                            }
                        }
                    },
                    "generator" => {
                        if let Some(g) = words.next() {
                            tokens.push(Entity::Generator(g));
                            non_floor_entity_count += 1;
                        }
                    },
                    _ => {},
                }
            } else {
                break;
            }
        }
        tokens
    })
    {
        let mut floor_id = None;
        let mut floor_inventory = VecDeque::new();
        for token in tokens {
            match token {
                Entity::Floor(n) => floor_id = Some(n),
                e @ _ => floor_inventory.push_back(e),
            }
        }
        if let Some(f) = floor_id {
            state.insert(f, floor_inventory);
        }
    }

    if let Some(top_floor) = state.iter().map(|s| {
        let (f, _): (&usize, &VecDeque<Entity>) = s;
        *f
    }).max() {
        let mut elevator = Elevator {
            holding: (None, None),
            current_floor: 1,
            top_floor: top_floor,
        };
        println!("{:?}", elevator);

        // implement Frame-Stewart 4+ towers of hanoi algorithm

        loop {
            {
                let inventory = state.entry(elevator.current_floor).or_insert(VecDeque::new());
                println!("Floor {}: {:?}", elevator.current_floor, inventory);
                if let (Some(l), Some(r)) = elevator.unload_all() {
                    inventory.push_back(l);
                    inventory.push_back(r);
                }
                loop {
                    if let Some(item) = inventory.pop_front() {
                        elevator.load_item(item);
                        if elevator.is_full() {
                            break;
                        }
                    } else {
                        panic!("the elevator will only function if it contains at least one RTG or microchip");
                    }
                }

                elevator.inc_floor();
            }
            println!("{:?}", state);
            if state.entry(elevator.top_floor).or_insert(VecDeque::new()).len() == non_floor_entity_count {
                break;
            }
        }
    }
    42
}

#[derive(Debug, Clone)]
enum Entity<'e> {
    Floor(usize),
    Generator(&'e str),
    Microchip(&'e str),
}

#[derive(Debug)]
struct Elevator<'e> {
    holding: (Option<Entity<'e>>, Option<Entity<'e>>),
    current_floor: usize,
    top_floor: usize,
}

impl<'e> Elevator<'e> {
    fn inc_floor(&mut self) {
        if self.current_floor < self.top_floor {
            self.current_floor += 1;
        }
    }

    fn dec_floor(&mut self) {
        if self.current_floor > 0 {
            self.current_floor -= 1;
        }
    }

    fn load_item(&mut self, e: Entity<'e>) {
        if !self.holding.0.is_some() {
            self.holding.0 = Some(e);
        } else if !self.holding.1.is_some() {
            self.holding.1 = Some(e);
        }
    }

    fn is_full(&self) -> bool {
        self.holding.0.is_some() && self.holding.1.is_some()
    }

    fn unload_left(&mut self) -> Option<Entity<'e>> {
        let out = self.holding.0.clone();
        self.holding.0 = None;
        out
    }

    fn unload_right(&mut self) -> Option<Entity<'e>> {
        let out = self.holding.1.clone();
        self.holding.1 = None;
        out
    }

    fn unload_all(&mut self) -> (Option<Entity<'e>>, Option<Entity<'e>>) {
        let out = (self.holding.0.clone(), self.holding.1.clone());
        self.holding.0 = None;
        self.holding.1 = None;
        out
    }
}

// Interesting syntax usage here but I used a method instead
//fn unload_left<'e>(&mut Elevator { holding: (ref mut left, _), .. }: &'e mut Elevator) -> Option<Entity<'e>> {
//    let out = left.clone();
//    *left = None;
//    out
//}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::ptr;
use std::f32::consts::PI;

use math::*;
use polygon::Camera;
use polygon::gl_render::{GLRender, ShaderProgram, GLMeshData};
use polygon::geometry::Mesh;
use resource::ResourceManager;

static mut instance: *mut DebugDrawInner = 0 as *mut DebugDrawInner;

#[derive(Debug)]
pub struct DebugDraw {
    renderer: Rc<GLRender>,

    shader: ShaderProgram,
    unit_cube: GLMeshData,
    unit_sphere: GLMeshData,

    inner: Box<DebugDrawInner>,

    // Vecs used for dynamically reconstructing meshes.
    line_vertices: Vec<f32>,
    line_indices: Vec<u32>,
}

static CUBE_VERTS: [f32; 32] =
    [ 0.5,  0.5,  0.5, 1.0,
      0.5,  0.5, -0.5, 1.0,
      0.5, -0.5,  0.5, 1.0,
      0.5, -0.5, -0.5, 1.0,
     -0.5,  0.5,  0.5, 1.0,
     -0.5,  0.5, -0.5, 1.0,
     -0.5, -0.5,  0.5, 1.0,
     -0.5, -0.5, -0.5, 1.0,];
static CUBE_INDICES: [u32; 24] =
    [0, 1,
     1, 3,
     3, 2,
     2, 0,
     4, 5,
     5, 7,
     7, 6,
     6, 4,
     0, 4,
     1, 5,
     2, 6,
     3, 7,];

impl DebugDraw {
    pub fn new(renderer: Rc<GLRender>, resource_manager: &ResourceManager) -> DebugDraw {
        assert!(unsafe { instance.is_null() }, "Cannot create more than one instance of DebugDraw at a time");

        let mut inner = Box::new(DebugDrawInner {
            command_buffer: Vec::new(),
        });

        unsafe {
            instance = &mut *inner;
        }

        // Build sphere vertices. This could be done offline, but I'm lazy so we do it at runtime!
        let unit_sphere = {
            const VERTS_PER_CIRCLE: usize = 50;
            let mut sphere_verts = Vec::new();
            let mut sphere_indices = Vec::<u32>::new();

            // Vertices around X axis.
            sphere_verts.push(Point::new(0.0, 0.0, 1.0));
            for offset in 0..VERTS_PER_CIRCLE {
                let percent = offset as f32 / VERTS_PER_CIRCLE as f32;
                let theta = percent * 2.0 * PI;
                sphere_verts.push(Point::new(0.0, theta.sin(), theta.cos()));
                sphere_indices.push(sphere_verts.len() as u32 - 2);
                sphere_indices.push(sphere_verts.len() as u32 - 1);
            }

            // Vertices around Y axis.
            sphere_verts.push(Point::new(1.0, 0.0, 0.0));
            for offset in 0..VERTS_PER_CIRCLE {
                let percent = offset as f32 / VERTS_PER_CIRCLE as f32;
                let theta = percent * 2.0 * PI;
                sphere_verts.push(Point::new(theta.cos(), 0.0, theta.sin()));
                sphere_indices.push(sphere_verts.len() as u32 - 2);
                sphere_indices.push(sphere_verts.len() as u32 - 1);
            }

            // Vertices around Z axis.
            sphere_verts.push(Point::new(1.0, 0.0, 0.0));
            for offset in 0..VERTS_PER_CIRCLE {
                let percent = offset as f32 / VERTS_PER_CIRCLE as f32;
                let theta = percent * 2.0 * PI;
                sphere_verts.push(Point::new(theta.cos(), theta.sin(), 0.0));
                sphere_indices.push(sphere_verts.len() as u32 - 2);
                sphere_indices.push(sphere_verts.len() as u32 - 1);
            }

            build_mesh(&*renderer, Point::as_ref(&*sphere_verts), &*sphere_indices)
        };

        DebugDraw {
            renderer: renderer.clone(),

            shader: resource_manager.get_shader("shaders/debug_draw.glsl").unwrap(),
            unit_cube: build_mesh(&*renderer, &CUBE_VERTS, &CUBE_INDICES),
            unit_sphere: unit_sphere,

            inner: inner,

            line_vertices: Vec::new(),
            line_indices: Vec::new(),
        }
    }

    pub fn flush_commands(&mut self, camera: &Camera) {
        for command in &self.inner.command_buffer {
            match command {
                &DebugDrawCommand::Line { start, end, color: _ } => {
                    self.line_vertices.extend(start.as_array());
                    self.line_vertices.extend(end.as_array());
                },
                &DebugDrawCommand::Box { transform, color } => {
                    self.renderer.draw_wireframe(
                        camera,
                        &self.shader,
                        &self.unit_cube,
                        transform,
                        color);
                },
                &DebugDrawCommand::Sphere { center, radius, color } => {
                    let model_transform =
                        Matrix4::from_point(center) * Matrix4::scale(radius, radius, radius);
                    self.renderer.draw_wireframe(
                        camera,
                        &self.shader,
                        &self.unit_sphere,
                        model_transform,
                        color);
                },
            }
        }

        if !self.line_vertices.is_empty() {
            for index in 0..self.line_vertices.len() / 4 {
                self.line_indices.push(index as u32);
            }
            let line_mesh = build_mesh(&*self.renderer, &self.line_vertices, &self.line_indices);
            self.renderer.draw_wireframe(
                camera,
                &self.shader,
                &line_mesh,
                Matrix4::identity(),
                color::WHITE);
            self.renderer.delete_mesh(line_mesh);
        }

        self.line_vertices.clear();
        self.line_indices.clear();
    }

    // TODO: This function is a hack to get debug pausing working. This should be better handled
    // by DebugDraw itself, rather than forcing Engine to handle it.
    pub fn clear_buffer(&mut self) {
        self.inner.command_buffer.clear();
    }
}

impl Drop for DebugDraw {
    fn drop(&mut self) {
        unsafe {
            instance = ptr::null_mut();
        }
    }
}

/// Creates a mesh from a list of vertices and indices.
fn build_mesh(renderer: &GLRender, vertices: &[f32], indices: &[u32]) -> GLMeshData {
    let mesh = Mesh::from_raw_data(vertices, indices);
    renderer.gen_mesh(&mesh)
}

#[derive(Debug, Clone)]
pub enum DebugDrawCommand {
    Line {
        start: Point,
        end: Point,
        color: Color,
    },
    Box {
        transform: Matrix4,
        color:     Color,
    },
    Sphere {
        center: Point,
        radius: f32,
        color: Color,
    }
}

#[derive(Debug)]
struct DebugDrawInner {
    command_buffer: Vec<DebugDrawCommand>,
}

pub fn draw_command(command: DebugDrawCommand) {
    debug_assert!(unsafe { !instance.is_null() }, "Cannot use debug drawing if there is no instance");

    let inner = unsafe { &mut *instance };
    inner.command_buffer.push(command);
}

pub fn line(start: Point, end: Point) {
    draw_command(DebugDrawCommand::Line {
        start: start,
        end: end,
        color: color::WHITE,
    });
}

pub fn box_min_max(min: Point, max: Point) {
    box_min_max_color(min, max, color::WHITE);
}

pub fn box_min_max_color(min: Point, max: Point, color: Color) {
    let offset = max - min;
    let center = min + offset * 0.5;
    let transform = Matrix4::from_point(center) * Matrix4::from_scale_vector(offset);
    draw_command(DebugDrawCommand::Box {
        transform: transform,
        color: color,
    });
}

pub fn box_center_widths(center: Point, widths: Vector3) {
    let transform = Matrix4::from_point(center) * Matrix4::from_scale_vector(widths);
    draw_command(DebugDrawCommand::Box {
        transform: transform,
        color: color::WHITE,
    });
}

pub fn box_matrix(transform: Matrix4) {
    box_matrix_color(transform, color::WHITE);
}

pub fn box_matrix_color(transform: Matrix4, color: Color) {
    draw_command(DebugDrawCommand::Box {
        transform: transform,
        color: color,
    });
}

pub fn sphere(center: Point, radius: f32) {
    sphere_color(center, radius, color::WHITE);
}

pub fn sphere_color(center: Point, radius: f32, color: Color) {
    draw_command(DebugDrawCommand::Sphere {
        center: center,
        radius: radius,
        color: color,
    });
}
<commit_msg>Thread-Safe Debug Draw<commit_after>use std::rc::Rc;
use std::ptr;
use std::f32::consts::PI;
use std::sync::Mutex;

use math::*;
use polygon::Camera;
use polygon::gl_render::{GLRender, ShaderProgram, GLMeshData};
use polygon::geometry::Mesh;
use resource::ResourceManager;

static mut instance: *const Mutex<DebugDrawInner> = 0 as *const _;

#[derive(Debug)]
pub struct DebugDraw {
    renderer: Rc<GLRender>,

    shader: ShaderProgram,
    unit_cube: GLMeshData,
    unit_sphere: GLMeshData,

    inner: Box<Mutex<DebugDrawInner>>,

    // Vecs used for dynamically reconstructing meshes.
    line_vertices: Vec<f32>,
    line_indices: Vec<u32>,
}

static CUBE_VERTS: [f32; 32] =
    [ 0.5,  0.5,  0.5, 1.0,
      0.5,  0.5, -0.5, 1.0,
      0.5, -0.5,  0.5, 1.0,
      0.5, -0.5, -0.5, 1.0,
     -0.5,  0.5,  0.5, 1.0,
     -0.5,  0.5, -0.5, 1.0,
     -0.5, -0.5,  0.5, 1.0,
     -0.5, -0.5, -0.5, 1.0,];
static CUBE_INDICES: [u32; 24] =
    [0, 1,
     1, 3,
     3, 2,
     2, 0,
     4, 5,
     5, 7,
     7, 6,
     6, 4,
     0, 4,
     1, 5,
     2, 6,
     3, 7,];

impl DebugDraw {
    pub fn new(renderer: Rc<GLRender>, resource_manager: &ResourceManager) -> DebugDraw {
        assert!(unsafe { instance.is_null() }, "Cannot create more than one instance of DebugDraw at a time");

        let mut inner = Box::new(Mutex::new(DebugDrawInner {
            command_buffer: Vec::new(),
        }));

        unsafe {
            instance = &mut *inner;
        }

        // Build sphere vertices. This could be done offline, but I'm lazy so we do it at runtime!
        let unit_sphere = {
            const VERTS_PER_CIRCLE: usize = 50;
            let mut sphere_verts = Vec::new();
            let mut sphere_indices = Vec::<u32>::new();

            // Vertices around X axis.
            sphere_verts.push(Point::new(0.0, 0.0, 1.0));
            for offset in 0..VERTS_PER_CIRCLE {
                let percent = offset as f32 / VERTS_PER_CIRCLE as f32;
                let theta = percent * 2.0 * PI;
                sphere_verts.push(Point::new(0.0, theta.sin(), theta.cos()));
                sphere_indices.push(sphere_verts.len() as u32 - 2);
                sphere_indices.push(sphere_verts.len() as u32 - 1);
            }

            // Vertices around Y axis.
            sphere_verts.push(Point::new(1.0, 0.0, 0.0));
            for offset in 0..VERTS_PER_CIRCLE {
                let percent = offset as f32 / VERTS_PER_CIRCLE as f32;
                let theta = percent * 2.0 * PI;
                sphere_verts.push(Point::new(theta.cos(), 0.0, theta.sin()));
                sphere_indices.push(sphere_verts.len() as u32 - 2);
                sphere_indices.push(sphere_verts.len() as u32 - 1);
            }

            // Vertices around Z axis.
            sphere_verts.push(Point::new(1.0, 0.0, 0.0));
            for offset in 0..VERTS_PER_CIRCLE {
                let percent = offset as f32 / VERTS_PER_CIRCLE as f32;
                let theta = percent * 2.0 * PI;
                sphere_verts.push(Point::new(theta.cos(), theta.sin(), 0.0));
                sphere_indices.push(sphere_verts.len() as u32 - 2);
                sphere_indices.push(sphere_verts.len() as u32 - 1);
            }

            build_mesh(&*renderer, Point::as_ref(&*sphere_verts), &*sphere_indices)
        };

        DebugDraw {
            renderer: renderer.clone(),

            shader: resource_manager.get_shader("shaders/debug_draw.glsl").unwrap(),
            unit_cube: build_mesh(&*renderer, &CUBE_VERTS, &CUBE_INDICES),
            unit_sphere: unit_sphere,

            inner: inner,

            line_vertices: Vec::new(),
            line_indices: Vec::new(),
        }
    }

    pub fn flush_commands(&mut self, camera: &Camera) {
        let inner = self.inner.lock().unwrap();
        for command in &inner.command_buffer {
            match command {
                &DebugDrawCommand::Line { start, end, color: _ } => {
                    self.line_vertices.extend(start.as_array());
                    self.line_vertices.extend(end.as_array());
                },
                &DebugDrawCommand::Box { transform, color } => {
                    self.renderer.draw_wireframe(
                        camera,
                        &self.shader,
                        &self.unit_cube,
                        transform,
                        color);
                },
                &DebugDrawCommand::Sphere { center, radius, color } => {
                    let model_transform =
                        Matrix4::from_point(center) * Matrix4::scale(radius, radius, radius);
                    self.renderer.draw_wireframe(
                        camera,
                        &self.shader,
                        &self.unit_sphere,
                        model_transform,
                        color);
                },
            }
        }

        if !self.line_vertices.is_empty() {
            for index in 0..self.line_vertices.len() / 4 {
                self.line_indices.push(index as u32);
            }
            let line_mesh = build_mesh(&*self.renderer, &self.line_vertices, &self.line_indices);
            self.renderer.draw_wireframe(
                camera,
                &self.shader,
                &line_mesh,
                Matrix4::identity(),
                color::WHITE);
            self.renderer.delete_mesh(line_mesh);
        }

        self.line_vertices.clear();
        self.line_indices.clear();
    }

    // TODO: This function is a hack to get debug pausing working. This should be better handled
    // by DebugDraw itself, rather than forcing Engine to handle it.
    pub fn clear_buffer(&mut self) {
        let mut inner = self.inner.lock().unwrap();
        inner.command_buffer.clear();
    }
}

impl Drop for DebugDraw {
    fn drop(&mut self) {
        unsafe {
            instance = ptr::null_mut();
        }
    }
}

/// Creates a mesh from a list of vertices and indices.
fn build_mesh(renderer: &GLRender, vertices: &[f32], indices: &[u32]) -> GLMeshData {
    let mesh = Mesh::from_raw_data(vertices, indices);
    renderer.gen_mesh(&mesh)
}

#[derive(Debug, Clone)]
pub enum DebugDrawCommand {
    Line {
        start: Point,
        end: Point,
        color: Color,
    },
    Box {
        transform: Matrix4,
        color:     Color,
    },
    Sphere {
        center: Point,
        radius: f32,
        color: Color,
    }
}

#[derive(Debug)]
struct DebugDrawInner {
    command_buffer: Vec<DebugDrawCommand>,
}

pub fn draw_command(command: DebugDrawCommand) {
    debug_assert!(unsafe { !instance.is_null() }, "Cannot use debug drawing if there is no instance");

    let inner = unsafe { &*instance };
    let mut inner = inner.lock().unwrap();
    inner.command_buffer.push(command);
}

pub fn line(start: Point, end: Point) {
    draw_command(DebugDrawCommand::Line {
        start: start,
        end: end,
        color: color::WHITE,
    });
}

pub fn box_min_max(min: Point, max: Point) {
    box_min_max_color(min, max, color::WHITE);
}

pub fn box_min_max_color(min: Point, max: Point, color: Color) {
    let offset = max - min;
    let center = min + offset * 0.5;
    let transform = Matrix4::from_point(center) * Matrix4::from_scale_vector(offset);
    draw_command(DebugDrawCommand::Box {
        transform: transform,
        color: color,
    });
}

pub fn box_center_widths(center: Point, widths: Vector3) {
    let transform = Matrix4::from_point(center) * Matrix4::from_scale_vector(widths);
    draw_command(DebugDrawCommand::Box {
        transform: transform,
        color: color::WHITE,
    });
}

pub fn box_matrix(transform: Matrix4) {
    box_matrix_color(transform, color::WHITE);
}

pub fn box_matrix_color(transform: Matrix4, color: Color) {
    draw_command(DebugDrawCommand::Box {
        transform: transform,
        color: color,
    });
}

pub fn sphere(center: Point, radius: f32) {
    sphere_color(center, radius, color::WHITE);
}

pub fn sphere_color(center: Point, radius: f32, color: Color) {
    draw_command(DebugDrawCommand::Sphere {
        center: center,
        radius: radius,
        color: color,
    });
}
<|endoftext|>


<commit_before>extern crate regex;
use self::regex::Regex;
use super::*;

#[test]
fn string_newline_terminate_works() {
    assert_eq!("word".with_newline(), "word\n");
    assert_eq!("myname".with_newline(), "myname\n");
}

#[test]
fn string_fill_works() {
    let max = 1500;
    let buf = "myword\n".fill(max);

    // make sure string isn't too long
    assert!(buf.len() <= max);

    // make sure buf only contains the word followed by a newline
    let re = Regex::new(r"^(myword\n)+$").unwrap();
    assert!(re.is_match(&buf));
}

struct Full {
}

impl Full {
    fn new() -> Self {
        Full{}
    }
}

impl Write for Full {
    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::BrokenPipe, "full"))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[test]
fn write_repeat_stops_on_error() {
    assert_eq!(Full::new().write_repeat("some data".as_bytes()).kind(),
               io::ErrorKind::BrokenPipe);
}
<commit_msg>adds test for Yes trait<commit_after>extern crate regex;
use self::regex::Regex;
use std::str;
use super::*;

#[test]
fn string_with_newline_works() {
    assert_eq!("word".with_newline(), "word\n");
    assert_eq!("myname".with_newline(), "myname\n");
}

#[test]
fn string_fill_works() {
    let max = 1500;
    let buf = "myword\n".fill(max);

    // make sure string isn't too long
    assert!(buf.len() <= max);

    // make sure buf only contains the word followed by a newline
    let re = Regex::new(r"^(myword\n)+$").unwrap();
    assert!(re.is_match(&buf));
}

struct Full {
}

impl Full {
    fn new() -> Self {
        Full{}
    }
}

impl Write for Full {
    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::BrokenPipe, "full"))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[test]
fn write_repeat_stops_on_error() {
    assert_eq!(Full::new().write_repeat("some data".as_bytes()).kind(),
               io::ErrorKind::BrokenPipe);
}

struct Checker {
    re: Regex
}

impl Checker {
    fn new(reg: &str) -> Self {
        Checker { re: Regex::new(reg).unwrap() }
    }
}

impl Write for Checker {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        assert!(self.re.is_match(str::from_utf8(data).unwrap()));
        Err(io::Error::new(io::ErrorKind::BrokenPipe, "full"))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[test]
fn yes_works() {
    Checker::new(r"^(some name\n)+$").yes("some name");
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
use super::Result;
use team::Team;
use tmux;

pub fn run(time_per_driver_in_minutes: &f64, team: &mut Team) -> Result<()> {
    let time_per_driver_in_seconds = time_per_driver_in_minutes * 60.0;

    let mut elapsed_time = 0.0;

    loop {
        if is_time_for_next_driver(&time_per_driver_in_seconds, elapsed_time) {
            prompt_user(team)?;
        };

        println!("{}", team.driver);
        elapsed_time += 1.0;
        sleep(Duration::from_secs(1))
    }
}

fn prompt_user(team: &mut Team) -> Result<()> {
    let prompt_command = r#"
    echo 'Continue mobbing? [y/n]' && \
        read input && \
        echo $input > /tmp/mob
    "#;

    let exit_status = tmux::new_window_with_command(prompt_command)?;

    if exit_status.success() && is_continue()? {
        team.next_driver();
        Ok(())
    } else {
        exit(1);
    }
}

fn is_continue() -> Result<bool> {
    let mut file = File::open("/tmp/mob")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents.trim().to_lowercase() == "y")
}

fn is_time_for_next_driver(time_per_driver: &f64, elapsed_time: f64) -> bool {
    if elapsed_time != 0.0 && elapsed_time % time_per_driver == 0.0 {
        true
    } else {
        false
    }
}
<commit_msg>refactor: Stop printing driver name when running<commit_after>use std::fs::File;
use std::io::Read;
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
use super::Result;
use team::Team;
use tmux;

pub fn run(time_per_driver_in_minutes: &f64, team: &mut Team) -> Result<()> {
    let time_per_driver_in_seconds = time_per_driver_in_minutes * 60.0;

    let mut elapsed_time = 0.0;

    loop {
        if is_time_for_next_driver(&time_per_driver_in_seconds, elapsed_time) {
            prompt_user(team)?;
        };

        elapsed_time += 1.0;
        sleep(Duration::from_secs(1))
    }
}

fn prompt_user(team: &mut Team) -> Result<()> {
    let prompt_command = r#"
    echo 'Continue mobbing? [y/n]' && \
        read input && \
        echo $input > /tmp/mob
    "#;

    let exit_status = tmux::new_window_with_command(prompt_command)?;

    if exit_status.success() && is_continue()? {
        team.next_driver();
        Ok(())
    } else {
        exit(1);
    }
}

fn is_continue() -> Result<bool> {
    let mut file = File::open("/tmp/mob")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents.trim().to_lowercase() == "y")
}

fn is_time_for_next_driver(time_per_driver: &f64, elapsed_time: f64) -> bool {
    if elapsed_time != 0.0 && elapsed_time % time_per_driver == 0.0 {
        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
    Metadata,
    X86_MMX,
    Token,
}
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

impl Integer {
    pub fn width(&self) -> u32 {
        unsafe { LLVMGetIntTypeWidth(self.into()) }
    }
}

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

pub struct Struct(Type);
impl_type!(Struct);

pub struct Array(Type);
impl_type!(Array);

pub struct Pointer(Type);
impl_type!(Pointer);

pub struct Vector(Type);
impl_type!(Vector);

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<commit_msg>remove extra curly brace<commit_after>use std::fmt;
use std::mem::transmute;
use std::ops::Deref;

use llvm_sys::prelude::*;
use llvm_sys::core::*;
use llvm_sys::*;

use super::*;

/// Enumeration of all the base types of the LLVM type system.
#[allow(non_camel_case_types)]
#[derive(Debug)]
#[repr(C)]
pub enum Kind {
    Void = 0,
    Half,
    Float,
    Double,
    X86_FP80,
    FP128,
    PPC_FP128,
    Label,
    Integer,
    Function,
    Struct,
    Array,
    Pointer,
    Vector,
    Metadata,
    X86_MMX,
    Token,
}

/// Should always be used as `&Type`.
///
/// `Type`s are owned by `Context` instances such that only one instance of a
/// specific `Type` exists per `Context`, e.g. only 1 `Type` for `i64` exists
/// per context. `Type`s are also never mutated and never destroyed, living for
/// the lifetime of the `Context` that owns them.
// TODO: can this be made into an unsized type?
pub struct Type(LLVMType);

impl<'a> Into<&'a Type> for LLVMTypeRef {
    fn into(self) -> &'a Type {
        unsafe { transmute::<LLVMTypeRef, &Type>(self) }
    }
}

impl<'a> From<&'a Type> for LLVMTypeRef {
    fn from(ty: &'a Type) -> LLVMTypeRef {
        unsafe { transmute::<&Type, LLVMTypeRef>(ty) }
    }
}

impl Type {
    pub fn kind(&self) -> Kind {
        unsafe { transmute(LLVMGetTypeKind(self.into())) }
    }

    pub fn is_sized(&self) -> bool {
        unsafe { LLVMTypeIsSized(self.into()) == 1 }
    }
}

// This counts as the llvm::Type::print method from the C++ API, though the C++
// version has more options.
impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let s_ptr = LLVMPrintTypeToString(self.into());
            let r = write!(f, "{}", c_str_to_str!(s_ptr));
            LLVMDisposeMessage(s_ptr);
            r
        }
    }
}

impl fmt::Debug for Type {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "llvm::Type({})", self)
    }
}

impl PartialEq for Type {
    fn eq(&self, other: &Self) -> bool {
        LLVMTypeRef::from(self) == LLVMTypeRef::from(other)
    }
}

impl Eq for Type {}

macro_rules! impl_type {
    ($t:ty) => {
        impl<'a> Into<&'a $t> for LLVMTypeRef {
            fn into(self) -> &'a $t {
                unsafe { transmute::<LLVMTypeRef, &$t>(self) }
            }
        }

        impl<'a> From<&'a $t> for LLVMTypeRef {
            fn from(ty: &'a $t) -> LLVMTypeRef {
                unsafe { transmute::<&$t, LLVMTypeRef>(ty) }
            }
        }

        impl Deref for $t {
            type Target = Type;

            fn deref(&self) -> &Self::Target {
                unsafe { transmute::<&Self, &Self::Target>(self) }
            }
        }
    }
}

// Base types:

pub struct Void(Type);
impl_type!(Void);

pub struct Half(Type);
impl_type!(Half);

pub struct Float(Type);
impl_type!(Float);

pub struct Double(Type);
impl_type!(Double);

#[allow(non_camel_case_types)]
pub struct X86_FP80(Type);
impl_type!(X86_FP80);

#[allow(non_camel_case_types)]
pub struct FP128(Type);
impl_type!(FP128);

#[allow(non_camel_case_types)]
pub struct PPC_FP128(Type);
impl_type!(PPC_FP128);

pub struct Label(Type);
impl_type!(Label);

pub struct Metadata(Type);
impl_type!(Metadata);

#[allow(non_camel_case_types)]
pub struct X86_MMX(Type);
impl_type!(X86_MMX);

pub struct Token(Type);
impl_type!(Token);

/// Integer types are constructed with a size. Construct them with the methods
/// that `Context` provides.
pub struct Integer(Type);
impl_type!(Integer);

impl Integer {
    pub fn width(&self) -> u32 {
        unsafe { LLVMGetIntTypeWidth(self.into()) }
    }
}

/// A function type is a tuple consisting of a return type and an array of
/// parameter types.
pub struct Function(Type);
impl_type!(Function);

impl Function {
    pub fn new<'a>(
        return_type: &'a Type,
        param_types: &[&'a Type],
        is_var_args: bool,
    ) -> &'a Function {
        unsafe {
            LLVMFunctionType(
                return_type.into(),
                transmute::<*const &Type, *mut LLVMTypeRef>(param_types.as_ptr()),
                param_types.len() as u32,
                is_var_args as LLVMBool,
            ).into()
        }
    }
}

pub struct Struct(Type);
impl_type!(Struct);

pub struct Array(Type);
impl_type!(Array);

pub struct Pointer(Type);
impl_type!(Pointer);

pub struct Vector(Type);
impl_type!(Vector);

/// Represents a LLVM Context Type
pub trait ContextType {
    fn get_type_in_context<'a>(context: &'a Context) -> &'a Type;
}

macro_rules! impl_context_type {
    ($t: ty, $to_type_in_context: ident) => {
        impl ContextType for $t {
            fn get_type_in_context<'a>(context: &'a Context) -> &'a Type {
                unsafe {
                    $to_type_in_context(context.ptr).into()
                }
            }
        }
    }
}

impl_context_type!(bool, LLVMInt1TypeInContext);
// This might actually not be true, Not sure
impl_context_type!(char, LLVMInt8TypeInContext);
impl_context_type!(u8, LLVMInt8TypeInContext);
impl_context_type!(u16, LLVMInt16TypeInContext);
impl_context_type!(u32, LLVMInt32TypeInContext);
impl_context_type!(u64, LLVMInt64TypeInContext);
impl_context_type!(i8, LLVMInt8TypeInContext);
impl_context_type!(i16, LLVMInt16TypeInContext);
impl_context_type!(i32, LLVMInt32TypeInContext);
impl_context_type!(i64, LLVMInt64TypeInContext);
impl_context_type!(f32, LLVMFloatTypeInContext);
impl_context_type!(f64, LLVMDoubleTypeInContext);
//TODO: Function Types
//TODO: Structure Types
//TODO: Sequential Types
//TODO: Other Types
<|endoftext|>


<commit_before>// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.

//! Traits for loading/saving Registry values
use super::enums::*;
use super::winapi::shared::winerror;
use super::RegValue;
use super::{to_utf16, v16_to_v8};
use std::ffi::{OsStr, OsString};
use std::io;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::slice;

/// A trait for types that can be loaded from registry values.
///
/// **NOTE:** Uses `from_utf16_lossy` when converting to `String`.
///
/// **NOTE:** When converting to `String`, trailing `NULL` characters are trimmed
/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`.
/// When converting to `OsString`, all `NULL` characters are left as is.
pub trait FromRegValue: Sized {
    fn from_reg_value(val: &RegValue) -> io::Result<Self>;
}

impl FromRegValue for String {
    fn from_reg_value(val: &RegValue) -> io::Result<String> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
                };
                let mut s = String::from_utf16_lossy(words);
                while s.ends_with('\u{0}') {
                    s.pop();
                }
                if val.vtype == REG_MULTI_SZ {
                    return Ok(s.replace("\u{0}", "\n"));
                }
                Ok(s)
            }
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

impl FromRegValue for OsString {
    fn from_reg_value(val: &RegValue) -> io::Result<OsString> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
                };
                let s = OsString::from_wide(words);
                Ok(s)
            }
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

impl FromRegValue for u32 {
    fn from_reg_value(val: &RegValue) -> io::Result<u32> {
        match val.vtype {
            REG_DWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u32) }),
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

impl FromRegValue for u64 {
    fn from_reg_value(val: &RegValue) -> io::Result<u64> {
        match val.vtype {
            REG_QWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u64) }),
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

/// A trait for types that can be written into registry values.
///
/// **NOTE:** Adds trailing `NULL` character to `str` and `String` values
/// but **not** to `OsStr` values.
pub trait ToRegValue {
    fn to_reg_value(&self) -> RegValue;
}

impl ToRegValue for String {
    fn to_reg_value(&self) -> RegValue {
        RegValue {
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ,
        }
    }
}

impl<'a> ToRegValue for &'a str {
    fn to_reg_value(&self) -> RegValue {
        RegValue {
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ,
        }
    }
}

impl<'a> ToRegValue for &'a OsStr {
    fn to_reg_value(&self) -> RegValue {
        RegValue {
            bytes: v16_to_v8(&(self.encode_wide().collect::<Vec<_>>())),
            vtype: REG_SZ,
        }
    }
}

impl ToRegValue for u32 {
    fn to_reg_value(&self) -> RegValue {
        let bytes: Vec<u8> =
            unsafe { slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() };
        RegValue {
            bytes,
            vtype: REG_DWORD,
        }
    }
}

impl ToRegValue for u64 {
    fn to_reg_value(&self) -> RegValue {
        let bytes: Vec<u8> =
            unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() };
        RegValue {
            bytes,
            vtype: REG_QWORD,
        }
    }
}
<commit_msg>Clippy: allow cast_ptr_alignment in FromRegValue impls<commit_after>// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.

//! Traits for loading/saving Registry values
use super::enums::*;
use super::winapi::shared::winerror;
use super::RegValue;
use super::{to_utf16, v16_to_v8};
use std::ffi::{OsStr, OsString};
use std::io;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::slice;

/// A trait for types that can be loaded from registry values.
///
/// **NOTE:** Uses `from_utf16_lossy` when converting to `String`.
///
/// **NOTE:** When converting to `String`, trailing `NULL` characters are trimmed
/// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`.
/// When converting to `OsString`, all `NULL` characters are left as is.
pub trait FromRegValue: Sized {
    fn from_reg_value(val: &RegValue) -> io::Result<Self>;
}

impl FromRegValue for String {
    fn from_reg_value(val: &RegValue) -> io::Result<String> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    #[allow(clippy::cast_ptr_alignment)]
                    slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
                };
                let mut s = String::from_utf16_lossy(words);
                while s.ends_with('\u{0}') {
                    s.pop();
                }
                if val.vtype == REG_MULTI_SZ {
                    return Ok(s.replace("\u{0}", "\n"));
                }
                Ok(s)
            }
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

impl FromRegValue for OsString {
    fn from_reg_value(val: &RegValue) -> io::Result<OsString> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    #[allow(clippy::cast_ptr_alignment)]
                    slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2)
                };
                let s = OsString::from_wide(words);
                Ok(s)
            }
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

impl FromRegValue for u32 {
    fn from_reg_value(val: &RegValue) -> io::Result<u32> {
        match val.vtype {
            #[allow(clippy::cast_ptr_alignment)]
            REG_DWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u32) }),
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

impl FromRegValue for u64 {
    fn from_reg_value(val: &RegValue) -> io::Result<u64> {
        match val.vtype {
            #[allow(clippy::cast_ptr_alignment)]
            REG_QWORD => Ok(unsafe { *(val.bytes.as_ptr() as *const u64) }),
            _ => werr!(winerror::ERROR_BAD_FILE_TYPE),
        }
    }
}

/// A trait for types that can be written into registry values.
///
/// **NOTE:** Adds trailing `NULL` character to `str` and `String` values
/// but **not** to `OsStr` values.
pub trait ToRegValue {
    fn to_reg_value(&self) -> RegValue;
}

impl ToRegValue for String {
    fn to_reg_value(&self) -> RegValue {
        RegValue {
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ,
        }
    }
}

impl<'a> ToRegValue for &'a str {
    fn to_reg_value(&self) -> RegValue {
        RegValue {
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ,
        }
    }
}

impl<'a> ToRegValue for &'a OsStr {
    fn to_reg_value(&self) -> RegValue {
        RegValue {
            bytes: v16_to_v8(&(self.encode_wide().collect::<Vec<_>>())),
            vtype: REG_SZ,
        }
    }
}

impl ToRegValue for u32 {
    fn to_reg_value(&self) -> RegValue {
        let bytes: Vec<u8> =
            unsafe { slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() };
        RegValue {
            bytes,
            vtype: REG_DWORD,
        }
    }
}

impl ToRegValue for u64 {
    fn to_reg_value(&self) -> RegValue {
        let bytes: Vec<u8> =
            unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() };
        RegValue {
            bytes,
            vtype: REG_QWORD,
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Unbounded multi-producer, multi-consumer lock-free queue.

use std::ptr;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};

use hazard::{Hazard, Memory, VecMemory};

use {ConsumeError, ProduceError, POINTERS};

//================================================
// Structs
//================================================

// Consumer ______________________________________

/// A consumer for an unbounded MPMC lock-free queue.
#[derive(Debug)]
pub struct Consumer<T>(usize, Arc<Queue<T>>);

impl<T> Consumer<T> {
    //- Accessors --------------------------------

    /// Attempts to remove and return the item at the front of the queue.
    ///
    /// This method returns `Err` if the queue is empty.
    pub fn consume(&self) -> Result<T, ConsumeError> {
        self.1.consume(self.0)
    }

    /// Attempts to clone this consumer.
    pub fn try_clone(&self) -> Option<Self> {
        if let Some(thread) = self.1.threads.lock().unwrap().pop() {
            Some(Consumer(thread, self.1.clone()))
        } else {
            None
        }
    }
}

impl<T> Clone for Consumer<T> {
    fn clone(&self) -> Self {
        self.try_clone().expect("too many producer and consumer clones")
    }
}

impl<T> Drop for Consumer<T> {
    fn drop(&mut self) {
        self.1.consumer.store(0, Ordering::Release);
        self.1.threads.lock().unwrap().push(self.0);
    }
}

unsafe impl<T> Send for Consumer<T> where T: Send { }

// Producer __________________________________

/// A producer for an unbounded MPMC lock-free queue.
#[derive(Debug)]
pub struct Producer<T>(usize, Arc<Queue<T>>);

impl<T> Producer<T> {
    //- Accessors --------------------------------

    /// Attempts to add the supplied item to the back of the queue.
    ///
    /// This method returns `Err` if the queue is full or has no remaining consumers.
    pub fn produce(&self, item: T) -> Result<(), ProduceError<T>> {
        self.1.produce(self.0, item)
    }

    /// Attempts to clone this producer.
    pub fn try_clone(&self) -> Option<Self> {
        if let Some(thread) = self.1.threads.lock().unwrap().pop() {
            Some(Producer(thread, self.1.clone()))
        } else {
            None
        }
    }
}

impl<T> Clone for Producer<T> {
    fn clone(&self) -> Self {
        self.try_clone().expect("too many producer and consumer clones")
    }
}

impl<T> Drop for Producer<T> {
    fn drop(&mut self) {
        self.1.producer.store(0, Ordering::Release);
        self.1.threads.lock().unwrap().push(self.0);
    }
}

unsafe impl<T> Send for Producer<T> where T: Send { }

// Node __________________________________________

#[derive(Debug)]
struct Node<T> {
    item: Option<T>,
    next: AtomicPtr<Node<T>>,
}

impl<T> Node<T> {
    //- Constructors -----------------------------

    fn new(item: Option<T>) -> Self {
        Node { item: item, next: AtomicPtr::new(ptr::null_mut()) }
    }
}

// Queue _________________________________________

const READ: usize = 1;
const WRITE: usize = 0;
const NEXT: usize = 2;

#[derive(Debug)]
#[repr(C)]
struct Queue<T> {
    write: AtomicPtr<Node<T>>,
    consumer: AtomicUsize,
    _wpadding: [usize; POINTERS - 2],
    read: AtomicPtr<Node<T>>,
    producer: AtomicUsize,
    _rpadding: [usize; POINTERS - 2],
    hazard: Hazard<Node<T>, VecMemory>,
    threads: Mutex<Vec<usize>>,
}

impl<T> Queue<T> {
    //- Constructors -----------------------------

    fn new(threads: usize) -> Arc<Self> {
        let sentinel = unsafe { VecMemory.allocate(Node::new(None)) };
        Arc::new(Queue {
            write: AtomicPtr::new(sentinel),
            consumer: AtomicUsize::new(1),
            _wpadding: [0; POINTERS - 2],
            read: AtomicPtr::new(sentinel),
            producer: AtomicUsize::new(1),
            _rpadding: [0; POINTERS - 2],
            hazard: Hazard::new(VecMemory, threads, 3),
            threads: Mutex::new((2..threads).collect()),
        })
    }

    //- Accessors --------------------------------

    fn produce(&self, thread: usize, item: T) -> Result<(), ProduceError<T>> {
        // Return an error if all of the consumers have been disconnected.
        if self.consumer.load(Ordering::Acquire) == 0 {
            return Err(ProduceError::Disconnected(item));
        }

        let node = unsafe { VecMemory.allocate(Node::new(Some(item))) };
        loop {
            let write = self.hazard.mark(thread, WRITE, self.write.load(Ordering::SeqCst));
            if write == self.write.load(Ordering::SeqCst) {
                let next = deref!(write).next.load(Ordering::SeqCst);
                if next.is_null() {
                    // Add the item to the back of the queue if this node is available.
                    if exchange(&deref!(write).next, ptr::null_mut(), node) {
                        exchange(&self.write, write, node);
                        self.hazard.clear(thread, WRITE);
                        return Ok(());
                    }
                } else {
                    // Attempt to update the write pointer.
                    exchange(&self.write, write, next);
                }
            }
        }
    }

    fn consume(&self, thread: usize) -> Result<T, ConsumeError> {
        loop {
            // Return an error if the queue is empty.
            let read = self.hazard.mark(thread, READ, self.read.load(Ordering::SeqCst));
            if read == self.write.load(Ordering::SeqCst) {
                if self.producer.load(Ordering::Acquire) == 0 {
                    return Err(ConsumeError::Disconnected);
                } else {
                    return Err(ConsumeError::Empty);
                }
            }

            // Remove and return the item at the front of the queue if this node is available.
            let next = self.hazard.mark(thread, NEXT, deref!(read).next.load(Ordering::SeqCst));
            if exchange(&self.read, read, next) {
                let item = deref_mut!(next).item.take().unwrap();
                self.hazard.clear(thread, READ);
                self.hazard.clear(thread, NEXT);
                self.hazard.retire(thread, read);
                return Ok(item);
            }
        }
    }
}

impl<T> Drop for Queue<T> {
    fn drop(&mut self) {
        while self.consume(0).is_ok() { }
        unsafe { VecMemory.deallocate(self.write.load(Ordering::Relaxed)); }
    }
}

unsafe impl<T> Sync for Queue<T> where T: Send { }

//================================================
// Functions
//================================================

fn exchange<T>(atomic: &AtomicPtr<Node<T>>, current: *mut Node<T>, new: *mut Node<T>) -> bool {
    atomic.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok()
}

/// Returns a producer and consumer for an unbounded MPMC lock-free queue.
///
/// The value of `clones` indicates the maximum number of clones allowed of the initial producer
/// and consumer. Both types of clones count towards this total.
pub fn channel<T>(clones: usize) -> (Producer<T>, Consumer<T>) {
    let queue = Queue::new(clones + 2);
    (Producer(0, queue.clone()), Consumer(1, queue))
}
<commit_msg>Swap read and write domains<commit_after>// Copyright 2017 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Unbounded multi-producer, multi-consumer lock-free queue.

use std::ptr;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};

use hazard::{Hazard, Memory, VecMemory};

use {ConsumeError, ProduceError, POINTERS};

//================================================
// Structs
//================================================

// Consumer ______________________________________

/// A consumer for an unbounded MPMC lock-free queue.
#[derive(Debug)]
pub struct Consumer<T>(usize, Arc<Queue<T>>);

impl<T> Consumer<T> {
    //- Accessors --------------------------------

    /// Attempts to remove and return the item at the front of the queue.
    ///
    /// This method returns `Err` if the queue is empty.
    pub fn consume(&self) -> Result<T, ConsumeError> {
        self.1.consume(self.0)
    }

    /// Attempts to clone this consumer.
    pub fn try_clone(&self) -> Option<Self> {
        if let Some(thread) = self.1.threads.lock().unwrap().pop() {
            Some(Consumer(thread, self.1.clone()))
        } else {
            None
        }
    }
}

impl<T> Clone for Consumer<T> {
    fn clone(&self) -> Self {
        self.try_clone().expect("too many producer and consumer clones")
    }
}

impl<T> Drop for Consumer<T> {
    fn drop(&mut self) {
        self.1.consumer.store(0, Ordering::Release);
        self.1.threads.lock().unwrap().push(self.0);
    }
}

unsafe impl<T> Send for Consumer<T> where T: Send { }

// Producer __________________________________

/// A producer for an unbounded MPMC lock-free queue.
#[derive(Debug)]
pub struct Producer<T>(usize, Arc<Queue<T>>);

impl<T> Producer<T> {
    //- Accessors --------------------------------

    /// Attempts to add the supplied item to the back of the queue.
    ///
    /// This method returns `Err` if the queue is full or has no remaining consumers.
    pub fn produce(&self, item: T) -> Result<(), ProduceError<T>> {
        self.1.produce(self.0, item)
    }

    /// Attempts to clone this producer.
    pub fn try_clone(&self) -> Option<Self> {
        if let Some(thread) = self.1.threads.lock().unwrap().pop() {
            Some(Producer(thread, self.1.clone()))
        } else {
            None
        }
    }
}

impl<T> Clone for Producer<T> {
    fn clone(&self) -> Self {
        self.try_clone().expect("too many producer and consumer clones")
    }
}

impl<T> Drop for Producer<T> {
    fn drop(&mut self) {
        self.1.producer.store(0, Ordering::Release);
        self.1.threads.lock().unwrap().push(self.0);
    }
}

unsafe impl<T> Send for Producer<T> where T: Send { }

// Node __________________________________________

#[derive(Debug)]
struct Node<T> {
    item: Option<T>,
    next: AtomicPtr<Node<T>>,
}

impl<T> Node<T> {
    //- Constructors -----------------------------

    fn new(item: Option<T>) -> Self {
        Node { item: item, next: AtomicPtr::new(ptr::null_mut()) }
    }
}

// Queue _________________________________________

const READ: usize = 0;
const WRITE: usize = 1;
const NEXT: usize = 2;

#[derive(Debug)]
#[repr(C)]
struct Queue<T> {
    write: AtomicPtr<Node<T>>,
    consumer: AtomicUsize,
    _wpadding: [usize; POINTERS - 2],
    read: AtomicPtr<Node<T>>,
    producer: AtomicUsize,
    _rpadding: [usize; POINTERS - 2],
    hazard: Hazard<Node<T>, VecMemory>,
    threads: Mutex<Vec<usize>>,
}

impl<T> Queue<T> {
    //- Constructors -----------------------------

    fn new(threads: usize) -> Arc<Self> {
        let sentinel = unsafe { VecMemory.allocate(Node::new(None)) };
        Arc::new(Queue {
            write: AtomicPtr::new(sentinel),
            consumer: AtomicUsize::new(1),
            _wpadding: [0; POINTERS - 2],
            read: AtomicPtr::new(sentinel),
            producer: AtomicUsize::new(1),
            _rpadding: [0; POINTERS - 2],
            hazard: Hazard::new(VecMemory, threads, 3),
            threads: Mutex::new((2..threads).collect()),
        })
    }

    //- Accessors --------------------------------

    fn produce(&self, thread: usize, item: T) -> Result<(), ProduceError<T>> {
        // Return an error if all of the consumers have been disconnected.
        if self.consumer.load(Ordering::Acquire) == 0 {
            return Err(ProduceError::Disconnected(item));
        }

        let node = unsafe { VecMemory.allocate(Node::new(Some(item))) };
        loop {
            let write = self.hazard.mark(thread, WRITE, self.write.load(Ordering::SeqCst));
            if write == self.write.load(Ordering::SeqCst) {
                let next = deref!(write).next.load(Ordering::SeqCst);
                if next.is_null() {
                    // Add the item to the back of the queue if this node is available.
                    if exchange(&deref!(write).next, ptr::null_mut(), node) {
                        exchange(&self.write, write, node);
                        self.hazard.clear(thread, WRITE);
                        return Ok(());
                    }
                } else {
                    // Attempt to update the write pointer.
                    exchange(&self.write, write, next);
                }
            }
        }
    }

    fn consume(&self, thread: usize) -> Result<T, ConsumeError> {
        loop {
            // Return an error if the queue is empty.
            let read = self.hazard.mark(thread, READ, self.read.load(Ordering::SeqCst));
            if read == self.write.load(Ordering::SeqCst) {
                if self.producer.load(Ordering::Acquire) == 0 {
                    return Err(ConsumeError::Disconnected);
                } else {
                    return Err(ConsumeError::Empty);
                }
            }

            // Remove and return the item at the front of the queue if this node is available.
            let next = self.hazard.mark(thread, NEXT, deref!(read).next.load(Ordering::SeqCst));
            if exchange(&self.read, read, next) {
                let item = deref_mut!(next).item.take().unwrap();
                self.hazard.clear(thread, READ);
                self.hazard.clear(thread, NEXT);
                self.hazard.retire(thread, read);
                return Ok(item);
            }
        }
    }
}

impl<T> Drop for Queue<T> {
    fn drop(&mut self) {
        while self.consume(0).is_ok() { }
        unsafe { VecMemory.deallocate(self.write.load(Ordering::Relaxed)); }
    }
}

unsafe impl<T> Sync for Queue<T> where T: Send { }

//================================================
// Functions
//================================================

fn exchange<T>(atomic: &AtomicPtr<Node<T>>, current: *mut Node<T>, new: *mut Node<T>) -> bool {
    atomic.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok()
}

/// Returns a producer and consumer for an unbounded MPMC lock-free queue.
///
/// The value of `clones` indicates the maximum number of clones allowed of the initial producer
/// and consumer. Both types of clones count towards this total.
pub fn channel<T>(clones: usize) -> (Producer<T>, Consumer<T>) {
    let queue = Queue::new(clones + 2);
    (Producer(0, queue.clone()), Consumer(1, queue))
}
<|endoftext|>