<commit_before>use std::default::Default;
use std::path::Path;
use std::fs::File;
use std::io::Read;
use error::Result;
use yaml_rust::YamlLoader;

use syntax_highlight::has_syntax_theme;

arg_enum! {
    #[derive(Debug, PartialEq, Copy, Clone)]
    pub enum Dump {
        DocObject,
        DocTemplate,
        DocLinkObject,
        Document
    }
}

impl Dump {
    pub fn is_doc(&self) -> bool {
        true
    }
}

#[derive(Debug, PartialEq)]
pub struct Config {
    pub source: String,
    pub dest: String,
    pub layouts: String,
    pub drafts: String,
    pub include_drafts: bool,
    pub posts: String,
    pub post_path: Option<String>,
    pub post_order: String,
    pub template_extensions: Vec<String>,
    pub rss: Option<String>,
    pub jsonfeed: Option<String>,
    pub name: Option<String>,
    pub description: Option<String>,
    pub link: Option<String>,
    pub ignore: Vec<String>,
    pub excerpt_separator: String,
    pub dump: Vec<Dump>,
    pub syntax_theme: String,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            source: "./".to_owned(),
            dest: "./".to_owned(),
            layouts: "_layouts".to_owned(),
            drafts: "_drafts".to_owned(),
            include_drafts: false,
            posts: "posts".to_owned(),
            post_path: None,
            post_order: "desc".to_owned(),
            template_extensions: vec!["md".to_owned(), "liquid".to_owned()],
            rss: None,
            jsonfeed: None,
            name: None,
            description: None,
            link: None,
            ignore: vec![],
            excerpt_separator: "\n\n".to_owned(),
            dump: vec![],
            syntax_theme: "base16-ocean.dark".to_owned(),
        }
    }
}

impl Config {
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> {
        let mut buffer = String::new();
        let mut f = try!(File::open(path));
        try!(f.read_to_string(&mut buffer));

        let yaml = try!(YamlLoader::load_from_str(&buffer));
        let yaml = match yaml.get(0) {
            Some(y) => y,
            None => return Ok(Default::default()),
        };

        let mut config = Config {
            name: yaml["name"].as_str().map(|s| s.to_owned()),
            rss: yaml["rss"].as_str().map(|s| s.to_owned()),
            jsonfeed: yaml["jsonfeed"].as_str().map(|s| s.to_owned()),
            description: yaml["description"].as_str().map(|s| s.to_owned()),
            post_path: yaml["post_path"].as_str().map(|s| s.to_owned()),
            ..Default::default()
        };

        if let Some(source) = yaml["source"].as_str() {
            config.source = source.to_owned();
        };

        if let Some(dest) = yaml["dest"].as_str() {
            config.dest = dest.to_owned();
        };

        if let Some(layouts) = yaml["layouts"].as_str() {
            config.layouts = layouts.to_owned();
        };

        if let Some(drafts) = yaml["drafts"].as_str() {
            config.drafts = drafts.to_owned();
        };

        if let Some(include_drafts) = yaml["include_drafts"].as_bool() {
            config.include_drafts = include_drafts;
        };

        if let Some(posts) = yaml["posts"].as_str() {
            config.posts = posts.to_owned();
        };

        if let Some(post_order) = yaml["post_order"].as_str() {
            config.post_order = post_order.to_owned();
        };

        if let Some(extensions) = yaml["template_extensions"].as_vec() {
            config.template_extensions = extensions
                .iter()
                .filter_map(|k| k.as_str().map(|k| k.to_owned()))
                .collect();
        };

        if let Some(link) = yaml["link"].as_str() {
            let mut link = link.to_owned();
            if !link.ends_with('/') {
                link += "/";
            }
            config.link = Some(link);
        };

        if let Some(patterns) = yaml["ignore"].as_vec() {
            config.ignore = patterns
                .iter()
                .filter_map(|k| k.as_str())
                .map(|k| k.to_owned())
                .collect();
        };

        if let Some(excerpt_separator) = yaml["excerpt_separator"].as_str() {
            config.excerpt_separator = excerpt_separator.to_owned();
        };

        if let Some(theme) = yaml["syntax-highlight"]["theme"].as_str() {
            let result: Result<()> = match has_syntax_theme(theme) {
                Ok(true) => {
                    config.syntax_theme = theme.to_owned();
                    Ok(())
                }
                Ok(false) => Err(format!("Syntax theme '{}' is unsupported", theme).into()),
                Err(err) => {
                    warn!("Syntax theme named '{}' ignored. Reason: {:?}", theme, err);
                    Ok(())
                }
            };
            result?;
        };

        Ok(config)
    }
}

#[test]
fn test_from_file_ok() {
    let result = Config::from_file("tests/fixtures/config/.cobalt.yml");
    assert!(result.is_ok());
    assert_eq!(result.unwrap(),
               Config {
                   dest: "./dest".to_owned(),
                   layouts: "_my_layouts".to_owned(),
                   posts: "_my_posts".to_owned(),
                   ..Default::default()
               });
}

#[test]
fn test_from_file_rss() {
    let result = Config::from_file("tests/fixtures/config/rss.yml");
    assert!(result.is_ok());
    assert_eq!(result.unwrap(),
               Config {
                   rss: Some("rss.xml".to_owned()),
                   name: Some("My blog!".to_owned()),
                   description: Some("Blog description".to_owned()),
                   link: Some("http://example.com/".to_owned()),
                   ..Default::default()
               });
}

#[test]
fn test_from_file_empty() {
    let result = Config::from_file("tests/fixtures/config/empty.yml");
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), Config { ..Default::default() });
}

#[test]
fn test_from_file_invalid_syntax() {
    let result = Config::from_file("tests/fixtures/config/invalid_syntax.yml");
    assert!(result.is_err());
}

#[test]
fn test_from_file_not_found() {
    let result = Config::from_file("tests/fixtures/config/config_does_not_exist.yml");
    assert!(result.is_err());
}
<commit_msg>tests: Improve failure reporting<commit_after>use std::default::Default;
use std::path::Path;
use std::fs::File;
use std::io::Read;
use error::Result;
use yaml_rust::YamlLoader;

use syntax_highlight::has_syntax_theme;

arg_enum! {
    #[derive(Debug, PartialEq, Copy, Clone)]
    pub enum Dump {
        DocObject,
        DocTemplate,
        DocLinkObject,
        Document
    }
}

impl Dump {
    pub fn is_doc(&self) -> bool {
        true
    }
}

#[derive(Debug, PartialEq)]
pub struct Config {
    pub source: String,
    pub dest: String,
    pub layouts: String,
    pub drafts: String,
    pub include_drafts: bool,
    pub posts: String,
    pub post_path: Option<String>,
    pub post_order: String,
    pub template_extensions: Vec<String>,
    pub rss: Option<String>,
    pub jsonfeed: Option<String>,
    pub name: Option<String>,
    pub description: Option<String>,
    pub link: Option<String>,
    pub ignore: Vec<String>,
    pub excerpt_separator: String,
    pub dump: Vec<Dump>,
    pub syntax_theme: String,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            source: "./".to_owned(),
            dest: "./".to_owned(),
            layouts: "_layouts".to_owned(),
            drafts: "_drafts".to_owned(),
            include_drafts: false,
            posts: "posts".to_owned(),
            post_path: None,
            post_order: "desc".to_owned(),
            template_extensions: vec!["md".to_owned(), "liquid".to_owned()],
            rss: None,
            jsonfeed: None,
            name: None,
            description: None,
            link: None,
            ignore: vec![],
            excerpt_separator: "\n\n".to_owned(),
            dump: vec![],
            syntax_theme: "base16-ocean.dark".to_owned(),
        }
    }
}

