<commit_before>extern crate notify;
extern crate yaml_rust;
extern crate glob;

use std::process::Command as ShellCommand;
use std::sync::mpsc::channel;
use self::glob::Pattern;

use self::notify::{RecommendedWatcher, Watcher};
use self::yaml_rust::{Yaml, YamlLoader};

use cli::Command;

pub const FILENAME: &'static str = ".watch.yaml";

/// # `WatchCommand`
///
/// Starts watcher to listen the change events configured
/// in watch.yaml
///
pub struct WatchCommand {
    watches: Watches,
}

impl WatchCommand {
    pub fn new(watches: Watches) -> Self {
        WatchCommand {
            watches: watches
        }
    }
}

impl Command for WatchCommand {

    fn execute(&self) -> Result<(), &str>{

        let (tx, rx) = channel();
        let mut watcher: RecommendedWatcher = match Watcher::new(tx) {
            Ok(w) => w,
            Err(err) => panic!("Error while trying watch. Cause: {:?}",err)
        };

        match watcher.watch(".") {
            Ok(()) => {},
            Err(_) => panic!("Unable to watch current directory"),
        }

        println!("Watching.");
        while let Ok(event) = rx.recv() {
            let path: &str = if let Some(ref path_buf) = event.path {
                path_buf.to_str().unwrap()
            } else {
                ""
            };

            if let Some(mut cmd) = self.watches.watch(&path) {
                match cmd.status() {
                    Ok(_) => println!("executed"),
                    Err(err) => println!("Error {:?}", err),
                }
            }
        };
        Ok(())
    }
}