impl Config {
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> {
        let mut buffer = String::new();
        let mut f = try!(File::open(path));
        try!(f.read_to_string(&mut buffer));

        let yaml = try!(YamlLoader::load_from_str(&buffer));
        let yaml = match yaml.get(0) {
            Some(y) => y,
            None => return Ok(Default::default()),
        };

        let mut config = Config {
            name: yaml["name"].as_str().map(|s| s.to_owned()),
            rss: yaml["rss"].as_str().map(|s| s.to_owned()),
            jsonfeed: yaml["jsonfeed"].as_str().map(|s| s.to_owned()),
            description: yaml["description"].as_str().map(|s| s.to_owned()),
            post_path: yaml["post_path"].as_str().map(|s| s.to_owned()),
            ..Default::default()
        };

        if let Some(source) = yaml["source"].as_str() {
            config.source = source.to_owned();
        };

        if let Some(dest) = yaml["dest"].as_str() {
            config.dest = dest.to_owned();
        };

        if let Some(layouts) = yaml["layouts"].as_str() {
            config.layouts = layouts.to_owned();
        };

        if let Some(drafts) = yaml["drafts"].as_str() {
            config.drafts = drafts.to_owned();
        };

        if let Some(include_drafts) = yaml["include_drafts"].as_bool() {
            config.include_drafts = include_drafts;
        };

        if let Some(posts) = yaml["posts"].as_str() {
            config.posts = posts.to_owned();
        };

        if let Some(post_order) = yaml["post_order"].as_str() {
            config.post_order = post_order.to_owned();
        };

        if let Some(extensions) = yaml["template_extensions"].as_vec() {
            config.template_extensions = extensions
                .iter()
                .filter_map(|k| k.as_str().map(|k| k.to_owned()))
                .collect();
        };

        if let Some(link) = yaml["link"].as_str() {
            let mut link = link.to_owned();
            if !link.ends_with('/') {
                link += "/";
            }
            config.link = Some(link);
        };

        if let Some(patterns) = yaml["ignore"].as_vec() {
            config.ignore = patterns
                .iter()
                .filter_map(|k| k.as_str())
                .map(|k| k.to_owned())
                .collect();
        };

        if let Some(excerpt_separator) = yaml["excerpt_separator"].as_str() {
            config.excerpt_separator = excerpt_separator.to_owned();
        };

        if let Some(theme) = yaml["syntax-highlight"]["theme"].as_str() {
            let result: Result<()> = match has_syntax_theme(theme) {
                Ok(true) => {
                    config.syntax_theme = theme.to_owned();
                    Ok(())
                }
                Ok(false) => Err(format!("Syntax theme '{}' is unsupported", theme).into()),
                Err(err) => {
                    warn!("Syntax theme named '{}' ignored. Reason: {:?}", theme, err);
                    Ok(())
                }
            };
            result?;
        };

        Ok(config)
    }
}

#[test]
fn test_from_file_ok() {
    let result = Config::from_file("tests/fixtures/config/.cobalt.yml").unwrap();
    assert_eq!(result,
               Config {
                   dest: "./dest".to_owned(),
                   layouts: "_my_layouts".to_owned(),
                   posts: "_my_posts".to_owned(),
                   ..Default::default()
               });
}

#[test]
fn test_from_file_rss() {
    let result = Config::from_file("tests/fixtures/config/rss.yml").unwrap();
    assert_eq!(result,
               Config {
                   rss: Some("rss.xml".to_owned()),
                   name: Some("My blog!".to_owned()),
                   description: Some("Blog description".to_owned()),
                   link: Some("http://example.com/".to_owned()),
                   ..Default::default()
               });
}

#[test]
fn test_from_file_empty() {
    let result = Config::from_file("tests/fixtures/config/empty.yml").unwrap();
    assert_eq!((result), Config { ..Default::default() });
}

#[test]
fn test_from_file_invalid_syntax() {
    let result = Config::from_file("tests/fixtures/config/invalid_syntax.yml");
    assert!(result.is_err());
}

#[test]
fn test_from_file_not_found() {
    let result = Config::from_file("tests/fixtures/config/config_does_not_exist.yml");
    assert!(result.is_err());
}
<|endoftext|>


<commit_before>#![feature(convert)]
#![feature(slice_patterns)]
#![feature(collections)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

// TODO use an ADT here (#1)
#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  pub fn run(&mut self) {
    // just some aliases for brevity
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false;

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["push", "int", n] => self.stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => self.stack.push(Expr::Str(String::from_str(n))),

        // convert to string
        ["strconv", "int"] => if let Some(&Expr::Int(arg)) = self.stack.last() {
          self.stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        //["cmp", "<"] =>

        // how = "carry" | "always"
        ["jump", how, n] => {
          let new_ip = n.parse::<usize>().unwrap();

          if new_ip < len {
            // only check carry if we're not conditionally jumping
            if how != "carry" || carry {
              ip = new_ip;
            }
            // only reset carry if it was used
            if how == "carry" {
              carry = false;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "say"] => if let Some(Expr::Str(arg)) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call! a call to infix:<...>, that is
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          self.stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `add`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO name should probably be an identifier under SSAF, see backend#1
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"), // todo err!
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>Fix misleading comments<commit_after>#![feature(convert)]
#![feature(slice_patterns)]
#![feature(collections)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

// TODO use an ADT here (#1)
#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  pub fn run(&mut self) {
    // just some aliases for brevity
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false;

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["push", "int", n] => self.stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => self.stack.push(Expr::Str(String::from_str(n))),

        // convert to string
        ["strconv", "int"] => if let Some(&Expr::Int(arg)) = self.stack.last() {
          self.stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        // how = "carry" | "always"
        ["jump", how, n] => {
          let new_ip = n.parse::<usize>().unwrap();

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how != "carry" || carry {
              ip = new_ip;
            }
            // only reset carry if it was used
            if how == "carry" {
              carry = false;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "say"] => if let Some(Expr::Str(arg)) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call! a call to infix:<...>, that is
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          self.stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `add`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;

#[derive(Debug, Default, Deserialize)]
pub struct Error {
    pub detail: String,
}

#[derive(Debug, Deserialize)]
pub struct CrateLinks {
    pub owners: Option<String>,
    pub reverse_dependencies: String,
    pub version_downloads: String,
    pub versions: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct Crate {
    pub created_at: String,
    pub description: Option<String>,
    pub documentation: Option<String>,
    pub downloads: i32,
    pub homepage: Option<String>,
    pub id: String,
    pub keywords: Option<Vec<String>>,
    pub license: Option<String>,
    pub links: CrateLinks,
    pub max_version: String,
    pub name: String,
    pub repository: Option<String>,
    pub updated_at: String,
    pub versions: Option<Vec<u64>>,
}

impl Crate {
    pub fn print_repository(&self, verbose: bool) {
        if let Some(repository) = self.repository.as_ref() {
            let fmt = if verbose {
                format!("{:<16}{}", "Repository:", repository)
            } else {
                repository.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_documentation(&self, verbose: bool) {
        if let Some(documentation) = self.documentation.as_ref() {
            let fmt = if verbose {
                format!("{:<16}{}", "Documentation:", documentation)
            } else {
                documentation.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_downloads(&self, verbose: bool) {
        let fmt = if verbose {
            format!("{:<16}{}", "Downloads:", self.downloads)
        } else {
            format!("{}", self.downloads)
        };
        println!("{}", fmt);
    }

    pub fn print_homepage(&self, verbose: bool) {
        if let Some(homepage) = self.homepage.as_ref() {
            let fmt = if verbose {
                format!("{:<16}{}", "Homepage:", homepage)
            } else {
                homepage.clone()
            };
            println!("{}", fmt);
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Keyword {
    pub crates_cnt: u64,
    pub created_at: String,
    pub id: String,
    pub keyword: String,
}

#[derive(Debug, Deserialize)]
pub struct VersionLinks {
    pub authors: String,
    pub dependencies: String,
    pub version_downloads: String,
}

#[derive(Debug, Deserialize)]
pub struct Version {
    #[serde(rename="crate")]
    pub krate: String,
    pub created_at: String,
    pub dl_path: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub id: i32,
    pub links: VersionLinks,
    pub num: String,
    pub updated_at: String,
    pub yanked: bool,
}

#[derive(Debug, Deserialize)]
pub struct Reply {
    #[serde(default)]
    pub errors: Error,
    #[serde(rename="crate")]
    pub krate: Crate,
    pub keywords: Vec<Keyword>,
    pub versions: Vec<Version>,
}

impl fmt::Display for Crate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let empty = &String::new();
        let empty_vec = &vec![empty.clone()];
        let description = self.description.as_ref().unwrap_or(empty);
        let documentation = self.documentation.as_ref().unwrap_or(empty);
        let homepage = self.homepage.as_ref().unwrap_or(empty);
        let repository = self.repository.as_ref().unwrap_or(empty);
        let license = self.license.as_ref().unwrap_or(empty);
        let keywords = self.keywords.as_ref().unwrap_or(empty_vec);

        if f.alternate() {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", self.name),
                   format_args!("{:<16}{}", "Version:", self.max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", self.downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository),
                   format_args!("{:<16}{}", "License:", license),
                   format_args!("{:<16}{:?}", "Keywords:", keywords),
                   format_args!("{:<16}{}", "Created at:", self.created_at),
                   format_args!("{:<16}{}", "Updated at:", self.updated_at))
        } else {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", self.name),
                   format_args!("{:<16}{}", "Version:", self.max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", self.downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository))
        }
    }
}

pub type CratesReply = HashMap<String, String>;

#[derive(Deserialize, Debug)]
struct GenericResponse {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}
<commit_msg>Reporting pretty JSON text requires deriving Serialize<commit_after>use std::collections::HashMap;
use std::fmt;

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Error {
    pub detail: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct CrateLinks {
    pub owners: Option<String>,
    pub reverse_dependencies: String,
    pub version_downloads: String,
    pub versions: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Crate {
    pub created_at: String,
    pub description: Option<String>,
    pub documentation: Option<String>,
    pub downloads: i32,
    pub homepage: Option<String>,
    pub id: String,
    pub keywords: Option<Vec<String>>,
    pub license: Option<String>,
    pub links: CrateLinks,
    pub max_version: String,
    pub name: String,
    pub repository: Option<String>,
    pub updated_at: String,
    pub versions: Option<Vec<u64>>,
}

impl Crate {
    pub fn print_repository(&self, verbose: bool) {
        if let Some(repository) = self.repository.as_ref() {
            let fmt = if verbose {
                format!("{:<16}{}", "Repository:", repository)
            } else {
                repository.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_documentation(&self, verbose: bool) {
        if let Some(documentation) = self.documentation.as_ref() {
            let fmt = if verbose {
                format!("{:<16}{}", "Documentation:", documentation)
            } else {
                documentation.clone()
            };
            println!("{}", fmt);
        }
    }

    pub fn print_downloads(&self, verbose: bool) {
        let fmt = if verbose {
            format!("{:<16}{}", "Downloads:", self.downloads)
        } else {
            format!("{}", self.downloads)
        };
        println!("{}", fmt);
    }

    pub fn print_homepage(&self, verbose: bool) {
        if let Some(homepage) = self.homepage.as_ref() {
            let fmt = if verbose {
                format!("{:<16}{}", "Homepage:", homepage)
            } else {
                homepage.clone()
            };
            println!("{}", fmt);
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Keyword {
    pub crates_cnt: u64,
    pub created_at: String,
    pub id: String,
    pub keyword: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct VersionLinks {
    pub authors: String,
    pub dependencies: String,
    pub version_downloads: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Version {
    #[serde(rename="crate")]
    pub krate: String,
    pub created_at: String,
    pub dl_path: String,
    pub downloads: i32,
    pub features: HashMap<String, Vec<String>>,
    pub id: i32,
    pub links: VersionLinks,
    pub num: String,
    pub updated_at: String,
    pub yanked: bool,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Reply {
    #[serde(default)]
    pub errors: Error,
    #[serde(rename="crate")]
    pub krate: Crate,
    pub keywords: Vec<Keyword>,
    pub versions: Vec<Version>,
}

impl fmt::Display for Crate {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let empty = &String::new();
        let empty_vec = &vec![empty.clone()];
        let description = self.description.as_ref().unwrap_or(empty);
        let documentation = self.documentation.as_ref().unwrap_or(empty);
        let homepage = self.homepage.as_ref().unwrap_or(empty);
        let repository = self.repository.as_ref().unwrap_or(empty);
        let license = self.license.as_ref().unwrap_or(empty);
        let keywords = self.keywords.as_ref().unwrap_or(empty_vec);

        if f.alternate() {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", self.name),
                   format_args!("{:<16}{}", "Version:", self.max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", self.downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository),
                   format_args!("{:<16}{}", "License:", license),
                   format_args!("{:<16}{:?}", "Keywords:", keywords),
                   format_args!("{:<16}{}", "Created at:", self.created_at),
                   format_args!("{:<16}{}", "Updated at:", self.updated_at))
        } else {
            write!(f,
                   "{}\n{}\n{}\n{}\n{}\n{}\n{}",
                   format_args!("{:<16}{}", "Crate:", self.name),
                   format_args!("{:<16}{}", "Version:", self.max_version),
                   format_args!("{:<16}{}", "Description:", description),
                   format_args!("{:<16}{}", "Downloads:", self.downloads),
                   format_args!("{:<16}{}", "Homepage:", homepage),
                   format_args!("{:<16}{}", "Documentation:", documentation),
                   format_args!("{:<16}{}", "Repository:", repository))
        }
    }
}

pub type CratesReply = HashMap<String, String>;

#[derive(Deserialize, Debug)]
struct GenericResponse {
    args: HashMap<String, String>,
    data: Option<String>,
    files: Option<HashMap<String, String>>,
    form: Option<HashMap<String, String>>,
    headers: HashMap<String, String>,
    json: Option<String>,
    origin: String,
    url: String,
}
<|endoftext|>


<commit_before>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}
<commit_msg>Removed Copy bound on SIMD ops May as well remove unecessary bounds, even when any SIMD-able numeric is always Copy.<commit_after>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}
<|endoftext|>


<commit_before>
use std;
use piston::{
    GameEvent,
    KeyPress,
    KeyPressArgs,
    keyboard,
    Update,
    UpdateArgs,
};
use {
    Event,
    StartState,
    Status,
    Failure,
    Success,
    Running,
};

/// Keeps track of an event.
pub enum Cursor<'a, A, S> {
    /// Keeps track of whether a key was pressed.
    KeyPressedCursor(keyboard::Key),
    /// Keeps track of an event where you have a state of an action.
    State(&'a A, S),
    /// Keeps track of an event where you wait and do nothing.
    WaitCursor(f64, f64),
    /// Keeps track of an event where sub events happens sequentially.
    SequenceCursor(&'a Vec<Event<A>>, uint, Box<Cursor<'a, A, S>>),
    /// Keeps track of an event where sub events are repeated sequentially.
    WhileCursor(Box<Cursor<'a, A, S>>, &'a Vec<Event<A>>, uint, Box<Cursor<'a, A, S>>),
    /// Keeps track of an event where all sub events must happen.
    WhenAllCursor(Vec<Option<Cursor<'a, A, S>>>),
}

impl<'a, A: StartState<S>, S> Cursor<'a, A, S> {
    /// Updates the cursor that tracks an event.
    ///
    /// Returns `Running` if the action did not terminate.
    /// or `Success(dt)` or `Failure(dt)` that tells how much time is left of the update time.
    pub fn update(
        &mut self,
        e: &GameEvent,
        f: |action: &'a A, state: &mut S| -> Status
    ) -> (Status, f64) {
        match (e, self) {
            (&KeyPress(KeyPressArgs { key: key_pressed }), &KeyPressedCursor(key))
            if key_pressed == key => {
                // Key press is considered to happen instantly.
                (Success, 0.0)
            },
            (&Update(UpdateArgs { dt }), &State(action, ref mut state)) => {
                // Call the function that updates the state.
                (f(action, state), dt)
            },
            (&Update(UpdateArgs { dt }), &WaitCursor(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    (Running, 0.0)
                }
            },
            (_, &SequenceCursor(
                seq,
                ref mut i,
                ref mut cursor
            )) => {
                let cur = cursor;
                let mut remaining_e = *e;
                while *i < seq.len() {
                    match cur.update(&remaining_e, |action, state| f(action, state)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_e = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => Update(UpdateArgs { dt: new_dt }),
                                // Other events are 'consumed' and not passed to next.
                                // If this is the last event, then the sequence succeeded.
                                _ => if *i == seq.len() - 1 {
                                        return (Success, new_dt)
                                    } else {
                                        return (Running, 0.0)
                                    }
                            }
                        }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    // This has to be an update event, because all other cases return early.
                    if *i >= seq.len() { return (Success, match remaining_e {
                            Update(UpdateArgs { dt }) => dt,
                            _ => unreachable!()
                        }); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = seq[*i].to_cursor();
                }
                (Running, 0.0)
            },
            (_, &WhileCursor(
                ref mut ev_cursor,
                rep,
                ref mut i,
                ref mut cursor
            )) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.update(e, |action, state| f(action, state)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_e = *e;
                loop {
                    match cur.update(&remaining_e, |action, state| f(action, state)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_e = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => Update(UpdateArgs { dt: new_dt }),
                                // Other events are 'consumed' and not passed to next.
                                _ => return (Running, 0.0)
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = rep[*i].to_cursor();
                }
                (Running, 0.0)
            },
            (_, &WhenAllCursor(ref mut cursors)) => {
                // Get the least delta time left over.
                let mut min_dt = std::f64::MAX_VALUE;
                // Count number of terminated events.
                let mut terminated = 0;
                for cur in cursors.mut_iter() {
                    match *cur {
                        None => terminated += 1,
                        Some(ref mut cur) => {
                            match cur.update(
                                e,
                                |action, state| f(action, state)
                            ) {
                                (Running, _) => {},
                                (Failure, new_dt) => return (Failure, new_dt),
                                (Success, new_dt) => {
                                    min_dt = min_dt.min(new_dt);
                                    terminated += 1;
                                }
                            }
                        }
                    }
                }
                match terminated {
                    // If there are no events, there is a whole 'dt' left.
                    0 if cursors.len() == 0 => (Success, match *e {
                            Update(UpdateArgs { dt }) => dt,
                            // Other kind of events happen instantly.
                            _ => 0.0
                        }),
                    // If all events terminated, the least delta time is left.
                    n if cursors.len() == n => (Success, min_dt),
                    _ => (Running, 0.0)
                }
            },
            _ => (Running, 0.0)
        }
    }
}

<commit_msg>Fixed comment<commit_after>
use std;
use piston::{
    GameEvent,
    KeyPress,
    KeyPressArgs,
    keyboard,
    Update,
    UpdateArgs,
};
use {
    Event,
    StartState,
    Status,
    Failure,
    Success,
    Running,
};

/// Keeps track of an event.
pub enum Cursor<'a, A, S> {
    /// Keeps track of whether a key was pressed.
    KeyPressedCursor(keyboard::Key),
    /// Keeps track of an event where you have a state of an action.
    State(&'a A, S),
    /// Keeps track of an event where you wait and do nothing.
    WaitCursor(f64, f64),
    /// Keeps track of an event where sub events happens sequentially.
    SequenceCursor(&'a Vec<Event<A>>, uint, Box<Cursor<'a, A, S>>),
    /// Keeps track of an event where sub events are repeated sequentially.
    WhileCursor(Box<Cursor<'a, A, S>>, &'a Vec<Event<A>>, uint, Box<Cursor<'a, A, S>>),
    /// Keeps track of an event where all sub events must happen.
    WhenAllCursor(Vec<Option<Cursor<'a, A, S>>>),
}

impl<'a, A: StartState<S>, S> Cursor<'a, A, S> {
    /// Updates the cursor that tracks an event.
    ///
    /// Returns status and the remaining delta time.
    pub fn update(
        &mut self,
        e: &GameEvent,
        f: |action: &'a A, state: &mut S| -> Status
    ) -> (Status, f64) {
        match (e, self) {
            (&KeyPress(KeyPressArgs { key: key_pressed }), &KeyPressedCursor(key))
            if key_pressed == key => {
                // Key press is considered to happen instantly.
                (Success, 0.0)
            },
            (&Update(UpdateArgs { dt }), &State(action, ref mut state)) => {
                // Call the function that updates the state.
                (f(action, state), dt)
            },
            (&Update(UpdateArgs { dt }), &WaitCursor(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    (Running, 0.0)
                }
            },
            (_, &SequenceCursor(
                seq,
                ref mut i,
                ref mut cursor
            )) => {
                let cur = cursor;
                let mut remaining_e = *e;
                while *i < seq.len() {
                    match cur.update(&remaining_e, |action, state| f(action, state)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_e = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => Update(UpdateArgs { dt: new_dt }),
                                // Other events are 'consumed' and not passed to next.
                                // If this is the last event, then the sequence succeeded.
                                _ => if *i == seq.len() - 1 {
                                        return (Success, new_dt)
                                    } else {
                                        return (Running, 0.0)
                                    }
                            }
                        }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    // This has to be an update event, because all other cases return early.
                    if *i >= seq.len() { return (Success, match remaining_e {
                            Update(UpdateArgs { dt }) => dt,
                            _ => unreachable!()
                        }); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = seq[*i].to_cursor();
                }
                (Running, 0.0)
            },
            (_, &WhileCursor(
                ref mut ev_cursor,
                rep,
                ref mut i,
                ref mut cursor
            )) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.update(e, |action, state| f(action, state)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_e = *e;
                loop {
                    match cur.update(&remaining_e, |action, state| f(action, state)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_e = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => Update(UpdateArgs { dt: new_dt }),
                                // Other events are 'consumed' and not passed to next.
                                _ => return (Running, 0.0)
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = rep[*i].to_cursor();
                }
                (Running, 0.0)
            },
            (_, &WhenAllCursor(ref mut cursors)) => {
                // Get the least delta time left over.
                let mut min_dt = std::f64::MAX_VALUE;
                // Count number of terminated events.
                let mut terminated = 0;
                for cur in cursors.mut_iter() {
                    match *cur {
                        None => terminated += 1,
                        Some(ref mut cur) => {
                            match cur.update(
                                e,
                                |action, state| f(action, state)
                            ) {
                                (Running, _) => {},
                                (Failure, new_dt) => return (Failure, new_dt),
                                (Success, new_dt) => {
                                    min_dt = min_dt.min(new_dt);
                                    terminated += 1;
                                }
                            }
                        }
                    }
                }
                match terminated {
                    // If there are no events, there is a whole 'dt' left.
                    0 if cursors.len() == 0 => (Success, match *e {
                            Update(UpdateArgs { dt }) => dt,
                            // Other kind of events happen instantly.
                            _ => 0.0
                        }),
                    // If all events terminated, the least delta time is left.
                    n if cursors.len() == n => (Success, min_dt),
                    _ => (Running, 0.0)
                }
            },
            _ => (Running, 0.0)
        }
    }
}

<|endoftext|>


<commit_before>use std::io::{Read, Write};
use super::event::{Event, EventType};
use super::handler::{Handler, Message};
use super::listener::{ListenerHandle, Listener};
use super::request::{ConfigGroup, Request};
use super::response::Response;
use super::scope::Scope;
use super::error::{ReceiveError, Error};
use std::cell::RefCell;

/// The base DaZeus struct.
///
/// See the [crate documentation](./index.html) for a more detailed instruction on how to get
/// started with these DaZeus bindings.
pub struct DaZeus<'a, T> where T: Read + Write {
    handler: RefCell<Handler<T>>,
    listeners: Vec<Listener<'a, T>>,
    current_handle: u64,
}

impl<'a, T> DaZeus<'a, T> where T: Read + Write {
    /// Create a new instance of DaZeus from the given connection.
    pub fn new(conn: T) -> DaZeus<'a, T> {
        DaZeus {
            handler: RefCell::new(Handler::new(conn)),
            listeners: Vec::new(),
            current_handle: 1
        }
    }

    fn next_response(&self) -> Result<Response, Error> {
        loop {
            match try!(self.handler.borrow_mut().read()) {
                Message::Event(e) => self.handle_event(e),
                Message::Response(r) => return Ok(r),
            }
        }
    }

    fn try_next_event(&self) -> Result<Event, Error> {
        match try!(self.handler.borrow_mut().read()) {
            Message::Event(e) => {
                self.handle_event(e.clone());
                Ok(e)
            },
            Message::Response(_) => Err(Error::ReceiveError(ReceiveError::new())),
        }
    }

    fn next_event(&self) -> Event {
        match self.try_next_event() {
            Ok(evt) => evt,
            Err(e) => panic!("{}", e),
        }
    }

    /// Send a request to DaZeus and retrieve a Future in which the response will be contained.
    pub fn send(&self, request: Request) -> Response {
        match self.try_send(request) {
            Ok(response) => response,
            Err(e) => panic!("{}", e),
        }
    }

    /// Try to send a request to DaZeus
    pub fn try_send(&self, request: Request) -> Result<Response, Error> {
        try!(self.handler.borrow_mut().write(request));
        self.next_response()
    }

    /// Handle an event received by calling all event listeners listening for that event type.
    fn handle_event(&self, event: Event) {
        for listener in self.listeners.iter() {
            if listener.event == event.event {
                listener.call(event.clone(), self);
            }
        }
    }

    /// Loop wait for messages to receive in a blocking way.
    pub fn listen(&self) -> Result<(), Error> {
        loop {
            try!(self.try_next_event());
        }
    }

    /// Subscribe to an event type and call the callback function every time such an event occurs.
    pub fn subscribe<F>(&mut self, event: EventType, callback: F) -> (ListenerHandle, Response)
        where F: FnMut(Event, &DaZeus<T>) + 'a
    {
        let request = match event {
            EventType::Command(ref cmd) => Request::SubscribeCommand(cmd.clone(), None),
            _ => Request::Subscribe(event.clone()),
        };

        let handle = self.current_handle;
        self.current_handle += 1;
        let listener = Listener::new(handle, event, callback);

        self.listeners.push(listener);
        (handle, self.send(request))
    }

    /// Subscribe to a command and call the callback function every time such a command occurs.
    pub fn subscribe_command<F>(&mut self, command: &str, callback: F) -> (ListenerHandle, Response)
        where F: FnMut(Event, &DaZeus<T>) + 'a
    {
        self.subscribe(EventType::Command(command.to_string()), callback)
    }

    /// Unsubscribe a listener for some event.
    pub fn unsubscribe(&mut self, handle: ListenerHandle) -> Response {
        // first find the event type
        let event = {
            match self.listeners.iter().find(|&ref l| l.has_handle(handle)) {
                Some(listener) => Some(listener.event.clone()),
                None => None,
            }
        };

        self.listeners.retain(|&ref l| !l.has_handle(handle));
        match event {
            // we can't unsubscribe commands
            Some(EventType::Command(_)) => Response::for_success(),

            // unsubscribe if there are no more listeners for the event
            Some(evt) => match self.listeners.iter().any(|&ref l| l.event == evt) {
                false => self.send(Request::Unsubscribe(evt)),
                true => Response::for_success(),
            },

            None => Response::for_fail("Could not find listener with given handle"),
        }
    }

    /// Remove all subscriptions for a specific event type.
    pub fn unsubscribe_all(&mut self, event: EventType) -> Response {
        self.listeners.retain(|&ref l| l.event != event);
        match event {
            EventType::Command(_) => Response::for_success(),
            _ => self.send(Request::Unsubscribe(event)),
        }
    }

    /// Check if there is any active listener for the given event type.
    pub fn has_any_subscription(&self, event: EventType) -> bool {
        self.listeners.iter().any(|&ref l| l.event == event)
    }

    /// Retrieve the networks the bot is connected to.
    pub fn networks(&self) -> Response {
        self.send(Request::Networks)
    }

    /// Retrieve the channels the bot is in for a given network.
    pub fn channels(&self, network: &str) -> Response {
        self.send(Request::Channels(network.to_string()))
    }

    /// Send a message to a specific channel using the PRIVMSG method.
    pub fn message(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Message(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP NOTICE to a specific channel.
    pub fn notice(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Notice(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP REQUEST to a specific channel.
    pub fn ctcp(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Ctcp(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP REPLY to a specific channel.
    pub fn ctcp_reply(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::CtcpReply(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP ACTION to a specific channel
    pub fn action(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Action(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a request for the list of nicks in a channel.
    ///
    /// Note that the response will not contain the names data, instead listen for a names event.
    /// The Response will only indicate whether or not the request has been submitted successfully.
    /// The server may respond with an `EventType::Names` event any time after this request has
    /// been submitted.
    pub fn send_names(&self, network: &str, channel: &str) -> Response {
        self.send(Request::Names(network.to_string(), channel.to_string()))
    }

    /// Send a request for a whois of a specific nick on some network.
    ///
    /// Note that the response will not contain the whois data, instead listen for a whois event.
    /// The Response will only indicate whether or not the request has been submitted successfully.
    /// The server may respond with an `EventType::Whois` event any time after this request has
    /// been submitted.
    pub fn send_whois(&self, network: &str, nick: &str) -> Response {
        self.send(Request::Whois(network.to_string(), nick.to_string()))
    }

    /// Try to join a channel on some network.
    pub fn join(&self, network: &str, channel: &str) -> Response {
        self.send(Request::Join(network.to_string(), channel.to_string()))
    }

    /// Try to leave a channel on some network.
    pub fn part(&self, network: &str, channel: &str) -> Response {
        self.send(Request::Part(network.to_string(), channel.to_string()))
    }

    /// Retrieve the nickname of the bot on the given network.
    pub fn nick(&self, network: &str) -> Response {
        self.send(Request::Nick(network.to_string()))
    }

    /// Send a handshake to the DaZeus core.
    pub fn handshake(&self, name: &str, version: &str, config: Option<&str>) -> Response {
        let n = name.to_string();
        let v = version.to_string();
        let req = match config {
            Some(config_name) => Request::Handshake(n, v, Some(config_name.to_string())),
            None => Request::Handshake(n, v, None),
        };
        self.send(req)
    }

    /// Retrieve a config value from the DaZeus config.
    pub fn get_config(&self, name: &str, group: ConfigGroup) -> Response {
        self.send(Request::Config(name.to_string(), group))
    }

    /// Retrieve the character that is used by the bot for highlighting.
    pub fn get_highlight_char(&self) -> Response {
        self.get_config("highlight", ConfigGroup::Core)
    }

    /// Retrieve a property stored in the bot database.
    pub fn get_property(&self, name: &str, scope: Scope) -> Response {
        self.send(Request::GetProperty(name.to_string(), scope))
    }

    /// Set a property to be stored in the bot database.
    pub fn set_property(&self, name: &str, value: &str, scope: Scope) -> Response {
        self.send(Request::SetProperty(name.to_string(), value.to_string(), scope))
    }

    /// Remove a property stored in the bot database.
    pub fn unset_property(&self, name: &str, scope: Scope) -> Response {
        self.send(Request::UnsetProperty(name.to_string(), scope))
    }

    /// Retrieve a list of keys starting with the common prefix with the given scope.
    pub fn get_property_keys(&self, prefix: &str, scope: Scope) -> Response {
        self.send(Request::PropertyKeys(prefix.to_string(), scope))
    }

    /// Set a permission to either allow or deny for a specific scope.
    pub fn set_permission(&self, permission: &str, allow: bool, scope: Scope) -> Response {
        self.send(Request::SetPermission(permission.to_string(), allow, scope))
    }

    /// Retrieve whether for some scope the given permission was set.
    ///
    /// Will return the default if it was not.
    pub fn has_permission(&self, permission: &str, default: bool, scope: Scope) -> Response {
        self.send(Request::HasPermission(permission.to_string(), default, scope))
    }

    /// Remove a set permission from the bot.
    pub fn unset_permission(&self, permission: &str, scope: Scope) -> Response {
        self.send(Request::UnsetPermission(permission.to_string(), scope))
    }

    /// Send a whois request and wait for an event that answers this request (blocking).
    ///
    /// Note that the IRC server may not respond to the whois request (if it has been configured
    /// this way), in which case this request will block forever.
    pub fn whois(&mut self, network: &str, nick: &str) -> Event {
        if !self.has_any_subscription(EventType::Whois) {
            self.send(Request::Subscribe(EventType::Whois));
        }
        self.send_whois(network, nick);

        loop {
            let evt = self.next_event();
            match evt.event {
                EventType::Whois if &evt[0] == network && &evt[2] == nick => {
                    if !self.has_any_subscription(EventType::Whois) {
                        self.send(Request::Unsubscribe(EventType::Whois));
                    }
                    return evt;
                },
                _ => (),
            }
        }
    }

    /// Send a names request and wait for an event that answers this request (blocking).
    ///
    /// Note that the IRC server may not respond to the names request (if it has been configured
    /// this way), in which case this request will block forever.
    pub fn names(&mut self, network: &str, channel: &str) -> Event {
        if !self.has_any_subscription(EventType::Names) {
            self.send(Request::Subscribe(EventType::Names));
        }
        self.send_names(network, channel);

        loop {
            let evt = self.next_event();
            match evt.event {
                EventType::Names if &evt[0] == network && &evt[2] == channel => {
                    if !self.has_any_subscription(EventType::Names) {
                        self.send(Request::Unsubscribe(EventType::Names));
                    }
                    return evt;
                },
                _ => (),
            }
        }
    }

    /// Send a reply in response to some event.
    ///
    /// Note that not all types of events can be responded to. Mostly message type events
    /// concerning some IRC user can be responded to. Join events can also be responded to.
    pub fn reply(&self, event: &Event, message: &str, highlight: bool) -> Response {
        if let Some((network, channel, user)) = targets_for_event(event) {
            let resp = self.nick(network);
            let nick = resp.get_str_or("nick", "");
            if channel == nick {
                self.message(network, user, message)
            } else {
                if highlight {
                    let msg = format!("{}: {}", user, message);
                    self.message(network, channel, &msg[..])
                } else {
                    self.message(network, channel, message)
                }
            }
        } else {
            Response::for_fail("Not an event to reply to")
        }
    }

    /// Send a reply (as a notice) in response to some event.
    ///
    /// Note that not all types of events can be responded to. Mostly message type events
    /// concerning some IRC user can be responded to. Join events can also be responded to.
    pub fn reply_with_notice(&self, event: &Event, message: &str) -> Response {
        if let Some((network, channel, user)) = targets_for_event(event) {
            let resp = self.nick(network);
            let nick = resp.get_str_or("nick", "");
            if channel == nick {
                self.notice(network, user, message)
            } else {
                self.notice(network, channel, message)
            }
        } else {
            Response::for_fail("Not an event to reply to")
        }
    }

    /// Send a reply (as a ctcp action) in response to some event.
    ///
    /// Note that not all types of events can be responded to. Mostly message type events
    /// concerning some IRC user can be responded to. Join events can also be responded to.
    pub fn reply_with_action(&self, event: &Event, message: &str) -> Response {
        if let Some((network, channel, user)) = targets_for_event(event) {
            let resp = self.nick(network);
            let nick = resp.get_str_or("nick", "");
            if channel == nick {
                self.action(network, user, message)
            } else {
                self.action(network, channel, message)
            }
        } else {
            Response::for_fail("Not an event to reply to")
        }
    }
}

fn targets_for_event(event: &Event) -> Option<(&str, &str, &str)> {
    let params = &event.params;
    match event.event {
        EventType::Join
        | EventType::PrivMsg
        | EventType::Notice
        | EventType::Ctcp
        | EventType::Action => Some((&params[0][..], &params[2][..], &params[1][..])),
        _ => None,
    }
}
<commit_msg>Fixed bug where nothing could be done inside event handlers<commit_after>use std::io::{Read, Write};
use super::event::{Event, EventType};
use super::handler::{Handler, Message};
use super::listener::{ListenerHandle, Listener};
use super::request::{ConfigGroup, Request};
use super::response::Response;
use super::scope::Scope;
use super::error::{ReceiveError, Error};
use std::cell::RefCell;

/// The base DaZeus struct.
///
/// See the [crate documentation](./index.html) for a more detailed instruction on how to get
/// started with these DaZeus bindings.
pub struct DaZeus<'a, T> where T: Read + Write {
    handler: RefCell<Handler<T>>,
    listeners: Vec<Listener<'a, T>>,
    current_handle: u64,
}

impl<'a, T> DaZeus<'a, T> where T: Read + Write {
    /// Create a new instance of DaZeus from the given connection.
    pub fn new(conn: T) -> DaZeus<'a, T> {
        DaZeus {
            handler: RefCell::new(Handler::new(conn)),
            listeners: Vec::new(),
            current_handle: 1
        }
    }

    fn next_response(&self) -> Result<Response, Error> {
        loop {
            let msg = self.handler.borrow_mut().read();
            match try!(msg) {
                Message::Event(e) => self.handle_event(e),
                Message::Response(r) => return Ok(r),
            }
        }
    }

    fn try_next_event(&self) -> Result<Event, Error> {
        let msg = self.handler.borrow_mut().read();
        match try!(msg) {
            Message::Event(e) => {
                self.handle_event(e.clone());
                Ok(e)
            },
            Message::Response(_) => Err(Error::ReceiveError(ReceiveError::new())),
        }
    }

    fn next_event(&self) -> Event {
        match self.try_next_event() {
            Ok(evt) => evt,
            Err(e) => panic!("{}", e),
        }
    }

    /// Send a request to DaZeus and retrieve a Future in which the response will be contained.
    pub fn send(&self, request: Request) -> Response {
        match self.try_send(request) {
            Ok(response) => response,
            Err(e) => panic!("{}", e),
        }
    }

    /// Try to send a request to DaZeus
    pub fn try_send(&self, request: Request) -> Result<Response, Error> {
        try!(self.handler.borrow_mut().write(request));
        self.next_response()
    }

    /// Handle an event received by calling all event listeners listening for that event type.
    fn handle_event(&self, event: Event) {
        for listener in self.listeners.iter() {
            if listener.event == event.event {
                listener.call(event.clone(), self);
            }
        }
    }

    /// Loop wait for messages to receive in a blocking way.
    pub fn listen(&self) -> Result<(), Error> {
        loop {
            try!(self.try_next_event());
        }
    }

    /// Subscribe to an event type and call the callback function every time such an event occurs.
    pub fn subscribe<F>(&mut self, event: EventType, callback: F) -> (ListenerHandle, Response)
        where F: FnMut(Event, &DaZeus<T>) + 'a
    {
        let request = match event {
            EventType::Command(ref cmd) => Request::SubscribeCommand(cmd.clone(), None),
            _ => Request::Subscribe(event.clone()),
        };

        let handle = self.current_handle;
        self.current_handle += 1;
        let listener = Listener::new(handle, event, callback);

        self.listeners.push(listener);
        (handle, self.send(request))
    }

    /// Subscribe to a command and call the callback function every time such a command occurs.
    pub fn subscribe_command<F>(&mut self, command: &str, callback: F) -> (ListenerHandle, Response)
        where F: FnMut(Event, &DaZeus<T>) + 'a
    {
        self.subscribe(EventType::Command(command.to_string()), callback)
    }

    /// Unsubscribe a listener for some event.
    pub fn unsubscribe(&mut self, handle: ListenerHandle) -> Response {
        // first find the event type
        let event = {
            match self.listeners.iter().find(|&ref l| l.has_handle(handle)) {
                Some(listener) => Some(listener.event.clone()),
                None => None,
            }
        };

        self.listeners.retain(|&ref l| !l.has_handle(handle));
        match event {
            // we can't unsubscribe commands
            Some(EventType::Command(_)) => Response::for_success(),

            // unsubscribe if there are no more listeners for the event
            Some(evt) => match self.listeners.iter().any(|&ref l| l.event == evt) {
                false => self.send(Request::Unsubscribe(evt)),
                true => Response::for_success(),
            },

            None => Response::for_fail("Could not find listener with given handle"),
        }
    }

    /// Remove all subscriptions for a specific event type.
    pub fn unsubscribe_all(&mut self, event: EventType) -> Response {
        self.listeners.retain(|&ref l| l.event != event);
        match event {
            EventType::Command(_) => Response::for_success(),
            _ => self.send(Request::Unsubscribe(event)),
        }
    }

    /// Check if there is any active listener for the given event type.
    pub fn has_any_subscription(&self, event: EventType) -> bool {
        self.listeners.iter().any(|&ref l| l.event == event)
    }

    /// Retrieve the networks the bot is connected to.
    pub fn networks(&self) -> Response {
        self.send(Request::Networks)
    }

    /// Retrieve the channels the bot is in for a given network.
    pub fn channels(&self, network: &str) -> Response {
        self.send(Request::Channels(network.to_string()))
    }

    /// Send a message to a specific channel using the PRIVMSG method.
    pub fn message(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Message(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP NOTICE to a specific channel.
    pub fn notice(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Notice(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP REQUEST to a specific channel.
    pub fn ctcp(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Ctcp(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP REPLY to a specific channel.
    pub fn ctcp_reply(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::CtcpReply(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a CTCP ACTION to a specific channel
    pub fn action(&self, network: &str, channel: &str, message: &str) -> Response {
        self.send(Request::Action(
            network.to_string(),
            channel.to_string(),
            message.to_string()
        ))
    }

    /// Send a request for the list of nicks in a channel.
    ///
    /// Note that the response will not contain the names data, instead listen for a names event.
    /// The Response will only indicate whether or not the request has been submitted successfully.
    /// The server may respond with an `EventType::Names` event any time after this request has
    /// been submitted.
    pub fn send_names(&self, network: &str, channel: &str) -> Response {
        self.send(Request::Names(network.to_string(), channel.to_string()))
    }

    /// Send a request for a whois of a specific nick on some network.
    ///
    /// Note that the response will not contain the whois data, instead listen for a whois event.
    /// The Response will only indicate whether or not the request has been submitted successfully.
    /// The server may respond with an `EventType::Whois` event any time after this request has
    /// been submitted.
    pub fn send_whois(&self, network: &str, nick: &str) -> Response {
        self.send(Request::Whois(network.to_string(), nick.to_string()))
    }

    /// Try to join a channel on some network.
    pub fn join(&self, network: &str, channel: &str) -> Response {
        self.send(Request::Join(network.to_string(), channel.to_string()))
    }

    /// Try to leave a channel on some network.
    pub fn part(&self, network: &str, channel: &str) -> Response {
        self.send(Request::Part(network.to_string(), channel.to_string()))
    }

    /// Retrieve the nickname of the bot on the given network.
    pub fn nick(&self, network: &str) -> Response {
        self.send(Request::Nick(network.to_string()))
    }

    /// Send a handshake to the DaZeus core.
    pub fn handshake(&self, name: &str, version: &str, config: Option<&str>) -> Response {
        let n = name.to_string();
        let v = version.to_string();
        let req = match config {
            Some(config_name) => Request::Handshake(n, v, Some(config_name.to_string())),
            None => Request::Handshake(n, v, None),
        };
        self.send(req)
    }

    /// Retrieve a config value from the DaZeus config.
    pub fn get_config(&self, name: &str, group: ConfigGroup) -> Response {
        self.send(Request::Config(name.to_string(), group))
    }

    /// Retrieve the character that is used by the bot for highlighting.
    pub fn get_highlight_char(&self) -> Response {
        self.get_config("highlight", ConfigGroup::Core)
    }

    /// Retrieve a property stored in the bot database.
    pub fn get_property(&self, name: &str, scope: Scope) -> Response {
        self.send(Request::GetProperty(name.to_string(), scope))
    }

    /// Set a property to be stored in the bot database.
    pub fn set_property(&self, name: &str, value: &str, scope: Scope) -> Response {
        self.send(Request::SetProperty(name.to_string(), value.to_string(), scope))
    }

    /// Remove a property stored in the bot database.
    pub fn unset_property(&self, name: &str, scope: Scope) -> Response {
        self.send(Request::UnsetProperty(name.to_string(), scope))
    }

    /// Retrieve a list of keys starting with the common prefix with the given scope.
    pub fn get_property_keys(&self, prefix: &str, scope: Scope) -> Response {
        self.send(Request::PropertyKeys(prefix.to_string(), scope))
    }

    /// Set a permission to either allow or deny for a specific scope.
    pub fn set_permission(&self, permission: &str, allow: bool, scope: Scope) -> Response {
        self.send(Request::SetPermission(permission.to_string(), allow, scope))
    }

    /// Retrieve whether for some scope the given permission was set.
    ///
    /// Will return the default if it was not.
    pub fn has_permission(&self, permission: &str, default: bool, scope: Scope) -> Response {
        self.send(Request::HasPermission(permission.to_string(), default, scope))
    }

    /// Remove a set permission from the bot.
    pub fn unset_permission(&self, permission: &str, scope: Scope) -> Response {
        self.send(Request::UnsetPermission(permission.to_string(), scope))
    }

    /// Send a whois request and wait for an event that answers this request (blocking).
    ///
    /// Note that the IRC server may not respond to the whois request (if it has been configured
    /// this way), in which case this request will block forever.
    pub fn whois(&mut self, network: &str, nick: &str) -> Event {
        if !self.has_any_subscription(EventType::Whois) {
            self.send(Request::Subscribe(EventType::Whois));
        }
        self.send_whois(network, nick);

        loop {
            let evt = self.next_event();
            match evt.event {
                EventType::Whois if &evt[0] == network && &evt[2] == nick => {
                    if !self.has_any_subscription(EventType::Whois) {
                        self.send(Request::Unsubscribe(EventType::Whois));
                    }
                    return evt;
                },
                _ => (),
            }
        }
    }

    /// Send a names request and wait for an event that answers this request (blocking).
    ///
    /// Note that the IRC server may not respond to the names request (if it has been configured
    /// this way), in which case this request will block forever.
    pub fn names(&mut self, network: &str, channel: &str) -> Event {
        if !self.has_any_subscription(EventType::Names) {
            self.send(Request::Subscribe(EventType::Names));
        }
        self.send_names(network, channel);

        loop {
            let evt = self.next_event();
            match evt.event {
                EventType::Names if &evt[0] == network && &evt[2] == channel => {
                    if !self.has_any_subscription(EventType::Names) {
                        self.send(Request::Unsubscribe(EventType::Names));
                    }
                    return evt;
                },
                _ => (),
            }
        }
    }

    /// Send a reply in response to some event.
    ///
    /// Note that not all types of events can be responded to. Mostly message type events
    /// concerning some IRC user can be responded to. Join events can also be responded to.
    pub fn reply(&self, event: &Event, message: &str, highlight: bool) -> Response {
        if let Some((network, channel, user)) = targets_for_event(event) {
            let resp = self.nick(network);
            let nick = resp.get_str_or("nick", "");
            if channel == nick {
                self.message(network, user, message)
            } else {
                if highlight {
                    let msg = format!("{}: {}", user, message);
                    self.message(network, channel, &msg[..])
                } else {
                    self.message(network, channel, message)
                }
            }
        } else {
            Response::for_fail("Not an event to reply to")
        }
    }

    /// Send a reply (as a notice) in response to some event.
    ///
    /// Note that not all types of events can be responded to. Mostly message type events
    /// concerning some IRC user can be responded to. Join events can also be responded to.
    pub fn reply_with_notice(&self, event: &Event, message: &str) -> Response {
        if let Some((network, channel, user)) = targets_for_event(event) {
            let resp = self.nick(network);
            let nick = resp.get_str_or("nick", "");
            if channel == nick {
                self.notice(network, user, message)
            } else {
                self.notice(network, channel, message)
            }
        } else {
            Response::for_fail("Not an event to reply to")
        }
    }

    /// Send a reply (as a ctcp action) in response to some event.
    ///
    /// Note that not all types of events can be responded to. Mostly message type events
    /// concerning some IRC user can be responded to. Join events can also be responded to.
    pub fn reply_with_action(&self, event: &Event, message: &str) -> Response {
        if let Some((network, channel, user)) = targets_for_event(event) {
            let resp = self.nick(network);
            let nick = resp.get_str_or("nick", "");
            if channel == nick {
                self.action(network, user, message)
            } else {
                self.action(network, channel, message)
            }
        } else {
            Response::for_fail("Not an event to reply to")
        }
    }
}

fn targets_for_event(event: &Event) -> Option<(&str, &str, &str)> {
    let params = &event.params;
    match event.event {
        EventType::Join
        | EventType::PrivMsg
        | EventType::Notice
        | EventType::Ctcp
        | EventType::Action => Some((&params[0][..], &params[2][..], &params[1][..])),
        _ => None,
    }
}
<|endoftext|>