/// # Watches
///
/// Represent all items in the yaml config loaded.
///
pub struct Watches {
    items: Vec<Yaml>,
}
impl Watches {
    pub fn from_args(args: Vec<String>) -> Self {
        let template =
        format!("
        - name: from command
          when:
            change: '{path}'
            run: {command}
        ", path="**", command=args[0]);

        Watches {
            items: YamlLoader::load_from_str(&template).unwrap(),
        }
    }

    pub fn from(plain_text: &str) -> Self {
        Watches {
            items: YamlLoader::load_from_str(&plain_text).unwrap(),
        }
    }

    /// Returns the first watch found for the given path
    /// it may return None if there is no item that match.
    ///
    pub fn watch(&self, path: &str) -> Option<ShellCommand>{
        match self.items[0] {
            Yaml::Array(ref items) => {
                for i in items.iter()
                              .filter(|i| !ignores(i["when"]["ignore"].clone(), path)){
                    let change = i["when"]["change"].as_str().unwrap();
                    let command = i["when"]["run"].as_str().unwrap();

                    if pattern_for(change).matches(path) {
                        println!("Running: {}", i["name"].as_str().unwrap());
                        let mut args: Vec<&str>= command.split(' ').collect();
                        let cmd = args.remove(0);

                        let mut shell = ShellCommand::new(cmd);
                        shell.args(&args);

                        return Some(shell)
                    }
                };
            },
            _ => panic!("Yaml format unkown.")
        };
        None
    }
}

fn ignores(item: Yaml, path: &str) -> bool {
    match item {
        Yaml::Array(ref ignoreds) => {
            ignoreds.iter()
                    .any(|i| pattern_for(i.as_str().unwrap()).matches(path))
        },
        Yaml::String(ref ignored) => { pattern_for(ignored).matches(path) },
        _ => false
    }
}

fn pattern_for(pattern: &str) -> Pattern {
    Pattern::new(&format!("**/{}", pattern)).unwrap()
}

#[test]
fn it_loads_from_yaml_file() {
    let file_content = "
- name: my tests
  when:
    change: tests/*
    run: cargo tests
";
    let content = YamlLoader::load_from_str(&file_content).unwrap();
    let watches = Watches::from(file_content);
    assert_eq!(content[0], watches.items[0]);
    assert_eq!(content[0]["when"], watches.items[0]["when"]);
    assert_eq!(content[0]["when"]["change"],
               watches.items[0]["when"]["change"])
}

#[test]
fn it_loads_from_args() {
    let args = vec![String::from("cargo build")];
    let watches = Watches::from_args(args);

    println!("{:?}", watches.items[0]);
    assert!(watches.watch("src/main.rs").is_some());
    assert!(watches.watch("test/main.rs").is_some());
    assert!(watches.watch(".").is_some());

    let result = watches.watch(".").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("build");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result));
}

#[test]
fn it_watches_test_path() {
    let file_content = "
- name: my tests
  when:
    change: 'tests/**'
    run: 'cargo tests'
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("/Users/crosa/others/funzzy/tests/test.rs").is_some());
    assert!(watches.watch("tests/tests.rs").is_some());
    assert!(watches.watch("tests/ruby.rb").is_some());
    assert!(watches.watch("tests/folder/other.rs").is_some())
}

#[test]
fn it_doesnot_watches_test_path() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);

    assert!(watches.watch("/Users/crosa/others/funzzy/events.yaml").is_none());
    assert!(watches.watch("tests/").is_none());
    assert!(watches.watch("tests/test.rs").is_none());
    assert!(watches.watch("tests/folder/other.rs").is_none());
}

#[test]
fn it_creates_shell_command() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);
    let result = watches.watch("src/test.rs").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("build");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result))
}

#[test]
fn it_works_with_multiples_itens() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'

- name: other
  when:
    change: 'test/**'
    run: 'cargo test'
";
    let watches = Watches::from(file_content);

    let result = watches.watch("test/test.rs").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("test");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result));

    let result_src = watches.watch("src/test.rs").unwrap();
    let mut expected_src = ShellCommand::new("cargo");
    expected_src.arg("build");
    assert_eq!(format!("{:?}", expected_src),  format!("{:?}", result_src))
}

#[test]
fn it_ignores_pattern() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
    ignore: 'src/test/**'
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("src/other.rb").is_some());
    assert!(watches.watch("src/test.txt").is_some());
    assert!(watches.watch("src/test/other.tmp").is_none())
}

#[test]
fn it_ignores_a_list_of_patterns() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
    ignore: ['src/test/**', 'src/tmp/**']
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("src/other.rb").is_some());
    assert!(watches.watch("src/test.txt").is_some());
    assert!(watches.watch("src/tmp/test.txt").is_none());
    assert!(watches.watch("src/test/other.tmp").is_none())
}
<commit_msg>refact: recursion search<commit_after>extern crate notify;
extern crate yaml_rust;
extern crate glob;

use std::process::Command as ShellCommand;
use std::sync::mpsc::channel;
use self::glob::Pattern;

use self::notify::{RecommendedWatcher, Watcher};
use self::yaml_rust::{Yaml, YamlLoader};

use cli::Command;

pub const FILENAME: &'static str = ".watch.yaml";

/// # `WatchCommand`
///
/// Starts watcher to listen the change events configured
/// in watch.yaml
///
pub struct WatchCommand {
    watches: Watches,
}

impl WatchCommand {
    pub fn new(watches: Watches) -> Self {
        WatchCommand {
            watches: watches
        }
    }
}

impl Command for WatchCommand {

    fn execute(&self) -> Result<(), &str>{

        let (tx, rx) = channel();
        let mut watcher: RecommendedWatcher = match Watcher::new(tx) {
            Ok(w) => w,
            Err(err) => panic!("Error while trying watch. Cause: {:?}",err)
        };

        match watcher.watch(".") {
            Ok(()) => {},
            Err(_) => panic!("Unable to watch current directory"),
        }

        println!("Watching.");
        while let Ok(event) = rx.recv() {
            let path: &str = if let Some(ref path_buf) = event.path {
                path_buf.to_str().unwrap()
            } else {
                ""
            };

            if let Some(mut cmd) = self.watches.watch(&path) {
                match cmd.status() {
                    Ok(_) => println!("executed"),
                    Err(err) => println!("Error {:?}", err),
                }
            }
        };
        Ok(())
    }
}

/// # Watches
///
/// Represent all items in the yaml config loaded.
///
pub struct Watches {
    items: Vec<Yaml>,
}
impl Watches {
    pub fn from_args(args: Vec<String>) -> Self {
        let template =
        format!("
        - name: from command
          when:
            change: '{path}'
            run: {command}
        ", path="**", command=args[0]);

        Watches {
            items: YamlLoader::load_from_str(&template).unwrap(),
        }
    }

    pub fn from(plain_text: &str) -> Self {
        Watches {
            items: YamlLoader::load_from_str(&plain_text).unwrap(),
        }
    }

    /// Returns the first watch found for the given path
    /// it may return None if there is no item that match.
    ///
    pub fn watch(&self, path: &str) -> Option<ShellCommand>{
        match self.items[0] {
            Yaml::Array(ref items) => {
                for i in items.iter()
                              .filter(|i| !ignores(i["when"]["ignore"].clone(), path)){
                    let change = i["when"]["change"].as_str().unwrap();
                    let command = i["when"]["run"].as_str().unwrap();

                    if pattern_for(change).matches(path) {
                        println!("Running: {}", i["name"].as_str().unwrap());
                        let mut args: Vec<&str>= command.split(' ').collect();
                        let cmd = args.remove(0);

                        let mut shell = ShellCommand::new(cmd);
                        shell.args(&args);

                        return Some(shell)
                    }
                };
            },
            _ => panic!("Yaml format unkown.")
        };
        None
    }
}

fn ignores(item: Yaml, path: &str) -> bool {
    match item {
        Yaml::Array(ref ignoreds) => {
            ignoreds.iter().any(|i| ignores(i.clone(), path))
        },
        Yaml::String(ref ignore) => { pattern_for(ignore).matches(path) },
        _ => false
    }
}

fn pattern_for(pattern: &str) -> Pattern {
    Pattern::new(&format!("**/{}", pattern)).unwrap()
}

#[test]
fn it_loads_from_yaml_file() {
    let file_content = "
- name: my tests
  when:
    change: tests/*
    run: cargo tests
";
    let content = YamlLoader::load_from_str(&file_content).unwrap();
    let watches = Watches::from(file_content);
    assert_eq!(content[0], watches.items[0]);
    assert_eq!(content[0]["when"], watches.items[0]["when"]);
    assert_eq!(content[0]["when"]["change"],
               watches.items[0]["when"]["change"])
}

#[test]
fn it_loads_from_args() {
    let args = vec![String::from("cargo build")];
    let watches = Watches::from_args(args);

    println!("{:?}", watches.items[0]);
    assert!(watches.watch("src/main.rs").is_some());
    assert!(watches.watch("test/main.rs").is_some());
    assert!(watches.watch(".").is_some());

    let result = watches.watch(".").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("build");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result));
}

#[test]
fn it_watches_test_path() {
    let file_content = "
- name: my tests
  when:
    change: 'tests/**'
    run: 'cargo tests'
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("/Users/crosa/others/funzzy/tests/test.rs").is_some());
    assert!(watches.watch("tests/tests.rs").is_some());
    assert!(watches.watch("tests/ruby.rb").is_some());
    assert!(watches.watch("tests/folder/other.rs").is_some())
}

#[test]
fn it_doesnot_watches_test_path() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);

    assert!(watches.watch("/Users/crosa/others/funzzy/events.yaml").is_none());
    assert!(watches.watch("tests/").is_none());
    assert!(watches.watch("tests/test.rs").is_none());
    assert!(watches.watch("tests/folder/other.rs").is_none());
}

#[test]
fn it_creates_shell_command() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
";
    let watches = Watches::from(file_content);
    let result = watches.watch("src/test.rs").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("build");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result))
}

#[test]
fn it_works_with_multiples_itens() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'

- name: other
  when:
    change: 'test/**'
    run: 'cargo test'
";
    let watches = Watches::from(file_content);

    let result = watches.watch("test/test.rs").unwrap();
    let mut expected = ShellCommand::new("cargo");
    expected.arg("test");
    assert_eq!(format!("{:?}", expected),  format!("{:?}", result));

    let result_src = watches.watch("src/test.rs").unwrap();
    let mut expected_src = ShellCommand::new("cargo");
    expected_src.arg("build");
    assert_eq!(format!("{:?}", expected_src),  format!("{:?}", result_src))
}

#[test]
fn it_ignores_pattern() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
    ignore: 'src/test/**'
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("src/other.rb").is_some());
    assert!(watches.watch("src/test.txt").is_some());
    assert!(watches.watch("src/test/other.tmp").is_none())
}

#[test]
fn it_ignores_a_list_of_patterns() {
    let file_content = "
- name: my source
  when:
    change: 'src/**'
    run: 'cargo build'
    ignore: ['src/test/**', 'src/tmp/**']
";
    let watches = Watches::from(file_content);
    assert!(watches.watch("src/other.rb").is_some());
    assert!(watches.watch("src/test.txt").is_some());
    assert!(watches.watch("src/tmp/test.txt").is_none());
    assert!(watches.watch("src/test/other.tmp").is_none())
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program.as_str().unwrap_or("<not-utf8>")));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_string());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.unshift(path.display().to_string());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_string(), v.to_string());
            },
            None => {
                self.env.remove(&key.to_string());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        let program = self.program.as_str().unwrap_or("<not-utf8>");
        if self.args.len() == 0 {
            program.to_string()
        } else {
            format!("{} {}", program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_string(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: os::env().move_iter().collect()
    }
}
<commit_msg>auto merge of #166 : nielsle/cargo/command-env, r=alexcrichton<commit_after>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program.as_str().unwrap_or("<not-utf8>")));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_string());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.unshift(path.display().to_string());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_string(), v.to_string());
            },
            None => {
                self.env.remove(&key.to_string());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env_set_all(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env_set_all(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        let program = self.program.as_str().unwrap_or("<not-utf8>");
        if self.args.len() == 0 {
            program.to_string()
        } else {
            format!("{} {}", program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_string(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: os::env().move_iter().collect()
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {
                let patch = Program::attempt_forward_jump(
                    &self.instructions,
                    index,
                    goal,
                    self.current_depth,
                );
                println!("SEEKING BRANCH\n{:?}\n", patch);
                return self.update(patch).execute(vm);
            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            if vm.cells[vm.data_pointer] == 0 {
                                self.current_depth -= 1;
                                continue;
                            }

                            let patch = Program::backward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                            );
                            println!("BACKWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        Command::JumpForward => {
                            if vm.cells[vm.data_pointer] != 0 {
                                self.current_depth += 1;
                                continue;
                            }

                            let patch = Program::attempt_forward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                                self.current_depth,
                            );
                            println!("FORWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        command if start < self.instructions.len() => vm.apply(command),

                        _ => {}
                    }
                }
            }

            _ => {}
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index,
                    status: ProgramStatus::Normal,
                    current_depth,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(commands, Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}
<commit_msg>Add unit test for attempt_forward_jump<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where
    F: FnMut(&T) -> bool,
{
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) {
            return Some(start + offset);
        }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {
                let patch = Program::attempt_forward_jump(
                    &self.instructions,
                    index,
                    goal,
                    self.current_depth,
                );
                println!("SEEKING BRANCH\n{:?}\n", patch);
                return self.update(patch).execute(vm);
            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            if vm.cells[vm.data_pointer] == 0 {
                                self.current_depth -= 1;
                                continue;
                            }

                            let patch = Program::backward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                            );
                            println!("BACKWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        Command::JumpForward => {
                            if vm.cells[vm.data_pointer] != 0 {
                                self.current_depth += 1;
                                continue;
                            }

                            let patch = Program::attempt_forward_jump(
                                &self.instructions,
                                index,
                                self.current_depth,
                                self.current_depth,
                            );
                            println!("FORWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        }

                        command if start < self.instructions.len() => vm.apply(command),

                        _ => {}
                    }
                }
            }

            _ => {}
        }
    }

    fn update(&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {}
            }
            if goal_depth == current_depth {
                return ProgramPatch {
                    instruction_pointer: index,
                    status: ProgramStatus::Normal,
                    current_depth,
                };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(
        commands: &Vec<Command>,
        index: usize,
        goal_depth: u64,
        mut current_depth: u64,
    ) -> ProgramPatch {
        let index = find_by(commands, Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {}
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index,
                status: ProgramStatus::Normal,
                current_depth,
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            },
        };
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn attempt_forward_jump() {
        let commands = vec![Command::JumpForward, Command::JumpForward, Command::JumpBackward];
        let index = 0;
        let goal_depth = 0;
        let current_depth = 0;
        let actual = Program::attempt_forward_jump(&commands, index, goal_depth, current_depth);
        assert_eq!(actual, ProgramPatch {
            instruction_pointer: 3,
            current_depth: 1,
            status: ProgramStatus::Seeking(0),
        })
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Kahan_summation
extern crate num;
extern crate permutohedron;

use std::f32;
use num::Float;
use permutohedron::Heap;

fn find_max(lst: &[f32]) -> Option<f32> {
    if lst.is_empty() {
        return None;
    }
    let max = lst.iter().fold(f32::NEG_INFINITY, |a, &b| Float::max(a, b));
    Some(max)
}

fn with_bits(val: f32, digits: usize) -> f32 {
    let num = format!("{:.*}", digits, val);
    num.parse::<f32>().unwrap()
}

fn kahan_sum(lst: &[f32]) -> Option<f32> {
    let mut sum = 0.0f32;
    let mut c = 0.0f32;
    for i in lst {
        let y = *i - c;
        let t = sum + y;
        c = (t - sum) - y;
        sum = t;
    }
    Some(with_bits(sum, 1))
}

fn all_sums(vec: &mut [f32]) -> Vec<f32> {
    let mut res = Vec::new();
    let mut perms = Heap::new(vec);
    loop {
        let v = perms.next();
        match v {
            Some(_v) => {
                let mut sum = 0.0f32;
                for e in &_v {
                    sum += with_bits(*e, 1);
                }
                res.push(with_bits(sum, 1));
            }
            None => break,
        }
    }
    res
}

fn main() {
    let v = vec![10000.0f32, 3.14159, 2.71828];
    let sums = all_sums(&mut v.clone());
    let res = kahan_sum(&v).unwrap();
    let max = find_max(&sums[..]).unwrap();
    println!("max: {} res: {}", max, res);
}

#[test]
fn test_kahansum() {
    let v = vec![10000.0f32, 3.14159, 2.71828];
    let sums = all_sums(&mut v.clone());
    let res = kahan_sum(&v).unwrap();
    let max = find_max(&sums[..]).unwrap();
    assert!(max < res);
}

#[test]
fn test_withbits() {
    let v = 3.123345f32;
    let res = with_bits(v, 3);
    assert!(res == 3.123f32);
}
<commit_msg>rename used underscore binding<commit_after>// http://rosettacode.org/wiki/Kahan_summation
extern crate num;
extern crate permutohedron;

use std::f32;
use num::Float;
use permutohedron::Heap;

fn find_max(lst: &[f32]) -> Option<f32> {
    if lst.is_empty() {
        return None;
    }
    let max = lst.iter().fold(f32::NEG_INFINITY, |a, &b| Float::max(a, b));
    Some(max)
}

fn with_bits(val: f32, digits: usize) -> f32 {
    let num = format!("{:.*}", digits, val);
    num.parse::<f32>().unwrap()
}

fn kahan_sum(lst: &[f32]) -> Option<f32> {
    let mut sum = 0.0f32;
    let mut c = 0.0f32;
    for i in lst {
        let y = *i - c;
        let t = sum + y;
        c = (t - sum) - y;
        sum = t;
    }
    Some(with_bits(sum, 1))
}

fn all_sums(vec: &mut [f32]) -> Vec<f32> {
    let mut res = Vec::new();
    let mut perms = Heap::new(vec);
    loop {
        let v = perms.next();
        match v {
            Some(v) => {
                let mut sum = 0.0f32;
                for e in &v {
                    sum += with_bits(*e, 1);
                }
                res.push(with_bits(sum, 1));
            }
            None => break,
        }
    }
    res
}

fn main() {
    let v = vec![10000.0f32, 3.14159, 2.71828];
    let sums = all_sums(&mut v.clone());
    let res = kahan_sum(&v).unwrap();
    let max = find_max(&sums[..]).unwrap();
    println!("max: {} res: {}", max, res);
}

#[test]
fn test_kahansum() {
    let v = vec![10000.0f32, 3.14159, 2.71828];
    let sums = all_sums(&mut v.clone());
    let res = kahan_sum(&v).unwrap();
    let max = find_max(&sums[..]).unwrap();
    assert!(max < res);
}

#[test]
fn test_withbits() {
    let v = 3.123345f32;
    let res = with_bits(v, 3);
    assert!(res == 3.123f32);
}
<|endoftext|>


<commit_before>use sass::value_part::ValuePart;
use evaluator::Evaluator;

use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Op {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    LeftParen,
    RightParen,
    Comma,
}

impl FromStr for Op {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "+" => Ok(Op::Plus),
            "-" => Ok(Op::Minus),
            "*" => Ok(Op::Star),
            "/" => Ok(Op::Slash),
            "%" => Ok(Op::Percent),
            "(" => Ok(Op::LeftParen),
            ")" => Ok(Op::RightParen),
            "," => Ok(Op::Comma),
            _   => Err(()),
        }
    }
}

impl Op {
    pub fn apply<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        match (self, &second) {
            (&Op::Plus, &ValuePart::List(..)) => self.apply_list(first, second),
            (&Op::Slash, _) => self.apply_slash(first, second, paren_level),
            (_, _) => self.apply_math(first, second),
        }
    }

    fn apply_list<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        match (&first, second) {
            (&ValuePart::Number(f), ValuePart::List(mut l)) => {
                if l.iter().any(|item| *item == ValuePart::Operator(Op::Slash)) {
                    let mut ve = vec![ValuePart::Operator(Op::LeftParen)];
                    l.push(ValuePart::Operator(Op::RightParen));
                    ve.append(&mut l);
                    self.apply_math(first, Evaluator::new(ve).evaluate())
                } else {
                    let new_first_item_value = format!("{}{}", f, l.remove(0));
                    let v = ValuePart::String(new_first_item_value.into());
                    let mut ve = vec![v];
                    ve.append(&mut l);
                    ValuePart::List(ve)
                }
            },
            (_, _) => ValuePart::List(vec![]),
        }
    }

    fn apply_slash<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        if paren_level == 0 {
            match first {
                ValuePart::List(mut f) => {
                    let mut ve = vec![ValuePart::Operator(*self), second];
                    f.append(&mut ve);
                    ValuePart::List(f)
                },
                ValuePart::Computed(..) => {
                    self.apply_math(first, second)
                },
                _ => ValuePart::List(vec![first, ValuePart::Operator(*self), second]),
            }
        } else {
            self.apply_math(first, second)
        }
    }

    fn apply_math<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let (first_num, second_num) = match (first, second) {
            (ValuePart::Number(f), ValuePart::Number(s)) => (f, s),
            (ValuePart::Number(f), ValuePart::Computed(s)) => (f, s),
            (ValuePart::Computed(f), ValuePart::Number(s)) => (f, s),
            (ValuePart::Computed(f), ValuePart::Computed(s)) => (f, s),
            (f, s) => return ValuePart::String(format!("Invalid arguments {:?} {:?}", f, s).into()),
        };
        let result = match *self {
            Op::Plus => first_num + second_num,
            Op::Minus => first_num - second_num,
            Op::Star => first_num * second_num,
            Op::Slash => first_num / second_num,
            Op::Percent => first_num % second_num,
            _ => 0.0,
        };
        ValuePart::Computed(result)
    }

    pub fn same_or_greater_precedence(self, other: Op) -> bool {
        match (self, other) {
            (Op::Plus, Op::Star) |
            (Op::Minus, Op::Star) |
            (Op::Plus, Op::Slash) |
            (Op::Minus, Op::Slash) |
            (Op::LeftParen, _) => false,
            (_, _) => true,
        }
    }
}
<commit_msg>Handle adding a list to a list<commit_after>use sass::value_part::ValuePart;
use evaluator::Evaluator;

use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Op {
    Plus,
    Minus,
    Star,
    Slash,
    Percent,
    LeftParen,
    RightParen,
    Comma,
}

impl FromStr for Op {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "+" => Ok(Op::Plus),
            "-" => Ok(Op::Minus),
            "*" => Ok(Op::Star),
            "/" => Ok(Op::Slash),
            "%" => Ok(Op::Percent),
            "(" => Ok(Op::LeftParen),
            ")" => Ok(Op::RightParen),
            "," => Ok(Op::Comma),
            _   => Err(()),
        }
    }
}

impl Op {
    pub fn apply<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        match (self, &second) {
            (&Op::Plus, &ValuePart::List(..)) => self.apply_list(first, second),
            (&Op::Slash, _) => self.apply_slash(first, second, paren_level),
            (_, _) => self.apply_math(first, second),
        }
    }

    fn apply_list<'a>(&self, mut first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let mut l = match second {
            ValuePart::List(contents) => contents,
            _ => unreachable!(), // only calling this on lists i swear
        };
        match first {
            ValuePart::Number(f) => {
                if l.iter().any(|item| *item == ValuePart::Operator(Op::Slash)) {
                    let mut ve = vec![ValuePart::Operator(Op::LeftParen)];
                    l.push(ValuePart::Operator(Op::RightParen));
                    ve.append(&mut l);
                    self.apply_math(ValuePart::Number(f), Evaluator::new(ve).evaluate())
                } else {
                    let new_first_item_value = format!("{}{}", f, l.remove(0));
                    let v = ValuePart::String(new_first_item_value.into());
                    let mut ve = vec![v];
                    ve.append(&mut l);
                    ValuePart::List(ve)
                }
            },
            ValuePart::List(ref mut f) => {
                f.extend(l);
                ValuePart::List(f.clone())
            },
            _ => ValuePart::List(vec![]),
        }
    }

    fn apply_slash<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>, paren_level: i32) -> ValuePart<'a> {
        if paren_level == 0 {
            match first {
                ValuePart::List(mut f) => {
                    let mut ve = vec![ValuePart::Operator(*self), second];
                    f.append(&mut ve);
                    ValuePart::List(f)
                },
                ValuePart::Computed(..) => {
                    self.apply_math(first, second)
                },
                _ => ValuePart::List(vec![first, ValuePart::Operator(*self), second]),
            }
        } else {
            self.apply_math(first, second)
        }
    }

    fn apply_math<'a>(&self, first: ValuePart<'a>, second: ValuePart<'a>) -> ValuePart<'a> {
        let (first_num, second_num) = match (first, second) {
            (ValuePart::Number(f), ValuePart::Number(s)) => (f, s),
            (ValuePart::Number(f), ValuePart::Computed(s)) => (f, s),
            (ValuePart::Computed(f), ValuePart::Number(s)) => (f, s),
            (ValuePart::Computed(f), ValuePart::Computed(s)) => (f, s),
            (f, s) => return ValuePart::String(format!("Invalid arguments {:?} {:?}", f, s).into()),
        };
        let result = match *self {
            Op::Plus => first_num + second_num,
            Op::Minus => first_num - second_num,
            Op::Star => first_num * second_num,
            Op::Slash => first_num / second_num,
            Op::Percent => first_num % second_num,
            _ => 0.0,
        };
        ValuePart::Computed(result)
    }

    pub fn same_or_greater_precedence(self, other: Op) -> bool {
        match (self, other) {
            (Op::Plus, Op::Star) |
            (Op::Minus, Op::Star) |
            (Op::Plus, Op::Slash) |
            (Op::Minus, Op::Slash) |
            (Op::LeftParen, _) => false,
            (_, _) => true,
        }
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write};

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    #[allow(dead_code)]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

/// A segment is a portion of the commit log. Segments are append-only logs written
/// until the maximum size is reached.
pub struct Segment {
    /// File descriptor
    file: File,
    /// Maximum number of bytes permitted to be appended to the log
    max_bytes: usize,
    /// current file position for the write
    pos: usize,

    /// Next offset of the log
    next_offset: u64,
    /// Base offset of the log
    base_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

/// Holds the pair of offset written to file position in the segment file.
#[derive(Copy, Clone, Debug)]
pub struct LogEntryMetadata {
    offset: u64,
    file_pos: u32,
}

impl LogEntryMetadata {
    #[inline]
    pub fn offset(&self) -> u64 {
        self.offset
    }

    #[inline]
    pub fn file_pos(&self) -> u32 {
        self.file_pos
    }
}

impl Segment {
    // TODO: open variant for reading

    pub fn new<P>(log_dir: P, base_offset: u64, max_bytes: usize) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log_path = {
            // the log is of the form BASE_OFFSET.log
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("log");
            path_buf
        };

        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(&log_path));

        Ok(Segment {
            file: f,
            max_bytes: max_bytes,
            pos: 0,

            next_offset: base_offset,
            base_offset: base_offset,
        })
    }

    #[inline]
    pub fn next_offset(&self) -> u64 {
        self.next_offset
    }

    #[inline]
    #[allow(dead_code)]
    pub fn starting_offset(&self) -> u64 {
        self.base_offset
    }

    pub fn append(&mut self, payload: &[u8]) -> Result<LogEntryMetadata, SegmentAppendError> {
        let off = self.next_offset;
        let msg = Message::new(payload, off);
        // ensure we have the capacity
        if msg.bytes().len() + self.pos > self.max_bytes {
            return Err(SegmentAppendError::LogFull);
        }

        try!(self.file.write_all(msg.bytes()));
        let write_pos = self.pos;

        self.pos += msg.bytes().len();
        self.next_offset += 1;

        Ok(LogEntryMetadata {
            offset: off,
            file_pos: write_pos as u32,
        })
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

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

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    pub fn log() {
        let path = TestDir::new();
        let mut f = Segment::new(path, 0, 1024).unwrap();

        let p0 = f.append(b"12345").unwrap();
        assert_eq!(p0.offset(), 0);
        assert_eq!(p0.file_pos(), 0);

        let p1 = f.append(b"66666").unwrap();
        assert_eq!(p1.offset(), 1);
        assert_eq!(p1.file_pos(), 21);

        f.flush_sync().unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let path = TestDir::new();

        let mut seg = Segment::new(path, 100u64, 100 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });
    }
}
<commit_msg>Adding message reconstruction<commit_after>use std::path::{Path, PathBuf};
use std::fs::{OpenOptions, File};
use crc::crc32::checksum_ieee;
use byteorder::{BigEndian, ByteOrder};
use std::io::{self, Write, Read};

#[derive(Debug)]
pub enum MessageError {
    IoError(io::Error),
    InvalidCRC
}

impl From<io::Error> for MessageError {
    fn from(e: io::Error) -> MessageError {
        MessageError::IoError(e)
    }
}

macro_rules! read_n {
    ($reader:expr, $buf:expr, $size:expr, $err_msg:expr) => ({

        match $reader.read(&mut $buf) {
            Ok(s) if s == $size => (),
            Ok(_) => return Err(MessageError::IoError(io::Error::new(io::ErrorKind::UnexpectedEof, $err_msg))),
            Err(e) => return Err(MessageError::IoError(e)),
        }
    })
}

/// Messages are appended to the log with the following encoding:
///
/// +-----------+--------------+
/// | Bytes     | Value        |
/// +-----------+--------------+
/// | 0-7       | Offset       |
/// | 8-11      | Payload Size |
/// | 12-15     | CRC32 (IEEE) |
/// | 16+       | Payload      |
/// +-----------+--------------+
#[derive(Debug)]
pub struct Message {
    bytes: Vec<u8>,
}

impl Message {
    pub fn new(payload: &[u8], offset: u64) -> Message {
        let mut bytes = vec![0; 16 + payload.len()];
        BigEndian::write_u64(&mut bytes[0..8], offset);
        BigEndian::write_u32(&mut bytes[8..12], payload.len() as u32);
        BigEndian::write_u32(&mut bytes[12..16], checksum_ieee(payload));
        bytes[16..].copy_from_slice(payload);
        Message { bytes: bytes }
    }

    pub fn read<R>(reader: &mut R) -> Result<Message, MessageError>
        where R: Read
    {
        let mut offset_buf = vec![0; 8];
        read_n!(reader, offset_buf, 8, "Unable to read offset");
        let mut size_buf = vec![0; 4];
        read_n!(reader, size_buf, 4, "Unable to read size");
        let mut crc_buf = vec![0; 4];
        read_n!(reader, crc_buf, 4, "Unable to read CRC");

        let size = BigEndian::read_u32(&size_buf) as usize;
        let crc = BigEndian::read_u32(&crc_buf);

        let mut bytes = vec![0; 16 + size];
        read_n!(reader, bytes[16..], size, "Unable to read message payload");

        let payload_crc = checksum_ieee(&bytes[16..]);
        if payload_crc != crc {
            return Err(MessageError::InvalidCRC);
        }

        bytes[0..8].copy_from_slice(&offset_buf);
        bytes[8..12].copy_from_slice(&size_buf);
        bytes[12..16].copy_from_slice(&crc_buf);

        Ok(Message { bytes: bytes })
    }

    #[inline]
    pub fn bytes(&self) -> &[u8] {
        &self.bytes
    }

    #[inline]
    #[allow(dead_code)]
    pub fn crc(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[12..16])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn size(&self) -> u32 {
        BigEndian::read_u32(&self.bytes[8..12])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn offset(&self) -> u64 {
        BigEndian::read_u64(&self.bytes[0..8])
    }

    #[inline]
    #[allow(dead_code)]
    pub fn payload(&self) -> &[u8] {
        &self.bytes[16..]
    }
}

/// A segment is a portion of the commit log. Segments are append-only logs written
/// until the maximum size is reached.
pub struct Segment {
    /// File descriptor
    file: File,
    /// Maximum number of bytes permitted to be appended to the log
    max_bytes: usize,
    /// current file position for the write
    pos: usize,

    /// Next offset of the log
    next_offset: u64,
    /// Base offset of the log
    base_offset: u64,
}

#[derive(Debug)]
pub enum SegmentAppendError {
    LogFull,
    IoError(io::Error),
}

impl From<io::Error> for SegmentAppendError {
    #[inline]
    fn from(e: io::Error) -> SegmentAppendError {
        SegmentAppendError::IoError(e)
    }
}

/// Holds the pair of offset written to file position in the segment file.
#[derive(Copy, Clone, Debug)]
pub struct LogEntryMetadata {
    offset: u64,
    file_pos: u32,
}

impl LogEntryMetadata {
    #[inline]
    pub fn offset(&self) -> u64 {
        self.offset
    }

    #[inline]
    pub fn file_pos(&self) -> u32 {
        self.file_pos
    }
}

impl Segment {
    // TODO: open variant for reading

    pub fn new<P>(log_dir: P, base_offset: u64, max_bytes: usize) -> io::Result<Segment>
        where P: AsRef<Path>
    {
        let log_path = {
            // the log is of the form BASE_OFFSET.log
            let mut path_buf = PathBuf::new();
            path_buf.push(&log_dir);
            path_buf.push(format!("{:020}", base_offset));
            path_buf.set_extension("log");
            path_buf
        };

        let f = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .create_new(true)
            .append(true)
            .open(&log_path));

        Ok(Segment {
            file: f,
            max_bytes: max_bytes,
            pos: 0,

            next_offset: base_offset,
            base_offset: base_offset,
        })
    }

    #[inline]
    pub fn next_offset(&self) -> u64 {
        self.next_offset
    }

    #[inline]
    #[allow(dead_code)]
    pub fn starting_offset(&self) -> u64 {
        self.base_offset
    }

    pub fn append(&mut self, payload: &[u8]) -> Result<LogEntryMetadata, SegmentAppendError> {
        let off = self.next_offset;
        let msg = Message::new(payload, off);
        // ensure we have the capacity
        if msg.bytes().len() + self.pos > self.max_bytes {
            return Err(SegmentAppendError::LogFull);
        }

        try!(self.file.write_all(msg.bytes()));
        let write_pos = self.pos;

        self.pos += msg.bytes().len();
        self.next_offset += 1;

        Ok(LogEntryMetadata {
            offset: off,
            file_pos: write_pos as u32,
        })
    }

    // TODO: async flush strategy
    pub fn flush_sync(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use super::super::testutil::*;
    use std::io;

    #[test]
    fn message_construction() {
        let msg = Message::new(b"123456789", 1234567u64);
        assert_eq!(msg.offset(), 1234567u64);
        assert_eq!(msg.payload(), b"123456789");
        assert_eq!(msg.crc(), 0xcbf43926);
        assert_eq!(msg.size(), 9u32);
    }

    #[test]
    fn message_read() {
        let msg = Message::new(b"123456789", 1234567u64);
        let mut buf_reader = io::BufReader::new(msg.bytes());
        let read_msg_result = Message::read(&mut buf_reader);
        assert!(read_msg_result.is_ok(), "result = {:?}", read_msg_result);

        let read_msg = read_msg_result.unwrap();
        assert_eq!(read_msg.offset(), 1234567u64);
        assert_eq!(read_msg.payload(), b"123456789");
        assert_eq!(read_msg.crc(), 0xcbf43926);
        assert_eq!(read_msg.size(), 9u32);
    }

    #[test]
    fn message_read_invalid_crc() {
        let mut msg = Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // mess with the payload such that the CRC does not match
        let last_ind = msg.len() - 1;
        msg[last_ind] += 1u8;

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::InvalidCRC) => true,
            _ => false,
        };
        assert!(matches_invalid_crc, "Invalid result, not CRC error. Result = {:?}", read_msg_result);
    }

    #[test]
    fn message_read_invalid_payload_length() {
        let mut msg = Message::new(b"123456789", 1234567u64).bytes().iter().cloned().collect::<Vec<u8>>();
        // pop the last byte
        msg.pop();

        let mut buf_reader = io::BufReader::new(msg.as_slice());
        let read_msg_result = Message::read(&mut buf_reader);
        let matches_invalid_crc = match read_msg_result {
            Err(MessageError::IoError(ref e)) if e.kind() == io::ErrorKind::UnexpectedEof => true,
            _ => false,
        };
        assert!(matches_invalid_crc, "Invalid result, not CRC error. Result = {:?}", read_msg_result);
    }

    #[test]
    pub fn log() {
        let path = TestDir::new();
        let mut f = Segment::new(path, 0, 1024).unwrap();

        let p0 = f.append(b"12345").unwrap();
        assert_eq!(p0.offset(), 0);
        assert_eq!(p0.file_pos(), 0);

        let p1 = f.append(b"66666").unwrap();
        assert_eq!(p1.offset(), 1);
        assert_eq!(p1.file_pos(), 21);

        f.flush_sync().unwrap();
    }

    #[bench]
    fn bench_segment_append(b: &mut Bencher) {
        let path = TestDir::new();

        let mut seg = Segment::new(path, 100u64, 100 * 1024 * 1024).unwrap();
        let buf = b"01234567891011121314151617181920";

        b.iter(|| {
            seg.append(buf).unwrap();
        });
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, lerp3, Vec3f};
use range::Rangef;
use std::ops::Add;

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Get vector from start to end (not normalized)
    pub fn to_vec3f(&self) -> Vec3f {
        self.end - self.start
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Treat the range's start and end as parametric coords. Use
    /// `point_from_parametric` to interpolate the range into a new
    /// segment. The output segment is not clamped.
    pub fn segment_from_parametric_range(&self, r: Rangef) -> Segment3f {
        Segment3f::new(&self.point_from_parametric(r.min),
                       &self.point_from_parametric(r.max))
    }

    /// Project another segment onto `self`. The result is a
    /// parametric range of `self` clamped to [0, 1].
    pub fn project_segment_as_range(&self, other: &Segment3f) -> Rangef {
        Rangef::from_sorting(self.closest_point_to_point(&other.start).0,
                             self.closest_point_to_point(&other.end).0)
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

impl Add<Vec3f> for Segment3f {
    type Output = Segment3f;
    fn add(self, v: Vec3f) -> Self::Output {
        Segment3f::new(&(self.start + v), &(self.end + v))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use range::Rangef;
    use vector::vec3f;

    fn make_seg(a: i32, b: i32) -> Segment3f {
        Segment3f::new(&vec3f(a, 0, 0), &vec3f(b, 0, 0))
    }

    #[test]
    fn test_to_vec3f() {
        assert_eq!(Segment3f::new(&vec3f(0, 0, 0),
                                  &vec3f(2, 3, 4)).to_vec3f(),
                   vec3f(2, 3, 4));

    }

    #[test]
    fn test_segment_length() {
        let s = Segment3f::new(&vec3f(0, 0, 0),
                               &vec3f(0, 0, 9));
        assert_eq!(s.length(), 9.0);
    }

    #[test]
    fn test_segment_distance_conversion() {
        let s = Segment3f::new(&vec3f(0, 1, 0),
                               &vec3f(0, 7, 0));

        let inputs = [
            (0.0f32, 0.0f32),
            (6.0, 1.0),
            (12.0, 2.0),
            (-3.0, -0.5)];

        for &(distance, delta) in inputs.iter() {
            assert_eq!(s.distance_to_parametric_delta(distance), delta);
            assert_eq!(s.distance_from_parametric_delta(delta), distance);
        }
    }

    #[test]
    fn test_point_from_parametric() {
        let s = Segment3f::new(&vec3f(0, 0, -1),
                               &vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
        assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
    }

    #[test]
    fn test_segment_from_parametric_range() {
        let s = make_seg(0, 4);
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.0, 1.0)),
                   make_seg(0, 4));
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.25, 0.75)),
                   make_seg(1, 3));
    }

    #[test]
    fn test_segment_closest_point_to_point() {
        let s = Segment3f::new(&vec3f(2, 0, 0),
                               &vec3f(3, 0, 0));
        assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
                   (0.0, vec3f(2, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
                   (1.0, vec3f(3, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
                   (0.5, vec3f(2.5, 0, 0)));
    }

    #[test]
    fn test_project_segment_as_range() {
        let s = make_seg(0, 4);
        assert_eq!(s.project_segment_as_range(&make_seg(0, 4)),
                   Rangef::new(0.0, 1.0));
        assert_eq!(s.project_segment_as_range(&make_seg(-1, 5)),
                   Rangef::new(0.0, 1.0));
        assert_eq!(s.project_segment_as_range(&make_seg(-1, -1)),
                   Rangef::new(0.0, 0.0));
        assert_eq!(s.project_segment_as_range(&make_seg(1, 3)),
                   Rangef::new(0.25, 0.75));
        assert_eq!(s.project_segment_as_range(&make_seg(3, 1)),
                   Rangef::new(0.25, 0.75));
    }
}
<commit_msg>Add missing divide<commit_after>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, lerp3, Vec3f};
use range::Rangef;
use std::ops::Add;

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Get vector from start to end (not normalized)
    pub fn to_vec3f(&self) -> Vec3f {
        self.end - self.start
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Treat the range's start and end as parametric coords. Use
    /// `point_from_parametric` to interpolate the range into a new
    /// segment. The output segment is not clamped.
    pub fn segment_from_parametric_range(&self, r: Rangef) -> Segment3f {
        Segment3f::new(&self.point_from_parametric(r.min),
                       &self.point_from_parametric(r.max))
    }

    /// Project another segment onto `self`. The result is a
    /// parametric range of `self` clamped to [0, 1].
    pub fn project_segment_as_range(&self, other: &Segment3f) -> Rangef {
        Rangef::from_sorting(self.closest_point_to_point(&other.start).0,
                             self.closest_point_to_point(&other.end).0)
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                let t = t / denom;
                (t, a + ab * t)
            }
        }
    }
}

impl Add<Vec3f> for Segment3f {
    type Output = Segment3f;
    fn add(self, v: Vec3f) -> Self::Output {
        Segment3f::new(&(self.start + v), &(self.end + v))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use range::Rangef;
    use vector::vec3f;

    fn make_seg(a: i32, b: i32) -> Segment3f {
        Segment3f::new(&vec3f(a, 0, 0), &vec3f(b, 0, 0))
    }

    #[test]
    fn test_to_vec3f() {
        assert_eq!(Segment3f::new(&vec3f(0, 0, 0),
                                  &vec3f(2, 3, 4)).to_vec3f(),
                   vec3f(2, 3, 4));

    }

    #[test]
    fn test_segment_length() {
        let s = Segment3f::new(&vec3f(0, 0, 0),
                               &vec3f(0, 0, 9));
        assert_eq!(s.length(), 9.0);
    }

    #[test]
    fn test_segment_distance_conversion() {
        let s = Segment3f::new(&vec3f(0, 1, 0),
                               &vec3f(0, 7, 0));

        let inputs = [
            (0.0f32, 0.0f32),
            (6.0, 1.0),
            (12.0, 2.0),
            (-3.0, -0.5)];

        for &(distance, delta) in inputs.iter() {
            assert_eq!(s.distance_to_parametric_delta(distance), delta);
            assert_eq!(s.distance_from_parametric_delta(delta), distance);
        }
    }

    #[test]
    fn test_point_from_parametric() {
        let s = Segment3f::new(&vec3f(0, 0, -1),
                               &vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
        assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
    }

    #[test]
    fn test_segment_from_parametric_range() {
        let s = make_seg(0, 4);
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.0, 1.0)),
                   make_seg(0, 4));
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.25, 0.75)),
                   make_seg(1, 3));
    }

    #[test]
    fn test_segment_closest_point_to_point() {
        let s = Segment3f::new(&vec3f(2, 0, 0),
                               &vec3f(3, 0, 0));
        assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
                   (0.0, vec3f(2, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
                   (1.0, vec3f(3, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
                   (0.5, vec3f(2.5, 0, 0)));
    }

    #[test]
    fn test_project_segment_as_range() {
        let s = make_seg(0, 4);
        assert_eq!(s.project_segment_as_range(&make_seg(0, 4)),
                   Rangef::new(0.0, 1.0));
        assert_eq!(s.project_segment_as_range(&make_seg(-1, 5)),
                   Rangef::new(0.0, 1.0));
        assert_eq!(s.project_segment_as_range(&make_seg(-1, -1)),
                   Rangef::new(0.0, 0.0));
        assert_eq!(s.project_segment_as_range(&make_seg(1, 3)),
                   Rangef::new(0.25, 0.75));
        assert_eq!(s.project_segment_as_range(&make_seg(3, 1)),
                   Rangef::new(0.25, 0.75));
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Élisabeth HENRY.
//
// This file is part of Caribon.
//
// Caribon is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Caribon.  If not, see <http://www.gnu.org/licenses/>.

/// `Word` type: some inner representation used by `Parser`.
///
/// You probably should not use this type directly.
#[repr(C)]
#[derive(Debug,Clone)]
pub enum Word {
    /// A String which is not part of the text (typically whitespace, HTML formatting, ...)
    Untracked(String),
    /// A word that is ignored, either because it is in `parser.ignored` or because it is
    /// a proper noun and `ignore_proper` has been set to `true`.
    Ignored(String),
    /// Tracked string, containing the string, the stemmed variant of the
    /// string, some value corresponding to the degree of repetitions and
    /// an option to a highlighting colour
    Tracked(String, String, f32, Option<&'static str>),
}

impl Word {
    /// Sets the stemmed value of a word.
    pub fn set_stemmed(&mut self, s: String) {
        match self {
            &mut Word::Tracked(_, ref mut stemmed, _, _) => {
                *stemmed = s;
            }
            _ => {}
        }
    }

    /// Sets the repetition value of a word.
    pub fn set_count(&mut self, x: f32) {
        match self {
            &mut Word::Tracked(_, _, ref mut v, _) => {
                *v = x;
            }
            _ => {}
        }
    }
}

#[repr(C)]
#[derive(Debug,Clone)]
/// The internal representation of the document.
///
/// Technically the name AST is not really well chosen, since it is not a tree, but mainly a vector of
/// `Word`s plus some additonal informations for HTML parsing, but the idea is that it is the internal
/// representation of the documentation.
pub struct Ast {
    /// Vector of `Word`s. The main data of the structure.
    pub words: Vec<Word>,
    /// Position of <head> tag, if any
    pub begin_head: Option<usize>,
    /// position of <body> tag, if any
    pub begin_body: Option<usize>,
    /// position of </body> tag, if any
    pub end_body: Option<usize>,
}

impl Ast {
    /// Creates a new, empty AST
    pub fn new() -> Ast {
        Ast {
            words: vec![],
            begin_head: None,
            begin_body: None,
            end_body: None,
        }
    }

    /// Sets begin_head to current last position of words
    ///
    /// This should be called *before* inserting the corresponding element.
    pub fn mark_begin_head(&mut self) {
        if self.begin_head.is_some() {
            return;
        }

        let i = self.words.len();
        self.begin_head = Some(i);
    }

    /// Sets begin_body to current last position of words
    ///
    /// This should be called *before* inserting the corresponding element.
    pub fn mark_begin_body(&mut self) {
        if self.begin_body.is_some() {
            return;
        }

        let i = self.words.len();
        self.begin_body = Some(i);
    }

    /// Sets end_body to current last position of words
    ///
    /// This should be called *before* inserting the corresponding element.
    pub fn mark_end_body(&mut self) {
        let i = self.words.len();
        self.end_body = Some(i);
    }

    /// Get only the words contained between <body> and </body>
    ///
    /// If body_begin and body_end are both set (and the first one is before the second),
    /// returns a slice that contains only words in this part; else, returns all words.
    pub fn get_body(&self) -> &[Word] {
        if let Some(begin) = self.begin_body {
            if let Some(end) = self.end_body {
                if begin < end {
                    return &self.words[begin + 1..end];
                }
            }
        }
        &self.words
    }

    /// Get only the words contained between <body> and </body>, mutable version
    ///
    /// Same as get_body, but takes and return a mutable reference.
    pub fn get_body_mut(&mut self) -> &mut [Word] {
        if let Some(begin) = self.begin_body {
            if let Some(end) = self.end_body {
                if begin < end {
                    return &mut self.words[begin + 1..end];
                }
            }
        }
        return &mut self.words
    }
}
<commit_msg>word.rs: rewrote math as if let when possible<commit_after>// Copyright (C) 2015 Élisabeth HENRY.
//
// This file is part of Caribon.
//
// Caribon is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Caribon.  If not, see <http://www.gnu.org/licenses/>.

/// `Word` type: some inner representation used by `Parser`.
///
/// You probably should not use this type directly.
#[repr(C)]
#[derive(Debug,Clone)]
pub enum Word {
    /// A String which is not part of the text (typically whitespace, HTML formatting, ...)
    Untracked(String),
    /// A word that is ignored, either because it is in `parser.ignored` or because it is
    /// a proper noun and `ignore_proper` has been set to `true`.
    Ignored(String),
    /// Tracked string, containing the string, the stemmed variant of the
    /// string, some value corresponding to the degree of repetitions and
    /// an option to a highlighting colour
    Tracked(String, String, f32, Option<&'static str>),
}

impl Word {
    /// Sets the stemmed value of a word.
    pub fn set_stemmed(&mut self, s: String) {
        if let &mut Word::Tracked(_, ref mut stemmed, _, _) = self {
            *stemmed = s;
        }
    }

    /// Sets the repetition value of a word.
    pub fn set_count(&mut self, x: f32) {
        if let &mut Word::Tracked(_, _, ref mut v, _) = self {
            *v = x;
        }
    }
}

#[repr(C)]
#[derive(Debug,Clone)]
/// The internal representation of the document.
///
/// Technically the name AST is not really well chosen, since it is not a tree, but mainly a vector of
/// `Word`s plus some additonal informations for HTML parsing, but the idea is that it is the internal
/// representation of the documentation.
pub struct Ast {
    /// Vector of `Word`s. The main data of the structure.
    pub words: Vec<Word>,
    /// Position of <head> tag, if any
    pub begin_head: Option<usize>,
    /// position of <body> tag, if any
    pub begin_body: Option<usize>,
    /// position of </body> tag, if any
    pub end_body: Option<usize>,
}

impl Ast {
    /// Creates a new, empty AST
    pub fn new() -> Ast {
        Ast {
            words: vec![],
            begin_head: None,
            begin_body: None,
            end_body: None,
        }
    }

    /// Sets begin_head to current last position of words
    ///
    /// This should be called *before* inserting the corresponding element.
    pub fn mark_begin_head(&mut self) {
        if self.begin_head.is_some() {
            return;
        }

        let i = self.words.len();
        self.begin_head = Some(i);
    }

    /// Sets begin_body to current last position of words
    ///
    /// This should be called *before* inserting the corresponding element.
    pub fn mark_begin_body(&mut self) {
        if self.begin_body.is_some() {
            return;
        }

        let i = self.words.len();
        self.begin_body = Some(i);
    }

    /// Sets end_body to current last position of words
    ///
    /// This should be called *before* inserting the corresponding element.
    pub fn mark_end_body(&mut self) {
        let i = self.words.len();
        self.end_body = Some(i);
    }

    /// Get only the words contained between <body> and </body>
    ///
    /// If body_begin and body_end are both set (and the first one is before the second),
    /// returns a slice that contains only words in this part; else, returns all words.
    pub fn get_body(&self) -> &[Word] {
        if let Some(begin) = self.begin_body {
            if let Some(end) = self.end_body {
                if begin < end {
                    return &self.words[begin + 1..end];
                }
            }
        }
        &self.words
    }

    /// Get only the words contained between <body> and </body>, mutable version
    ///
    /// Same as get_body, but takes and return a mutable reference.
    pub fn get_body_mut(&mut self) -> &mut [Word] {
        if let Some(begin) = self.begin_body {
            if let Some(end) = self.end_body {
                if begin < end {
                    return &mut self.words[begin + 1..end];
                }
            }
        }
        &mut self.words
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::BTreeMap;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;

static BASE_URL: &'static str = "https://api.spotify.com/v1";

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Track {
    pub album:             Album,
    pub artists:           Vec<Artist>,
    pub available_markets: Vec<String>,
    pub disc_number:       i32,
    pub duration_ms:       i32,
    pub explicit:          bool,
    pub external_ids:      BTreeMap<String, String>,
    pub external_urls:     BTreeMap<String, String>,
    pub href:              String,
    pub id:                String,
    pub is_playable:       Option<bool>,
    pub linked_from:       Option<TrackLink>,
    pub name:              String,
    pub popularity:        i32,
    pub preview_url:       String,
    pub track_number:      i32,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:               String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Album {
    pub album_type: String,
    pub artists:    Vec<Artist>,
    pub available_markets: Vec<String>,
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub images:        Vec<Image>,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Artist {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Image {
    pub height: i32,
    pub url:    String,
    pub width:  i32,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct TrackLink {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}
<commit_msg>Implement spotify::fetch_track() that fetches track detail information<commit_after>use std::io::Read;
use std::collections::BTreeMap;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;

static BASE_URL: &'static str = "https://api.spotify.com/v1";

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Track {
    pub album:             Album,
    pub artists:           Vec<Artist>,
    pub available_markets: Vec<String>,
    pub disc_number:       i32,
    pub duration_ms:       i32,
    pub explicit:          bool,
    pub external_ids:      BTreeMap<String, String>,
    pub external_urls:     BTreeMap<String, String>,
    pub href:              String,
    pub id:                String,
    pub is_playable:       Option<bool>,
    pub linked_from:       Option<TrackLink>,
    pub name:              String,
    pub popularity:        i32,
    pub preview_url:       String,
    pub track_number:      i32,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:               String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Album {
    pub album_type: String,
    pub artists:    Vec<Artist>,
    pub available_markets: Vec<String>,
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub images:        Vec<Image>,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Artist {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Image {
    pub height: i32,
    pub url:    String,
    pub width:  i32,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct TrackLink {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

/// This function fetches a track info with spotify api.
///
/// # Examples
///
/// ```
/// let track = pink_spider::spotify::fetch_track("3n3Ppam7vgaVa1iaRUc9Lp").unwrap();
///
/// assert_eq!(track.id, "3n3Ppam7vgaVa1iaRUc9Lp");
/// ```
pub fn fetch_track(id: &str) -> json::DecodeResult<Track> {
    let url    = format!("{}/tracks/{}", BASE_URL, id);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    json::decode::<Track>(&body)
}
<|endoftext|>


<commit_before>use ghclient::GithubClient;
use std;
use std::env;
use std::path::Path;
use std::string::String;
use structs::Config;

lazy_static! {
    static ref DEFAULT_CONF_PATH_STR:String = String::from("/etc/sectora.conf");
    static ref CONF_PATH_STR:String = env::var("SECTORA_CONFIG").unwrap_or(DEFAULT_CONF_PATH_STR.clone());
    static ref CONF_PATH:&'static Path = Path::new(&(*CONF_PATH_STR));
    pub static ref CONFIG:Config = match Config::new(&CONF_PATH) {
        Ok(config) => config,
        Err(err) => {
            println!("Failed to open configuration file: {:?}", *CONF_PATH);
            println!("[{:?}]", err);
            std::process::exit(11);
        }
    };
    pub static ref CLIENT:GithubClient = GithubClient::new(&CONFIG);
}
<commit_msg>Change return code for configuration error<commit_after>use ghclient::GithubClient;
use std;
use std::env;
use std::path::Path;
use std::string::String;
use structs::Config;

lazy_static! {
    static ref DEFAULT_CONF_PATH_STR:String = String::from("/etc/sectora.conf");
    static ref CONF_PATH_STR:String = env::var("SECTORA_CONFIG").unwrap_or(DEFAULT_CONF_PATH_STR.clone());
    static ref CONF_PATH:&'static Path = Path::new(&(*CONF_PATH_STR));
    pub static ref CONFIG:Config = match Config::new(&CONF_PATH) {
        Ok(config) => config,
        Err(err) => {
            println!("Failed to open configuration file: {:?}", *CONF_PATH);
            println!("[{:?}]", err);
            std::process::exit(-2);
        }
    };
    pub static ref CLIENT:GithubClient = GithubClient::new(&CONFIG);
}
<|endoftext|>


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

pub fn most_common_word(text: &str) -> (&str, u32) {
    let mut word_count: HashMap<&str, u32> = HashMap::new();

    let mut most_common_count = 0;
    let mut most_common_word: &str = "";

    for word in text.split(' ') {
        let count = match word_count.get(word) {
            None => 1,
            Some(c) => c + 1
        };
        word_count.insert(word, count);
        if count > most_common_count {
            most_common_count = count;
            most_common_word = word;
        }
    }

    (most_common_word, most_common_count)
}
<commit_msg>Use or_insert<commit_after>use std::collections::HashMap;

pub fn most_common_word(text: &str) -> (&str, u32) {
    let mut word_count: HashMap<&str, u32> = HashMap::new();

    let mut most_common_count = 0;
    let mut most_common_word: &str = "";

    for word in text.split(' ') {
        let count = word_count.entry(word).or_insert(0);
        *count += 1;
        if *count > most_common_count {
            most_common_count = *count;
            most_common_word = word;
        }
    }

    (most_common_word, most_common_count)
}
<|endoftext|>