<commit_before>import geom::*;
import comm::*;
import layout::display_list::*;

enum msg {
    draw(display_list),
    exit(comm::chan<()>)
}

fn renderer(osmain_ch: comm::chan<osmain::msg>) -> comm::chan<msg> {
    task::spawn_listener {|po|
        let draw_target_po = comm::port();
        comm::send(osmain_ch, osmain::get_draw_target(comm::chan(draw_target_po)));
        let draw_target = comm::recv(draw_target_po);

        let mut exit_confirm_ch = none;
        loop {
            alt comm::recv::<msg>(po) {
              draw(display_list) {

                draw_display_list(draw_target, display_list);

                let draw_po = comm::port();
                comm::send(osmain_ch, osmain::draw(comm::chan(draw_po)));
                comm::recv(draw_po);
              }
              exit(response_ch) {
                exit_confirm_ch = some(response_ch);
                break;
              }
            }
        }

        assert exit_confirm_ch.is_some();
        comm::send(exit_confirm_ch.get(), ());
    }
}

fn draw_display_list(
    draw_target: AzDrawTargetRef,
    display_list: display_list
) {
    clear(draw_target);

    for display_list.each {|item|
        let bounds = (*item).bounds;

        let red_color = {
            r: 1f as azure::AzFloat,
            g: 0f as azure::AzFloat,
            b: 0f as azure::AzFloat,
            a: 0.5f as azure::AzFloat
        };
        let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

        let red_rect = {
            x: au_to_int(bounds.origin.x) as azure::AzFloat,
            y: au_to_int(bounds.origin.y) as azure::AzFloat,
            width: au_to_int(bounds.size.width) as azure::AzFloat,
            height: au_to_int(bounds.size.height) as azure::AzFloat
        };
        AzDrawTargetFillRect(
            draw_target,
            ptr::addr_of(red_rect),
            unsafe { unsafe::reinterpret_cast(red_pattern) }
        );

        AzReleaseColorPattern(red_pattern);
    }
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as azure::AzFloat,
        g: 0f as azure::AzFloat,
        b: 0f as azure::AzFloat,
        a: 1f as azure::AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as azure::AzFloat,
        y: 0 as azure::AzFloat,
        width: 800 as azure::AzFloat,
        height: 600 as azure::AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

}<commit_msg>Use a more modern style in renderer<commit_after>import geom::*;
import comm::*;
import layout::display_list::*;

enum msg {
    draw(display_list),
    exit(comm::chan<()>)
}

fn renderer(osmain: chan<osmain::msg>) -> chan<msg> {
    task::spawn_listener::<msg> {|po|
        listen {|draw_target_ch|
            osmain.send(osmain::get_draw_target(draw_target_ch));
            let draw_target = draw_target_ch.recv();

            let mut exit_confirm_ch = none;
            loop {
                alt po.recv() {
                  draw(display_list) {

                    draw_display_list(draw_target, display_list);

                    listen {|draw_ch|
                        osmain.send(osmain::draw(draw_ch));
                        draw_ch.recv();
                    }
                  }
                  exit(response_ch) {
                    exit_confirm_ch = some(response_ch);
                    break;
                  }
                }
            }

            assert exit_confirm_ch.is_some();
            exit_confirm_ch.get().send(());
        }
    }
}

fn draw_display_list(
    draw_target: AzDrawTargetRef,
    display_list: display_list
) {
    clear(draw_target);

    for display_list.each {|item|
        let bounds = (*item).bounds;

        let red_color = {
            r: 1f as AzFloat,
            g: 0f as AzFloat,
            b: 0f as AzFloat,
            a: 0.5f as AzFloat
        };
        let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

        let red_rect = {
            x: au_to_int(bounds.origin.x) as AzFloat,
            y: au_to_int(bounds.origin.y) as AzFloat,
            width: au_to_int(bounds.size.width) as AzFloat,
            height: au_to_int(bounds.size.height) as AzFloat
        };
        AzDrawTargetFillRect(
            draw_target,
            ptr::addr_of(red_rect),
            unsafe { unsafe::reinterpret_cast(red_pattern) }
        );

        AzReleaseColorPattern(red_pattern);
    }
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

}<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;
extern crate exec;
extern crate regex;

#[cfg(test)]
extern crate rand;

pub mod command;
pub mod cli;
pub mod message;

use std::env;
use std::path::PathBuf;
use std::io::prelude::*;
use std::fs::File;
use std::collections::HashMap;
use rustc_serialize::json;

/// The main Key-Value structure.
pub struct Slate {

    /// Where the file containing the data is.
    pub filepath: PathBuf,
}

// FIXME: The examples are fucking up the real .slate file
// I need to pass an env variable to set up the file path
// and fallback to $HOME/.slate if the env var is not
// set.
impl Default for Slate {

    /// Get a default Slate. It will use a default file
    /// in your home directory, the `.slate` file.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// println!("{}", slate.filepath.to_str().unwrap());
    /// //=> $HOME/.slate
    /// ```
    fn default() -> Slate {
        let mut path = match env::home_dir() {
            Some(home) => home,
            None => panic!("No HOME dir found"),
        };
        path.push(".slate");

        Slate { filepath: path }
    }
}

impl Slate {

    /// Set a key with its value.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// let key = "foo".to_string();
    /// let value = "bar".to_string();
    ///
    /// match slate.set(&key, &value) {
    ///   Ok(_) => println!("Saved"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn set(&self, key: &String, value: &String) -> Result<(), &'static str> {
        let mut contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        contents.insert(key.to_owned(), value.to_owned());

        self.write(&contents)
    }

    /// Get the value of a key
    ///
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// let key = "foo".to_string();
    ///
    /// match slate.get(&key) {
    ///   Ok(value) => println!("{}", value), //=> bar
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn get(&self, key: &String) -> Result<String, &'static str> {
        let contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        match contents.get(key) {
            Some(value) => Ok(value.to_string()),
            None => Ok(String::new()),
        }
    }

    /// Remove completely a key with its value.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// let key = "foo".to_string();
    ///
    /// match slate.remove(&key) {
    ///   Ok(_) => println!("Key removed"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn remove(&self, key: &String) -> Result<(), &'static str> {
        let mut contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        contents.remove(key);

        self.write(&contents)
    }

    /// Remove all keys.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    ///
    /// match slate.clear() {
    ///   Ok(_) => println!("Keys removed"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn clear(&self) -> Result<(), &'static str> {
        let mut contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        contents.clear();

        self.write(&contents)
    }

    /// Rename a key.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// let old = "foo".to_string();
    /// let new = "bar".to_string();
    ///
    /// match slate.rename(&old, &new) {
    ///   Ok(_) => println!("Renamed!"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn rename(&self, src: &String, dts: &String) -> Result<(), &'static str> {
        let value = match self.get(src) {
            Ok(v) => v,
            Err(e) => { return Err(e) },
        };

        if let Err(e) = self.set(dts, &value) {
            return Err(e);
        };

        if let Err(e) = self.remove(src) {
            return Err(e);
        };

        Ok(())
    }

    /// Get a list of all keys.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// let list = match slate.list() {
    ///   Ok(all) => all,
    ///   Err(e) => panic!("{}", e),
    /// };
    ///
    /// for key in &list {
    ///   println!("{}", key);
    /// }
    /// ```
    pub fn list(&self) -> Result<Vec<String>, &'static str> {
        let contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        let mut keys: Vec<_> = contents.keys().collect();
        keys.sort(); // sort needs a mutable instance!!

        let list: Vec<_> = keys.iter().map(|&s| s.clone()).collect();

        Ok(list)
    }

    /// Read the contents of the Slate file.
    fn read(&self) -> Result<HashMap<String, String>, &'static str> {
        let mut r = match File::open(&self.filepath) {
            Ok(file) => file,
            Err(_) => { return Err("Cannot open file") }, // control when the file does not exist
        };

        let mut buffer = String::new();
        if let Err(_) = r.read_to_string(&mut buffer) {
            return Err("Error reading file");
        };

        let contents: HashMap<String, String> = match json::decode(&buffer) {
            Ok(hash) => hash,
            Err(_) => HashMap::new(),
        };

        Ok(contents)
    }

    /// Write to the Slate file.
    fn write(&self, contents: &HashMap<String, String>) -> Result<(), &'static str> {
        let encoded = json::encode(&contents).unwrap();

        let mut f = match File::create(&self.filepath) {
            Ok(file) => file,
            Err(_) => { return Err("Cannot create file") },
        };
        match f.write_all(encoded.as_bytes()) {
            Ok(_) => Ok(()),
            Err(_) => Err("Couldn't save file"),
        }
    }
}

/// Get the version of the library.
pub fn version() -> String {
    let (maj, min, pat) = (
        option_env!("CARGO_PKG_VERSION_MAJOR"),
        option_env!("CARGO_PKG_VERSION_MINOR"),
        option_env!("CARGO_PKG_VERSION_PATCH"),
    );

    match (maj, min, pat) {
        (Some(maj), Some(min), Some(pat)) =>
            format!("{}.{}.{}", maj, min, pat),
            _ => "".to_owned(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::path::PathBuf;
    use std::io::prelude::*;
    use std::fs::File;
    use rand::{thread_rng, Rng};

    fn create_temp_file(body: &str) -> PathBuf {
        let random_name: String = thread_rng().gen_ascii_chars().take(10).collect();
        let random_name = random_name + ".json";

        let mut temp = env::temp_dir();
        temp.push(&random_name);

        let mut file = match File::create(&temp) {
            Ok(file) => file,
            Err(e) => panic!("Cannot create temporal file for tests: {:?}", e),
        };
        if let Err(e) = file.write_all(body.as_bytes()) {
            panic!("Cannot add data to temporal file for tests: {:?}", e);
        };

        temp
    }

    #[test]
    fn test_default_slate() {
        let slate: Slate = Default::default();
        let mut expected: PathBuf = env::home_dir().unwrap();
        expected.push(".slate");

        assert_eq!(expected, slate.filepath);
    }

    #[test]
    fn it_sets_keys_with_values() {
        let temp = create_temp_file("");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };
        let key = "test".to_string();
        let value = "expected".to_string();

        if let Err(e) = slate.set(&key, &value) {
            panic!("Cannot set a value: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{\"test\":\"expected\"}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }

    #[test]
    fn it_gets_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let slate = Slate { filepath: temp };
        let key = "test".to_string();

        match slate.get(&key) {
            Ok(value) => assert_eq!("expected", value),
            Err(e) => panic!("Cannot get a value from slate: {:?}", e),
        }
    }

    #[test]
    fn it_gets_missing_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let slate = Slate { filepath: temp };
        let key = "missing".to_string();

        match slate.get(&key) {
            Ok(value) => assert_eq!("", value),
            Err(e) => panic!("Cannot get a value from slate: {:?}", e),
        }
    }

    #[test]
    fn it_lists_keys() {
        let temp = create_temp_file("{\"a\":\"1\",\"b\":\"2\"}");
        let slate = Slate { filepath: temp };

        match slate.list() {
            Ok(list) => assert_eq!(vec!["a", "b"], list),
            Err(e) => panic!("Cannot get list of values: {:?}", e),
        }
    }

    #[test]
    fn it_removes_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };
        let key = "test".to_string();

        if let Err(e) = slate.remove(&key) {
            panic!("Cannot remove the key: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }

    #[test]
    fn it_renames_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };
        let key = "test".to_string();
        let new_key = "spec".to_string();

        if let Err(e) = slate.rename(&key, &new_key) {
            panic!("Cannot move the key: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{\"spec\":\"expected\"}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }

    #[test]
    fn it_clears_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };

        if let Err(e) = slate.clear() {
            panic!("Cannot clear keys: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }
}
<commit_msg>Fix Slate code examples. Don't use default slate file.<commit_after>extern crate rustc_serialize;
extern crate docopt;
extern crate exec;
extern crate regex;

#[cfg(test)]
extern crate rand;

pub mod command;
pub mod cli;
pub mod message;

use std::env;
use std::path::PathBuf;
use std::io::prelude::*;
use std::fs::File;
use std::collections::HashMap;
use rustc_serialize::json;

/// The main Key-Value structure.
pub struct Slate {

    /// Where the file containing the data is.
    pub filepath: PathBuf,
}

impl Default for Slate {

    /// Get a default Slate. It will use a default file
    /// in your home directory, the `.slate` file.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    ///
    /// let slate: Slate = Default::default();
    /// println!("{}", slate.filepath.to_str().unwrap());
    /// //=> $HOME/.slate
    /// ```
    fn default() -> Slate {
        let mut path = match env::home_dir() {
            Some(home) => home,
            None => panic!("No HOME dir found"),
        };
        path.push(".slate");

        Slate { filepath: path }
    }
}

impl Slate {

    /// Set a key with its value.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    /// use std::env;
    ///
    /// // Create a temporal file for
    /// // the example. You can use Default::default();
    /// // to create the Slate and skip this part.
    /// let mut temp = env::temp_dir();
    /// temp.push(".slate");
    ///
    /// let slate: Slate = Slate { filepath: temp };
    /// let key = "foo".to_string();
    /// let value = "bar".to_string();
    ///
    /// match slate.set(&key, &value) {
    ///   Ok(_) => println!("Saved"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn set(&self, key: &String, value: &String) -> Result<(), &'static str> {
        let mut contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        contents.insert(key.to_owned(), value.to_owned());

        self.write(&contents)
    }

    /// Get the value of a key
    ///
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    /// use std::env;
    ///
    /// // Create a temporal file for
    /// // the example. You can use Default::default();
    /// // to create the Slate and skip this part.
    /// let mut temp = env::temp_dir();
    /// temp.push(".slate");
    ///
    /// let slate: Slate = Slate { filepath: temp };
    /// let key = "foo".to_string();
    ///
    /// match slate.get(&key) {
    ///   Ok(value) => println!("{}", value), //=> bar
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn get(&self, key: &String) -> Result<String, &'static str> {
        let contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        match contents.get(key) {
            Some(value) => Ok(value.to_string()),
            None => Ok(String::new()),
        }
    }

    /// Remove completely a key with its value.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    /// use std::env;
    ///
    /// // Create a temporal file for
    /// // the example. You can use Default::default();
    /// // to create the Slate and skip this part.
    /// let mut temp = env::temp_dir();
    /// temp.push(".slate");
    ///
    /// let slate: Slate = Slate { filepath: temp };
    /// let key = "foo".to_string();
    ///
    /// match slate.remove(&key) {
    ///   Ok(_) => println!("Key removed"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn remove(&self, key: &String) -> Result<(), &'static str> {
        let mut contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        contents.remove(key);

        self.write(&contents)
    }

    /// Remove all keys.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    /// use std::env;
    ///
    /// // Create a temporal file for
    /// // the example. You can use Default::default();
    /// // to create the Slate and skip this part.
    /// let mut temp = env::temp_dir();
    /// temp.push(".slate");
    ///
    /// let slate: Slate = Slate { filepath: temp };
    ///
    /// match slate.clear() {
    ///   Ok(_) => println!("Keys removed"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn clear(&self) -> Result<(), &'static str> {
        let mut contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        contents.clear();

        self.write(&contents)
    }

    /// Rename a key.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    /// use std::env;
    ///
    /// // Create a temporal file for
    /// // the example. You can use Default::default();
    /// // to create the Slate and skip this part.
    /// let mut temp = env::temp_dir();
    /// temp.push(".slate");
    ///
    /// let slate: Slate = Slate { filepath: temp };
    /// let old = "foo".to_string();
    /// let new = "bar".to_string();
    ///
    /// match slate.rename(&old, &new) {
    ///   Ok(_) => println!("Renamed!"),
    ///   Err(e) => panic!("{}", e),
    /// };
    /// ```
    pub fn rename(&self, src: &String, dts: &String) -> Result<(), &'static str> {
        let value = match self.get(src) {
            Ok(v) => v,
            Err(e) => { return Err(e) },
        };

        if let Err(e) = self.set(dts, &value) {
            return Err(e);
        };

        if let Err(e) = self.remove(src) {
            return Err(e);
        };

        Ok(())
    }

    /// Get a list of all keys.
    ///
    /// # Example
    ///
    /// ```
    /// use slate::Slate;
    /// use std::env;
    ///
    /// // Create a temporal file for
    /// // the example. You can use Default::default();
    /// // to create the Slate and skip this part.
    /// let mut temp = env::temp_dir();
    /// temp.push(".slate");
    ///
    /// let slate: Slate = Slate { filepath: temp };
    /// let list = match slate.list() {
    ///   Ok(all) => all,
    ///   Err(e) => panic!("{}", e),
    /// };
    ///
    /// for key in &list {
    ///   println!("{}", key);
    /// }
    /// ```
    pub fn list(&self) -> Result<Vec<String>, &'static str> {
        let contents = match self.read() {
            Ok(contents) => contents,
            Err(e) => { return Err(e) },
        };

        let mut keys: Vec<_> = contents.keys().collect();
        keys.sort(); // sort needs a mutable instance!!

        let list: Vec<_> = keys.iter().map(|&s| s.clone()).collect();

        Ok(list)
    }

    /// Read the contents of the Slate file.
    fn read(&self) -> Result<HashMap<String, String>, &'static str> {
        let mut r = match File::open(&self.filepath) {
            Ok(file) => file,
            Err(_) => {
                let empty = HashMap::new();
                match self.write(&empty) {
                    Ok(_) => File::open(&self.filepath).unwrap(),
                    Err(e) => { return Err(e) }
                }
            },
        };

        let mut buffer = String::new();
        if let Err(_) = r.read_to_string(&mut buffer) {
            return Err("Error reading file");
        };

        let contents: HashMap<String, String> = match json::decode(&buffer) {
            Ok(hash) => hash,
            Err(_) => HashMap::new(),
        };

        Ok(contents)
    }

    /// Write to the Slate file.
    fn write(&self, contents: &HashMap<String, String>) -> Result<(), &'static str> {
        let encoded = json::encode(&contents).unwrap();

        let mut f = match File::create(&self.filepath) {
            Ok(file) => file,
            Err(_) => { return Err("Cannot create file") },
        };
        match f.write_all(encoded.as_bytes()) {
            Ok(_) => Ok(()),
            Err(_) => Err("Cannot save file"),
        }
    }
}

/// Get the version of the library.
pub fn version() -> String {
    let (maj, min, pat) = (
        option_env!("CARGO_PKG_VERSION_MAJOR"),
        option_env!("CARGO_PKG_VERSION_MINOR"),
        option_env!("CARGO_PKG_VERSION_PATCH"),
    );

    match (maj, min, pat) {
        (Some(maj), Some(min), Some(pat)) =>
            format!("{}.{}.{}", maj, min, pat),
            _ => "".to_owned(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::path::PathBuf;
    use std::io::prelude::*;
    use std::fs::File;
    use rand::{thread_rng, Rng};

    fn create_temp_file(body: &str) -> PathBuf {
        let random_name: String = thread_rng().gen_ascii_chars().take(10).collect();
        let random_name = random_name + ".json";

        let mut temp = env::temp_dir();
        temp.push(&random_name);

        let mut file = match File::create(&temp) {
            Ok(file) => file,
            Err(e) => panic!("Cannot create temporal file for tests: {:?}", e),
        };
        if let Err(e) = file.write_all(body.as_bytes()) {
            panic!("Cannot add data to temporal file for tests: {:?}", e);
        };

        temp
    }

    #[test]
    fn test_default_slate() {
        let slate: Slate = Default::default();
        let mut expected: PathBuf = env::home_dir().unwrap();
        expected.push(".slate");

        assert_eq!(expected, slate.filepath);
    }

    #[test]
    fn it_sets_keys_with_values() {
        let temp = create_temp_file("");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };
        let key = "test".to_string();
        let value = "expected".to_string();

        if let Err(e) = slate.set(&key, &value) {
            panic!("Cannot set a value: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{\"test\":\"expected\"}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }

    #[test]
    fn it_gets_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let slate = Slate { filepath: temp };
        let key = "test".to_string();

        match slate.get(&key) {
            Ok(value) => assert_eq!("expected", value),
            Err(e) => panic!("Cannot get a value from slate: {:?}", e),
        }
    }

    #[test]
    fn it_gets_missing_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let slate = Slate { filepath: temp };
        let key = "missing".to_string();

        match slate.get(&key) {
            Ok(value) => assert_eq!("", value),
            Err(e) => panic!("Cannot get a value from slate: {:?}", e),
        }
    }

    #[test]
    fn it_lists_keys() {
        let temp = create_temp_file("{\"a\":\"1\",\"b\":\"2\"}");
        let slate = Slate { filepath: temp };

        match slate.list() {
            Ok(list) => assert_eq!(vec!["a", "b"], list),
            Err(e) => panic!("Cannot get list of values: {:?}", e),
        }
    }

    #[test]
    fn it_removes_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };
        let key = "test".to_string();

        if let Err(e) = slate.remove(&key) {
            panic!("Cannot remove the key: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }

    #[test]
    fn it_renames_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };
        let key = "test".to_string();
        let new_key = "spec".to_string();

        if let Err(e) = slate.rename(&key, &new_key) {
            panic!("Cannot move the key: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{\"spec\":\"expected\"}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }

    #[test]
    fn it_clears_keys() {
        let temp = create_temp_file("{\"test\":\"expected\"}");
        let mut file = File::open(&temp).unwrap();
        let slate = Slate { filepath: temp };

        if let Err(e) = slate.clear() {
            panic!("Cannot clear keys: {:?}", e);
        };

        let mut buffer = String::new();
        let expected = "{}";
        if let Err(e) = file.read_to_string(&mut buffer) {
            panic!("Cannot read temporal file for tests: {:?}", e);
        };
        assert_eq!(expected, buffer);
    }
}
<|endoftext|>


<commit_before>#![feature(ip_addr)]

#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

#[macro_use] extern crate nom;
#[macro_use] extern crate log;
#[macro_use] extern crate lazy_static;
extern crate mio;
extern crate bytes;
extern crate time;
extern crate rustc_serialize;
extern crate rand;
extern crate openssl;
extern crate pool;
extern crate uuid;

pub mod network;
pub mod parser;
pub mod messages;
<commit_msg>the ip_addr feature does not exist anymore<commit_after>#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

#[macro_use] extern crate nom;
#[macro_use] extern crate log;
#[macro_use] extern crate lazy_static;
extern crate mio;
extern crate bytes;
extern crate time;
extern crate rustc_serialize;
extern crate rand;
extern crate openssl;
extern crate pool;
extern crate uuid;

pub mod network;
pub mod parser;
pub mod messages;
<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Saving properties of the simulation to some stream (file or stdout mainly)
use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::{Path, PathBuf};

use utils;
use system::System;
use input::{Trajectory, TrajectoryResult};

/// The `Output` trait define the interface for all the quantities outputed by
/// the simulation during the run. An Output can be a text or a binary data
/// file, an image, a text log, …
pub trait Output {
    /// Function called once at the beggining of the simulation, which allow
    /// for some setup of the output if needed.
    fn setup(&mut self, _: &System) {}

    /// Write the output from the system.
    fn write(&mut self, system: &System);

    /// Function called once at the end of the simulation.
    fn finish(&mut self, _: &System) {}
}

/******************************************************************************/
/// The `TrajectoryOutput` allow to write the trajectory of the system to a
/// file, using any format supported by the
/// [Chemfiles](http://chemfiles.readthedocs.org/en/latest/formats.html) library.
pub struct TrajectoryOutput {
    file: Trajectory,
}

impl TrajectoryOutput {
    /// Create a new `TrajectoryOutput` writing to `filename`. The file is
    /// replaced if it already exists.
    pub fn new<'a, S>(filename: S) -> TrajectoryResult<TrajectoryOutput> where S: Into<&'a str> {
        Ok(TrajectoryOutput{
            file: try!(Trajectory::create(filename.into()))
        })
    }
}

impl Output for TrajectoryOutput {
    fn write(&mut self, system: &System) {
        match self.file.write(system) {
            Ok(()) => (),
            Err(err) => {
                fatal_error!("Error in while writing trajectory: {}", err.message());
            }
        }
    }
}

/******************************************************************************/
/// The `CellOutput` write all the components of a cell to a file . The columns
/// in the file contains the following values: `A B C α β γ`.
pub struct CellOutput {
    file: File,
    path: PathBuf
}

impl CellOutput {
    /// Create a new `CellOutput` writing to `filename`. The file is replaced if
    /// it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<CellOutput, io::Error> {
        Ok(CellOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for CellOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Unit cell of the simulation") {
            // Do panic in early time
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step A/Å B/Å C/Å α/deg β/deg γ/deg") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let cell = system.cell();
        if let Err(err) = writeln!(
            &mut self.file, "{} {} {} {} {} {} {}",
            system.step(), cell.a(), cell.b(), cell.c(), cell.alpha(), cell.beta(), cell.gamma()
        ) {
            // Do not panic during the simulation
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `EnergyOutput` write the energy of the system to a text file, organized
/// as: `PotentialEnergy     KineticEnergy     TotalEnergy`.
pub struct EnergyOutput {
    file: File,
    path: PathBuf
}

impl EnergyOutput {
    /// Create a new `EnergyOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<EnergyOutput, io::Error> {
        Ok(EnergyOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for EnergyOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Energy of the simulation (kJ/mol)") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Potential Kinetic Total") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let potential = utils::unit_to(system.potential_energy(), "kJ/mol");
        let kinetic = utils::unit_to(system.kinetic_energy(), "kJ/mol");
        let total = utils::unit_to(system.total_energy(), "kJ/mol");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), potential, kinetic, total) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `PropertiesOutput` write various physical properties of the system to
/// a file. These properties are:
///
/// - volume of the unit cell;
/// - instant temperature;
/// - instant pressure;
pub struct PropertiesOutput {
    file: File,
    path: PathBuf,
}

impl PropertiesOutput {
    /// Create a new `PropertiesOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<PropertiesOutput, io::Error> {
        Ok(PropertiesOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for PropertiesOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Physical properties of the simulation") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Volume/A^3 Temperature/K Pressure/bar") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let volume = utils::unit_to(system.volume(), "A^3");
        let temperature = utils::unit_to(system.temperature(), "K");
        let pressure = utils::unit_to(system.pressure(), "bar");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), volume, temperature, pressure) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::prelude::*;
    use std::fs;

    use super::*;
    use system::*;
    use types::*;
    use potentials::*;
    use units;

    fn testing_system() -> System {
        let mut system = System::from_cell(UnitCell::cubic(10.0));;

        system.add_particle(Particle::new("F"));
        system[0].position = Vector3D::zero();

        system.add_particle(Particle::new("F"));
        system[1].position = Vector3D::new(1.3, 0.0, 0.0);

        system.add_pair_interaction("F", "F",
            Box::new(Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), x0: units::from(1.2, "A").unwrap()}));
        return system;
    }

    fn check_file_content(filename: &str, content: &str) {
        let mut file = fs::File::open(filename).unwrap();
        let mut buffer = String::new();
        let _ = file.read_to_string(&mut buffer).unwrap();

        assert_eq!(buffer, content);
    }

    #[test]
    fn trajectory() {
        let filename = "testing-trajectory-output.xyz";
        let system = testing_system();
        {
            let mut out = TrajectoryOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        check_file_content(filename, "2\nWritten by the chemfiles library\nF 0 0 0\nF 1.3 0 0\n");
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn energy() {
        let filename = "testing-energy-output.dat";
        let system = testing_system();
        {
            let mut out = EnergyOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        check_file_content(filename, "# Energy of the simulation (kJ/mol)\n# Step Potential Kinetic Total\n0 1.5000000000000027 0 1.5000000000000027\n");
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn cell() {
        let filename = "testing-cell-output.dat";
        let system = testing_system();
        {
            let mut out = CellOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        check_file_content(filename, "# Unit cell of the simulation\n# Step A/Å B/Å C/Å α/deg β/deg γ/deg\n0 10 10 10 90 90 90\n");
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn properties() {
        let filename = "testing-properties-output.dat";
        let system = testing_system();
        {
            let mut out = PropertiesOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        check_file_content(filename, "# Physical properties of the simulation\n# Step Volume/A^3 Temperature/K Pressure/bar\n0 1000 0 -431.7400836223091\n");
        fs::remove_file(filename).unwrap();
    }
}
<commit_msg>Improve readability of output tests<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Saving properties of the simulation to some stream (file or stdout mainly)
use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::{Path, PathBuf};

use utils;
use system::System;
use input::{Trajectory, TrajectoryResult};

/// The `Output` trait define the interface for all the quantities outputed by
/// the simulation during the run. An Output can be a text or a binary data
/// file, an image, a text log, …
pub trait Output {
    /// Function called once at the beggining of the simulation, which allow
    /// for some setup of the output if needed.
    fn setup(&mut self, _: &System) {}

    /// Write the output from the system.
    fn write(&mut self, system: &System);

    /// Function called once at the end of the simulation.
    fn finish(&mut self, _: &System) {}
}

/******************************************************************************/
/// The `TrajectoryOutput` allow to write the trajectory of the system to a
/// file, using any format supported by the
/// [Chemfiles](http://chemfiles.readthedocs.org/en/latest/formats.html) library.
pub struct TrajectoryOutput {
    file: Trajectory,
}

impl TrajectoryOutput {
    /// Create a new `TrajectoryOutput` writing to `filename`. The file is
    /// replaced if it already exists.
    pub fn new<'a, S>(filename: S) -> TrajectoryResult<TrajectoryOutput> where S: Into<&'a str> {
        Ok(TrajectoryOutput{
            file: try!(Trajectory::create(filename.into()))
        })
    }
}

impl Output for TrajectoryOutput {
    fn write(&mut self, system: &System) {
        match self.file.write(system) {
            Ok(()) => (),
            Err(err) => {
                fatal_error!("Error in while writing trajectory: {}", err.message());
            }
        }
    }
}

/******************************************************************************/
/// The `CellOutput` write all the components of a cell to a file . The columns
/// in the file contains the following values: `A B C α β γ`.
pub struct CellOutput {
    file: File,
    path: PathBuf
}

impl CellOutput {
    /// Create a new `CellOutput` writing to `filename`. The file is replaced if
    /// it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<CellOutput, io::Error> {
        Ok(CellOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for CellOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Unit cell of the simulation") {
            // Do panic in early time
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step A/Å B/Å C/Å α/deg β/deg γ/deg") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let cell = system.cell();
        if let Err(err) = writeln!(
            &mut self.file, "{} {} {} {} {} {} {}",
            system.step(), cell.a(), cell.b(), cell.c(), cell.alpha(), cell.beta(), cell.gamma()
        ) {
            // Do not panic during the simulation
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `EnergyOutput` write the energy of the system to a text file, organized
/// as: `PotentialEnergy     KineticEnergy     TotalEnergy`.
pub struct EnergyOutput {
    file: File,
    path: PathBuf
}

impl EnergyOutput {
    /// Create a new `EnergyOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<EnergyOutput, io::Error> {
        Ok(EnergyOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for EnergyOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Energy of the simulation (kJ/mol)") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Potential Kinetic Total") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let potential = utils::unit_to(system.potential_energy(), "kJ/mol");
        let kinetic = utils::unit_to(system.kinetic_energy(), "kJ/mol");
        let total = utils::unit_to(system.total_energy(), "kJ/mol");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), potential, kinetic, total) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `PropertiesOutput` write various physical properties of the system to
/// a file. These properties are:
///
/// - volume of the unit cell;
/// - instant temperature;
/// - instant pressure;
pub struct PropertiesOutput {
    file: File,
    path: PathBuf,
}

impl PropertiesOutput {
    /// Create a new `PropertiesOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<PropertiesOutput, io::Error> {
        Ok(PropertiesOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for PropertiesOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Physical properties of the simulation") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Volume/A^3 Temperature/K Pressure/bar") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let volume = utils::unit_to(system.volume(), "A^3");
        let temperature = utils::unit_to(system.temperature(), "K");
        let pressure = utils::unit_to(system.pressure(), "bar");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), volume, temperature, pressure) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::prelude::*;
    use std::fs;

    use super::*;
    use system::*;
    use types::*;
    use potentials::*;
    use units;

    fn testing_system() -> System {
        let mut system = System::from_cell(UnitCell::cubic(10.0));;

        system.add_particle(Particle::new("F"));
        system[0].position = Vector3D::zero();

        system.add_particle(Particle::new("F"));
        system[1].position = Vector3D::new(1.3, 0.0, 0.0);

        system.add_pair_interaction("F", "F",
            Box::new(Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), x0: units::from(1.2, "A").unwrap()}));
        return system;
    }

    fn check_file_content(filename: &str, content: &str) {
        let mut file = fs::File::open(filename).unwrap();
        let mut buffer = String::new();
        let _ = file.read_to_string(&mut buffer).unwrap();

        assert_eq!(buffer, content);
    }

    #[test]
    fn trajectory() {
        let filename = "testing-trajectory-output.xyz";
        let system = testing_system();
        {
            let mut out = TrajectoryOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "2
Written by the chemfiles library
F 0 0 0
F 1.3 0 0
";

        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn energy() {
        let filename = "testing-energy-output.dat";
        let system = testing_system();
        {
            let mut out = EnergyOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Energy of the simulation (kJ/mol)
# Step Potential Kinetic Total
0 1.5000000000000027 0 1.5000000000000027
";

        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn cell() {
        let filename = "testing-cell-output.dat";
        let system = testing_system();
        {
            let mut out = CellOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Unit cell of the simulation
# Step A/Å B/Å C/Å α/deg β/deg γ/deg
0 10 10 10 90 90 90
";

        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn properties() {
        let filename = "testing-properties-output.dat";
        let system = testing_system();
        {
            let mut out = PropertiesOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Physical properties of the simulation
# Step Volume/A^3 Temperature/K Pressure/bar
0 1000 0 -431.7400836223091
";
        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }
}
<|endoftext|>


<commit_before>#![crate_name = "file_limit"]
#![cfg(linux)]

extern crate libc;

use std::io::{Error, Result};

// private fn to get the kernal struct for file limits
#[inline]
fn get_limit() -> Result<libc::rlimit> {
    unsafe {
        let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
        if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
            return Err(Error::last_os_error());
        }
        return Ok(rlim)
    }
}

#[inline]
pub fn get() -> Result<usize> {
    match get_limit() {
        Ok(rlim) => Ok(rlim.rlim_cur as usize),
        Err(err) => Err(err),
    }
}

pub enum MaxLimit {
    Val(usize),
    NoLimit,
}

#[inline]
pub fn max() -> Result<MaxLimit> {
    let rlim = match get_limit() {
        Ok(rlim) => rlim,
        Err(err) => return Err(err),
    };
    if rlim.rlim_max == libc::RLIM_INFINITY {
        Ok( MaxLimit::NoLimit )
    } else {
        Ok( MaxLimit::Val(rlim.rlim_max as usize))
    }
}

#[inline]
pub fn set_to_max() -> Result<usize> {
    let mut r = match get_limit() {
        Ok(l) => l,
        Err(err) => return Err(err),
    };
    if r.rlim_max != r.rlim_cur {
        if r.rlim_max == libc::RLIM_INFINITY { // no limit restriction
            r.rlim_cur *= 8;
        } else if r.rlim_cur < r.rlim_max{
            r.rlim_cur = r.rlim_max;
        }
        unsafe {
            if libc::setrlimit(libc::RLIMIT_NOFILE, &r) < 0 {
                let err = Error::last_os_error();
                return Err(err);
            }
        }
    }

    Ok(r.rlim_cur as usize)
}

#[test]
fn get_file_limit() {
    let lim = get().unwrap();
    assert!(lim > 0);
}

#[test]
fn max_limit() {
    match max() {
        Ok(MaxLimit::Val(v)) => {
            assert!(v > 0);
        },
        Ok(MaxLimit::NoLimit) => assert!(true),
        Err(err) => assert!(false),
    }
}

#[test]
fn set_max() {
    let cur_limit: usize = get().unwrap();
    let max_limit = set_to_max().unwrap();
    let new_limit: usize = get().unwrap();
    assert_eq!(max_limit, new_limit);
    assert!(new_limit >= cur_limit);
}
<commit_msg>configure from linux to unix<commit_after>#![crate_name = "file_limit"]
#![cfg(unix)]

extern crate libc;

use std::io::{Error, Result};

// private fn to get the kernal struct for file limits
#[inline]
fn get_limit() -> Result<libc::rlimit> {
    unsafe {
        let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0};
        if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 {
            return Err(Error::last_os_error());
        }
        return Ok(rlim)
    }
}

#[inline]
pub fn get() -> Result<usize> {
    match get_limit() {
        Ok(rlim) => Ok(rlim.rlim_cur as usize),
        Err(err) => Err(err),
    }
}

pub enum MaxLimit {
    Val(usize),
    NoLimit,
}

#[inline]
pub fn max() -> Result<MaxLimit> {
    let rlim = match get_limit() {
        Ok(rlim) => rlim,
        Err(err) => return Err(err),
    };
    if rlim.rlim_max == libc::RLIM_INFINITY {
        Ok( MaxLimit::NoLimit )
    } else {
        Ok( MaxLimit::Val(rlim.rlim_max as usize))
    }
}

#[inline]
pub fn set_to_max() -> Result<usize> {
    let mut r = match get_limit() {
        Ok(l) => l,
        Err(err) => return Err(err),
    };
    if r.rlim_max != r.rlim_cur {
        if r.rlim_max == libc::RLIM_INFINITY { // no limit restriction
            r.rlim_cur *= 8;
        } else if r.rlim_cur < r.rlim_max{
            r.rlim_cur = r.rlim_max;
        }
        unsafe {
            if libc::setrlimit(libc::RLIMIT_NOFILE, &r) < 0 {
                let err = Error::last_os_error();
                return Err(err);
            }
        }
    }

    Ok(r.rlim_cur as usize)
}

#[test]
fn get_file_limit() {
    let lim = get().unwrap();
    assert!(lim > 0);
}

#[test]
fn max_limit() {
    match max() {
        Ok(MaxLimit::Val(v)) => {
            assert!(v > 0);
        },
        Ok(MaxLimit::NoLimit) => assert!(true),
        Err(err) => assert!(false),
    }
}

#[test]
fn set_max() {
    let cur_limit: usize = get().unwrap();
    let max_limit = set_to_max().unwrap();
    let new_limit: usize = get().unwrap();
    assert_eq!(max_limit, new_limit);
    assert!(new_limit >= cur_limit);
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;
extern crate rand;

use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use rustc_serialize::{Encodable, Decodable};

use std::cmp::max;
use std::convert::From;
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::{Read, Write, Seek, SeekFrom, ErrorKind};
use std::mem::{size_of};
use std::str;

const NUM_CHILDREN: usize = 32;
const FILE_HEADER: &'static str = "B+Tree\0";
const CURRENT_VERSION: u8 = 0x01;

// specify the types for the keys & values
pub trait KeyType: Ord + Encodable + Decodable {}
pub trait ValueType: Ord + Encodable + Decodable {}

// provide generic implementations
impl<T> KeyType for T where T: KeyType {}
impl<T> ValueType for T where T: ValueType {}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
enum Payload<K: KeyType, V: ValueType> {
        Value(V),
        Children([(K,u64); NUM_CHILDREN]),
    }

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct Node<K: KeyType, V: ValueType> {
    key: K,
    parent: u64,
    payload: Payload<K,V>, // either children, or actual values
}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct WALRecord<K: KeyType, V: ValueType> {
    key: K,
    value: V,
}

/// This struct represents an on-disk B+Tree. There are NUM_CHILDREN keys at each
/// level in the tree. The on-disk format is as follows where VV is the version
/// number:
/// |-------------------------------------------|
/// | 0x42 0x2b 0x54 0x72 | 0x65 0x65 0x00 0xVV |
/// | B    +    T    r    | e    e    \0   0xVV |
/// |-------------------------------------------|
/// | smallest record in bincode format         |
/// |-------------------------------------------|
/// | ...                                       |
/// |-------------------------------------------|
/// | largest record in bincode format          |
/// |-------------------------------------------|
/// | internal nodes ...                        |
/// |-------------------------------------------|
/// | root node                                 |
/// |-------------------------------------------|
pub struct BTree<K: KeyType, V: ValueType> {
    tree_file: File,                // the file backing the whole thing
    wal_file: File,                 // write-ahead log for in-memory items
    root: Option<Node<K,V>>,        // optional in-memory copy of the root node
    max_key_size: usize,            // the size of the key in bytes
    max_value_size: usize,          // the size of the value in bytes
    mem_tree: BTreeMap<K, BTreeSet<V>>,  // the in-memory BTree that gets merged with the on-disk one
}

impl <K: KeyType, V: ValueType> BTree<K, V> {
    pub fn new(tree_file_path: String, max_key_size: usize, max_value_size: usize) -> Result<BTree<K,V>, Box<Error>> {
        // create our mem_tree
        let mut mem_tree = BTreeMap::<K, BTreeSet<V>>::new();

        let mut wal_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path.to_owned() + ".wal"));

        let record_size = max_key_size + max_value_size;

        // if we have a WAL file, replay it into the mem_tree
        if try!(wal_file.metadata()).len() != 0 {
            let mut buff = vec![0; record_size];

            loop {
                match wal_file.read_exact(&mut buff) {
                    Ok(_) => {
                        let record: WALRecord<K,V> = try!(decode(&buff));  // decode the record
                        mem_tree.entry(record.key).or_insert(BTreeSet::<V>::new()).insert(record.value);  // add it to the in-memory table
                    },
                    Err(e) => if e.kind() == ErrorKind::UnexpectedEof {
                        break  // reached the end of our file, break from the loop
                    } else {
                        return Err(From::from(e));
                    }
                }
            }
        }

        // compute the size of a on-disk Node
        let node_size: usize = (max_key_size + size_of::<u64>() + max(max_value_size, (max_key_size + size_of::<u64>()) * NUM_CHILDREN)) as usize;

        // open the data file
        let mut tree_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path));

        let metadata = try!(tree_file.metadata());

        // check to see if this is a new file
        if metadata.len() == 0 {
            // write out our header
            try!(tree_file.write(FILE_HEADER.as_bytes()));

            // write out our version
            try!(tree_file.write(&[CURRENT_VERSION]));

            // construct and return our BTree object
            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: None,
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        } else {
            let mut version_string = vec![0; 8];

            try!(tree_file.read_exact(&mut version_string));

            // make sure we've opened a proper file
            if try!(str::from_utf8(&version_string[0..FILE_HEADER.len()])) != FILE_HEADER ||
               version_string[FILE_HEADER.len()] != CURRENT_VERSION {
                return Err(From::from(std::io::Error::new(ErrorKind::InvalidData, "Invalid BTree file or BTree version")));
            }

            let mut buff = vec![0; node_size];

            // make sure we have a root node to read
            if metadata.len() < (version_string.len() + node_size) as u64 {
                // if we don't have a root node yet, just return
                return Ok(BTree{tree_file: tree_file,
                                wal_file: wal_file,
                                root: None,
                                max_key_size: max_key_size,
                                max_value_size: max_value_size,
                                mem_tree: mem_tree
                });
            }

            // seek node_size in from the end of the file to read the root node
            try!(tree_file.seek(SeekFrom::End((node_size as isize * -1) as i64)));
            try!(tree_file.read_exact(&mut buff));

            let root_node: Node<K,V> = try!(decode(&buff[..]));

            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: Some(root_node),
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        }
    }

    /// Inserts a key into the BTree
    pub fn insert(&mut self, key: K, value: V) -> Result<usize, Box<Error>> {
        let record = WALRecord{key: key, value: value};

        let record_size = self.max_key_size + self.max_value_size;
        let buff = try!(encode(&record, SizeLimit::Bounded(record_size as u64)));

        println!("BUFF SIZE: {}", buff.len());

        try!(self.wal_file.write_all(&buff));

        let WALRecord{key, value} = record;

        self.mem_tree.entry(key).or_insert(BTreeSet::<V>::new()).insert(value);

        Ok(buff.len())
    }
}

#[cfg(test)]
mod tests {

    use std::fs;
    use std::fs::OpenOptions;
    use ::BTree;
    use rand::{thread_rng, Rng};

    fn gen_temp_name() -> String {
        let file_name: String = thread_rng().gen_ascii_chars().take(10).collect();

        return "/tmp/".to_owned() + file_name.as_str() + ".btr";
    }

    fn remove_files(file_path: String) {
        fs::remove_file(&file_path);
        fs::remove_file(file_path + ".wal");
    }

    #[test]
    fn new_blank_file() {
        let file_path = gen_temp_name();

        BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();

        // make sure our two files were created
        let btf = OpenOptions::new().read(true).write(false).create(false).open(&file_path).unwrap();
        assert!(btf.metadata().unwrap().len() == 8);

        let wal = OpenOptions::new().read(true).write(false).create(false).open(file_path.to_owned() + ".wal").unwrap();
        assert!(wal.metadata().unwrap().len() == 0);

        remove_files(file_path); // remove files assuming it all went well
    }

    #[test]
    fn new_existing_file() {
        let file_path = gen_temp_name();

        {
            BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();
        }

        let btree = BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();

        // check our file lengths from the struct
        assert!(btree.tree_file.metadata().unwrap().len() == 8);
        assert!(btree.wal_file.metadata().unwrap().len() == 0);

        remove_files(file_path); // remove files assuming it all went well
    }

    #[test]
    fn insert_new_u8() {
        let file_path = gen_temp_name();

        let mut btree = BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();

        let len = btree.insert(2, 3).unwrap(); // insert into a new file

        println!("LENGTH: {}", len);

        assert!(btree.wal_file.metadata().unwrap().len() == 2);

        remove_files(file_path); // remove files assuming it all went well
    }

    #[test]
    fn insert_new_str() {
        let file_path = gen_temp_name();

        let mut btree = BTree::<String, String>::new(file_path.to_owned(), 15, 15).unwrap();

        let size = btree.insert("Hello".to_owned(), "World".to_owned()).unwrap(); // insert into a new file

        assert!(btree.wal_file.metadata().unwrap().len() == size as u64);

        remove_files(file_path); // remove files assuming it all went well
    }
}
<commit_msg>Updated insert to pad records<commit_after>extern crate bincode;
extern crate rustc_serialize;
extern crate rand;

use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use rustc_serialize::{Encodable, Decodable};

use std::cmp::max;
use std::convert::From;
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fs::File;
use std::fs::OpenOptions;
use std::io::{Read, Write, Seek, SeekFrom, ErrorKind};
use std::mem::{size_of};
use std::str;

const NUM_CHILDREN: usize = 32;
const FILE_HEADER: &'static str = "B+Tree\0";
const CURRENT_VERSION: u8 = 0x01;

// specify the types for the keys & values
pub trait KeyType: Ord + Encodable + Decodable {}
pub trait ValueType: Ord + Encodable + Decodable {}

// provide generic implementations
impl<T> KeyType for T where T: Ord + Encodable + Decodable {}
impl<T> ValueType for T where T: Ord + Encodable + Decodable {}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
enum Payload<K: KeyType, V: ValueType> {
        Value(V),
        Children([(K,u64); NUM_CHILDREN]),
    }

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct Node<K: KeyType, V: ValueType> {
    key: K,
    parent: u64,
    payload: Payload<K,V>, // either children, or actual values
}

#[derive(RustcEncodable, RustcDecodable, PartialEq)]
struct WALRecord<K: KeyType, V: ValueType> {
    key: K,
    value: V,
}

/// This struct represents an on-disk B+Tree. There are NUM_CHILDREN keys at each
/// level in the tree. The on-disk format is as follows where VV is the version
/// number:
/// |-------------------------------------------|
/// | 0x42 0x2b 0x54 0x72 | 0x65 0x65 0x00 0xVV |
/// | B    +    T    r    | e    e    \0   0xVV |
/// |-------------------------------------------|
/// | smallest record in bincode format         |
/// |-------------------------------------------|
/// | ...                                       |
/// |-------------------------------------------|
/// | largest record in bincode format          |
/// |-------------------------------------------|
/// | internal nodes ...                        |
/// |-------------------------------------------|
/// | root node                                 |
/// |-------------------------------------------|
pub struct BTree<K: KeyType, V: ValueType> {
    tree_file: File,                // the file backing the whole thing
    wal_file: File,                 // write-ahead log for in-memory items
    root: Option<Node<K,V>>,        // optional in-memory copy of the root node
    max_key_size: usize,            // the size of the key in bytes
    max_value_size: usize,          // the size of the value in bytes
    mem_tree: BTreeMap<K, BTreeSet<V>>,  // the in-memory BTree that gets merged with the on-disk one
}

impl <K: KeyType, V: ValueType> BTree<K, V> {
    pub fn new(tree_file_path: String, max_key_size: usize, max_value_size: usize) -> Result<BTree<K,V>, Box<Error>> {
        // create our mem_tree
        let mut mem_tree = BTreeMap::<K, BTreeSet<V>>::new();

        let mut wal_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path.to_owned() + ".wal"));

        let record_size = max_key_size + max_value_size;

        // if we have a WAL file, replay it into the mem_tree
        if try!(wal_file.metadata()).len() != 0 {
            let mut buff = vec![0; record_size];

            loop {
                match wal_file.read_exact(&mut buff) {
                    Ok(_) => {
                        let record: WALRecord<K,V> = try!(decode(&buff));  // decode the record
                        mem_tree.entry(record.key).or_insert(BTreeSet::<V>::new()).insert(record.value);  // add it to the in-memory table
                    },
                    Err(e) => if e.kind() == ErrorKind::UnexpectedEof {
                        break  // reached the end of our file, break from the loop
                    } else {
                        return Err(From::from(e));
                    }
                }
            }
        }

        // compute the size of a on-disk Node
        let node_size: usize = (max_key_size + size_of::<u64>() + max(max_value_size, (max_key_size + size_of::<u64>()) * NUM_CHILDREN)) as usize;

        // open the data file
        let mut tree_file = try!(OpenOptions::new().read(true).write(true).create(true).open(tree_file_path));

        let metadata = try!(tree_file.metadata());

        // check to see if this is a new file
        if metadata.len() == 0 {
            // write out our header
            try!(tree_file.write(FILE_HEADER.as_bytes()));

            // write out our version
            try!(tree_file.write(&[CURRENT_VERSION]));

            // construct and return our BTree object
            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: None,
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        } else {
            let mut version_string = vec![0; 8];

            try!(tree_file.read_exact(&mut version_string));

            // make sure we've opened a proper file
            if try!(str::from_utf8(&version_string[0..FILE_HEADER.len()])) != FILE_HEADER ||
               version_string[FILE_HEADER.len()] != CURRENT_VERSION {
                return Err(From::from(std::io::Error::new(ErrorKind::InvalidData, "Invalid BTree file or BTree version")));
            }

            let mut buff = vec![0; node_size];

            // make sure we have a root node to read
            if metadata.len() < (version_string.len() + node_size) as u64 {
                // if we don't have a root node yet, just return
                return Ok(BTree{tree_file: tree_file,
                                wal_file: wal_file,
                                root: None,
                                max_key_size: max_key_size,
                                max_value_size: max_value_size,
                                mem_tree: mem_tree
                });
            }

            // seek node_size in from the end of the file to read the root node
            try!(tree_file.seek(SeekFrom::End((node_size as isize * -1) as i64)));
            try!(tree_file.read_exact(&mut buff));

            let root_node: Node<K,V> = try!(decode(&buff[..]));

            Ok(BTree{tree_file: tree_file,
                     wal_file: wal_file,
                     root: Some(root_node),
                     max_key_size: max_key_size,
                     max_value_size: max_value_size,
                     mem_tree: mem_tree
            })
        }
    }

    /// Inserts a key into the BTree
    pub fn insert(&mut self, key: K, value: V) -> Result<usize, Box<Error>> {
        let record = WALRecord{key: key, value: value};

        // encode the record
        let record_size = self.max_key_size + self.max_value_size;
        let mut buff = try!(encode(&record, SizeLimit::Bounded(record_size as u64)));

        // padd it out to the max size
        if buff.len() > self.max_key_size + self.max_value_size {
            return Err(From::from(std::io::Error::new(ErrorKind::InvalidData, "Key and value size are too large")));
        } else {
            let diff = (self.max_key_size + self.max_value_size) - buff.len();
            buff.extend(vec![0; diff]);
        }

        try!(self.wal_file.write_all(&buff));

        let WALRecord{key, value} = record;

        self.mem_tree.entry(key).or_insert(BTreeSet::<V>::new()).insert(value);

        Ok(buff.len())
    }

    /// Merges the records on disk with the records in memory
    fn compact(&mut self) {

    }
}

#[cfg(test)]
mod tests {

    use std::fs;
    use std::fs::OpenOptions;
    use ::BTree;
    use rand::{thread_rng, Rng};

    fn gen_temp_name() -> String {
        let file_name: String = thread_rng().gen_ascii_chars().take(10).collect();

        return "/tmp/".to_owned() + file_name.as_str() + ".btr";
    }

    fn remove_files(file_path: String) {
        fs::remove_file(&file_path);
        fs::remove_file(file_path + ".wal");
    }

    #[test]
    fn new_blank_file() {
        let file_path = gen_temp_name();

        BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();

        // make sure our two files were created
        let btf = OpenOptions::new().read(true).write(false).create(false).open(&file_path).unwrap();
        assert!(btf.metadata().unwrap().len() == 8);

        let wal = OpenOptions::new().read(true).write(false).create(false).open(file_path.to_owned() + ".wal").unwrap();
        assert!(wal.metadata().unwrap().len() == 0);

        remove_files(file_path); // remove files assuming it all went well
    }

    #[test]
    fn new_existing_file() {
        let file_path = gen_temp_name();

        {
            BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();
        }

        let btree = BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();

        // check our file lengths from the struct
        assert!(btree.tree_file.metadata().unwrap().len() == 8);
        assert!(btree.wal_file.metadata().unwrap().len() == 0);

        remove_files(file_path); // remove files assuming it all went well
    }

    #[test]
    fn insert_new_u8() {
        let file_path = gen_temp_name();

        let mut btree = BTree::<u8, u8>::new(file_path.to_owned(), 1, 1).unwrap();

        let len = btree.insert(2, 3).unwrap(); // insert into a new file

        println!("LENGTH: {}", len);

        assert!(btree.wal_file.metadata().unwrap().len() == 2);

        remove_files(file_path); // remove files assuming it all went well
    }

    #[test]
    fn insert_new_str() {
        let file_path = gen_temp_name();

        let mut btree = BTree::<String, String>::new(file_path.to_owned(), 15, 15).unwrap();

        let size = btree.insert("Hello".to_owned(), "World".to_owned()).unwrap(); // insert into a new file

        assert!(btree.wal_file.metadata().unwrap().len() == size as u64);

        remove_files(file_path); // remove files assuming it all went well
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

mod task1 {
	fn sum_multiples_3_or_5_below(below: u64) -> u64 {
		let mut s = 0;
		for i in 1..below {
			if i % 5 == 0 || i % 3 == 0 {
				s += i;
			}
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_multiples_3_or_5_below(1000), 233168);
	}
}

mod task2 {
	fn sum_even_fibs_below(below: u64) -> u64 {
		let mut s = 0;
		let mut v1;
		let mut v2 = 1;
		let mut val = 1;
		while val <= below {
			if val % 2 == 0 {
				s += val;
			}
			v1 = v2;
			v2 = val;
			val = v1 + v2;
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_even_fibs_below(4000000), 4613732);
	}
}

mod task3 {
	pub fn factorize(num: u64) -> Vec<u64> {
		let mut n = num;
		let mut factor = 2u64;
		let mut factors = vec![];
		while n > 1 && factor.pow(2) <= n {
			while n % factor == 0 {
				factors.push(factor);
				n /= factor;
			}
			factor += 1;
		}
		factors.push(n);
		factors
	}

	fn largest_factor(num: u64) -> u64 {
		*factorize(num).iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_factor(600851475143), 6857);
	}
}

mod task4 {
	fn is_palindrome(num: u64) -> bool {
		let s = num.to_string().into_bytes();
		let l = s.len();
		for i in 0..l/2 {
			if s[i] != s[l - i - 1] {
				return false;
			}
		}
		true
	}

	fn largest_palindrome_product(digits: u32) -> u64 {
		let min = 10u64.pow(digits - 1);
		let max = 10u64.pow(digits) - 1;
		let mut res = vec![];
		for i in (min..max).rev() {
			for j in (min..max).rev() {
				if is_palindrome(i * j) {
					res.push(i * j);
				}
			}
		}
		*res.iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_palindrome_product(3), 906609);
	}
}
<commit_msg>solved task 5<commit_after>#![allow(dead_code)]

mod task1 {
	fn sum_multiples_3_or_5_below(below: u64) -> u64 {
		let mut s = 0;
		for i in 1..below {
			if i % 5 == 0 || i % 3 == 0 {
				s += i;
			}
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_multiples_3_or_5_below(1000), 233168);
	}
}

mod task2 {
	fn sum_even_fibs_below(below: u64) -> u64 {
		let mut s = 0;
		let mut v1;
		let mut v2 = 1;
		let mut val = 1;
		while val <= below {
			if val % 2 == 0 {
				s += val;
			}
			v1 = v2;
			v2 = val;
			val = v1 + v2;
		}
		s
	}

	#[test]
	fn test() {
		assert_eq!(sum_even_fibs_below(4000000), 4613732);
	}
}

mod task3 {
	pub fn factorize(num: u64) -> Vec<u64> {
		let mut n = num;
		let mut factor = 2u64;
		let mut factors = vec![];
		while n > 1 && factor.pow(2) <= n {
			while n % factor == 0 {
				factors.push(factor);
				n /= factor;
			}
			factor += 1;
		}
		factors.push(n);
		factors
	}

	fn largest_factor(num: u64) -> u64 {
		*factorize(num).iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_factor(600851475143), 6857);
	}
}

mod task4 {
	fn is_palindrome(num: u64) -> bool {
		let s = num.to_string().into_bytes();
		let l = s.len();
		for i in 0..l/2 {
			if s[i] != s[l - i - 1] {
				return false;
			}
		}
		true
	}

	fn largest_palindrome_product(digits: u32) -> u64 {
		let min = 10u64.pow(digits - 1);
		let max = 10u64.pow(digits) - 1;
		let mut res = vec![];
		for i in (min..max).rev() {
			for j in (min..max).rev() {
				if is_palindrome(i * j) {
					res.push(i * j);
				}
			}
		}
		*res.iter().max().unwrap()
	}

	#[test]
	fn test() {
		assert_eq!(largest_palindrome_product(3), 906609);
	}
}

mod task5 {
	use std::cmp::max;
	use std::collections::HashMap;
	use task3;

	fn factorize_map(num: u64) -> HashMap<u64, u64> {
		let mut map = HashMap::new();
		for f in task3::factorize(num) {
			let counter = map.entry(f).or_insert(0);
			*counter += 1;
		}
		map
	}

	fn smallest_multimle_of_all_up_to(num: u64) -> u64 {
		let mut all_map: HashMap<u64, u32> = HashMap::new();
		for i in (2..(num + 1)).rev() {
			for (k, v) in &factorize_map(i) {
				let counter = all_map.entry(*k).or_insert(*v as u32);
				*counter = max(*v as u32, *counter);
			}
		}
		let mut res = 1u64;
		for (k, v) in &all_map {
			res *= k.pow(*v);
		}
		res
	}

	#[test]
	fn test() {
		assert_eq!(smallest_multimle_of_all_up_to(20), 232792560);
	}
}
<|endoftext|>


<commit_before>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

//! This is the Raft Distributed Consensus Protocol implemented for Rust.
//! [Raft](http://raftconsensus.github.io/) is described as:
//!
//! > Raft is a consensus algorithm that is designed to be easy to understand. It's equivalent to
//! > Paxos in fault-tolerance and performance. The difference is that it's decomposed into
//! > relatively independent subproblems, and it cleanly addresses all major pieces needed for
//! > practical systems.
//!
//! This implementation utilizes [Cap'n Proto](https://kentonv.github.io/capnproto/) for its RPC,
//! [`mio`](https://github.com/carllerche/mio) for it's async event loop.
//!
//! If this package fails to build for you it is possibly because you do not have the
//! [`capnp`](https://capnproto.org/capnp-tool.html) utility installed. You should be able to find
//! appropriate packages for most popular distributions.
//!
//! # Consuming this library
//!
//! Consuming this library works in a few parts:
//!
//! 1. Implement `Store` and `StateMachine` such that they will hook into your application.
//! 2. Create a `Raft` with those impls which will spawn it's own `Server` and join with a cluster.
//! 3. Interact with the cluster by issuing `append()` calls.
//! 4. React to calls to `apply()` from the implemented `StateMachine`
//!
//! It's important to note that issuing an `append()` call to `Raft` does not (at this time)
//! necessarily gaurantee that the entry has been applied to the `StateMachine`, since it must be
//! successfully replicated across a majority of nodes before it is applied.
//!
//! ## State
//!
//!     // TODO
//!
//! ## StateMachine
//!
//!     // TODO
//!
//! ## Client Requests
//!
//!     // TODO
//!

extern crate bufstream;
extern crate capnp;
extern crate mio;
extern crate rand;
extern crate uuid;
#[macro_use] extern crate log;
#[macro_use] extern crate scoped_log;
#[macro_use] extern crate wrapped_enum;
#[cfg(test)] extern crate env_logger;

/// Prepares the environment testing. Should be called as the first line of every test with the
/// name of the test as the only argument.
///
/// TODO: Make this an annotation like #[rust_test] instead of a macro.
#[cfg(test)]
macro_rules! setup_test {
    ($test_name:expr) => (
        let _ = env_logger::init();
        push_log_scope!($test_name);
    );
}

pub mod state_machine;
pub mod store;
pub mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

mod backoff;
mod client;
mod connection;
mod messages;
mod replica;
mod server;
mod state;

pub use server::Server;
pub use state_machine::StateMachine;
pub use store::Store;
pub use client::Client;

use std::{io, net, ops, fmt};

use uuid::Uuid;

/// A simple convienence type.
pub type Result<T> = std::result::Result<T, Error>;

wrapped_enum!{
    /// The generic `raft::Error` is composed of one of the errors that can originate from the
    /// various libraries consumed by the library.
    /// With the exception of the `Raft` variant these are generated from `try!()` macros invoking
    /// on `io::Error` or `capnp::Error` by using
    /// [`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait).
    #[derive(Debug)]
    pub enum Error {
        /// An error originating from the [Cap'n Proto](https://github.com/dwrensha/capnproto-rust) library.
        CapnProto(capnp::Error),
        /// A specific error produced when a bad Cap'n proto message is discovered.
        SchemaError(capnp::NotInSchema),
        /// Errors originating from `std::io`.
        Io(io::Error),
        /// Raft specific errors.
        Raft(RaftError),
        /// Errors related to parsing addresses.
        AddrParse(net::AddrParseError),
    }
}

/// A Raft Error represents a Raft specific error that consuming code is expected to handle
/// gracefully.
#[derive(Debug)]
pub enum RaftError {
    /// The server ran out of slots in the slab for new connections
    ConnectionLimitReached,
    /// A client reported an invalid client id
    InvalidClientId,
    /// A replica reported back a leader not in the cluster.
    ClusterViolation,
    /// A remote connection attempted to use an unknown connection type in the connection preamble
    UnknownConnectionType,
    /// An invalid peer in in the peer set. Returned Server::new().
    InvalidPeerSet,
    /// Registering a connection failed
    ConnectionRegisterFailed,
    /// Failed to find a leader in the cluster. Try again later.
    LeaderSearchExhausted,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::CapnProto(ref error) => fmt::Display::fmt(error, f),
            Error::SchemaError(ref error) => fmt::Display::fmt(error, f),
            Error::Io(ref error) => fmt::Display::fmt(error, f),
            Error::Raft(ref error) => fmt::Debug::fmt(error, f),
            Error::AddrParse(ref error) => fmt::Debug::fmt(error, f),
        }
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}
impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
impl fmt::Display for LogIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The id of a Raft server. Must be unique among the participants in a
/// consensus group.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ServerId(u64);
impl From<u64> for ServerId {
    fn from(val: u64) -> ServerId {
        ServerId(val)
    }
}
impl Into<u64> for ServerId {
    fn into(self) -> u64 {
        self.0
    }
}
impl fmt::Debug for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ServerId({})", self.0)
    }
}
impl fmt::Display for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The ID of a Raft client.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ClientId(Uuid);
impl ClientId {
    fn new() -> ClientId {
        ClientId(Uuid::new_v4())
    }
    fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
    fn from_bytes(bytes: &[u8]) -> Result<ClientId> {
        match Uuid::from_bytes(bytes) {
            Some(uuid) => Ok(ClientId(uuid)),
            None => Err(Error::Raft(RaftError::InvalidClientId)),
        }
    }
}
impl fmt::Debug for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ClientId({})", self.0)
    }
}
impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
<commit_msg>Auto merge of #66 - pwoolcoc:fix-docs-formatting, r=danburkert<commit_after>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

//! This is the Raft Distributed Consensus Protocol implemented for Rust.
//! [Raft](http://raftconsensus.github.io/) is described as:
//!
//! > Raft is a consensus algorithm that is designed to be easy to understand. It's equivalent to
//! > Paxos in fault-tolerance and performance. The difference is that it's decomposed into
//! > relatively independent subproblems, and it cleanly addresses all major pieces needed for
//! > practical systems.
//!
//! This implementation utilizes [Cap'n Proto](https://kentonv.github.io/capnproto/) for its RPC,
//! [`mio`](https://github.com/carllerche/mio) for it's async event loop.
//!
//! If this package fails to build for you it is possibly because you do not have the
//! [`capnp`](https://capnproto.org/capnp-tool.html) utility installed. You should be able to find
//! appropriate packages for most popular distributions.
//!
//! # Consuming this library
//!
//! Consuming this library works in a few parts:
//!
//! 1. Implement `Store` and `StateMachine` such that they will hook into your application.
//! 2. Create a `Raft` with those impls which will spawn it's own `Server` and join with a cluster.
//! 3. Interact with the cluster by issuing `append()` calls.
//! 4. React to calls to `apply()` from the implemented `StateMachine`
//!
//! It's important to note that issuing an `append()` call to `Raft` does not (at this time)
//! necessarily gaurantee that the entry has been applied to the `StateMachine`, since it must be
//! successfully replicated across a majority of nodes before it is applied.
//!
//! ## State
//!
//!     // TODO
//!
//! ## StateMachine
//!
//!     // TODO
//!
//! ## Client Requests
//!
//!     // TODO
//!

extern crate bufstream;
extern crate capnp;
extern crate mio;
extern crate rand;
extern crate uuid;
#[macro_use] extern crate log;
#[macro_use] extern crate scoped_log;
#[macro_use] extern crate wrapped_enum;
#[cfg(test)] extern crate env_logger;

/// Prepares the environment testing. Should be called as the first line of every test with the
/// name of the test as the only argument.
///
/// TODO: Make this an annotation like #[rust_test] instead of a macro.
#[cfg(test)]
macro_rules! setup_test {
    ($test_name:expr) => (
        let _ = env_logger::init();
        push_log_scope!($test_name);
    );
}

pub mod state_machine;
pub mod store;
pub mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

mod backoff;
mod client;
mod connection;
mod messages;
mod replica;
mod server;
mod state;

pub use server::Server;
pub use state_machine::StateMachine;
pub use store::Store;
pub use client::Client;

use std::{io, net, ops, fmt};

use uuid::Uuid;

/// A simple convienence type.
pub type Result<T> = std::result::Result<T, Error>;

wrapped_enum!{
    #[doc = "The generic `raft::Error` is composed of one of the errors that can originate from the"]
    #[doc = "various libraries consumed by the library."]
    #[doc = "With the exception of the `Raft` variant these are generated from `try!()` macros invoking"]
    #[doc = "on `io::Error` or `capnp::Error` by using"]
    #[doc = "[`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait)."]
    #[derive(Debug)]
    pub enum Error {
        /// An error originating from the [Cap'n Proto](https://github.com/dwrensha/capnproto-rust) library.
        CapnProto(capnp::Error),
        /// A specific error produced when a bad Cap'n proto message is discovered.
        SchemaError(capnp::NotInSchema),
        /// Errors originating from `std::io`.
        Io(io::Error),
        /// Raft specific errors.
        Raft(RaftError),
        /// Errors related to parsing addresses.
        AddrParse(net::AddrParseError),
    }
}

/// A Raft Error represents a Raft specific error that consuming code is expected to handle
/// gracefully.
#[derive(Debug)]
pub enum RaftError {
    /// The server ran out of slots in the slab for new connections
    ConnectionLimitReached,
    /// A client reported an invalid client id
    InvalidClientId,
    /// A replica reported back a leader not in the cluster.
    ClusterViolation,
    /// A remote connection attempted to use an unknown connection type in the connection preamble
    UnknownConnectionType,
    /// An invalid peer in in the peer set. Returned Server::new().
    InvalidPeerSet,
    /// Registering a connection failed
    ConnectionRegisterFailed,
    /// Failed to find a leader in the cluster. Try again later.
    LeaderSearchExhausted,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::CapnProto(ref error) => fmt::Display::fmt(error, f),
            Error::SchemaError(ref error) => fmt::Display::fmt(error, f),
            Error::Io(ref error) => fmt::Display::fmt(error, f),
            Error::Raft(ref error) => fmt::Debug::fmt(error, f),
            Error::AddrParse(ref error) => fmt::Debug::fmt(error, f),
        }
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}
impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
impl fmt::Display for LogIndex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The id of a Raft server. Must be unique among the participants in a
/// consensus group.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ServerId(u64);
impl From<u64> for ServerId {
    fn from(val: u64) -> ServerId {
        ServerId(val)
    }
}
impl Into<u64> for ServerId {
    fn into(self) -> u64 {
        self.0
    }
}
impl fmt::Debug for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ServerId({})", self.0)
    }
}
impl fmt::Display for ServerId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

/// The ID of a Raft client.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ClientId(Uuid);
impl ClientId {
    fn new() -> ClientId {
        ClientId(Uuid::new_v4())
    }
    fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }
    fn from_bytes(bytes: &[u8]) -> Result<ClientId> {
        match Uuid::from_bytes(bytes) {
            Some(uuid) => Ok(ClientId(uuid)),
            None => Err(Error::Raft(RaftError::InvalidClientId)),
        }
    }
}
impl fmt::Debug for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ClientId({})", self.0)
    }
}
impl fmt::Display for ClientId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
<|endoftext|>


<commit_before>//! FizzBuzz helper library for Rust and Cargo
//!
//! Instructions: Add to your cargo tomato and go!
//!
//! # Example 1: Basic fizzbuzz
//!
//! ```
//! use fx::Fx;
//!
//! for i in (1..101).map(fx::default) {
//!     println!("{}", i);
//! }
//! ```
//!
//! # Example 2: Sum of inverse
//!
//! ```
//! use fx::Fx;
//!
//! let sum_of_non_fizz_buzz_values = (1..101)
//!     .map(fx::default)
//!     .fold(0, |a,b| a + if let Fx::I(n) = b {
//!         n
//!     } else {
//!         0
//!     });
//!
//! assert!(sum_of_non_fizz_buzz_values == 2632);
//! ```

#[macro_export]
macro_rules! fx {
    ($range:expr) => {
        for i in ($range).map(fx::default) {
            println!("{}", i);
        }
    }
}

/// Enum representing value status.
pub enum Fx {
    Fizz(u32),
    Buzz(u32),
    FizzBuzz(u32),
    I(u32),
}

impl Fx {
    /// Create new Fx enum using standard FizzBuzz rules.
    pub fn new(n: u32) -> Fx {
        Fx::arbitrary(n, |n| n % 3 == 0, |n| n % 5 == 0)
    }

    /// Create new Fx enum using arbitrary FizzBuzz rules.
    pub fn arbitrary<FA, FB>(n: u32, fa: FA, fb: FB) -> Fx
        where FA: Fn(u32) -> bool,
              FB: Fn(u32) -> bool
    {
        match (n, fa(n), fb(n)) {
            (n, true, true) => Fx::FizzBuzz(n),
            (n, true, _) => Fx::Fizz(n),
            (n, _, true) => Fx::Buzz(n),
            (n, _, _) => Fx::I(n),
        }
    }
}

/// Print Fx value to console.
impl std::fmt::Display for Fx {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            &Fx::FizzBuzz(_) => write!(f, "FizzBuzz"),
            &Fx::Fizz(_) => write!(f, "Fizz"),
            &Fx::Buzz(_) => write!(f, "Buzz"),
            &Fx::I(n) => write!(f, "{}", n),
        }
    }
}

/// Convenience method for creating a new default Fx enum.
pub fn default(n: u32) -> Fx {
    Fx::new(n)
}

#[cfg(test)]
mod test {
    use super::Fx;

    #[test]
    fn integers_work() {
        assert!(format!("{}", Fx::new(2)) == "2");
    }

    #[test]
    fn fizz_works() {
        assert!(format!("{}", Fx::new(3)) == "Fizz");
    }

    #[test]
    fn buzz_works() {
        assert!(format!("{}", Fx::new(5)) == "Buzz");
    }

    #[test]
    fn fizz_buzz_works() {
        assert!(format!("{}", Fx::new(15)) == "FizzBuzz");
    }
}
<commit_msg>Add second fx! macro: `fx!(n, m)`<commit_after>//! FizzBuzz helper library for Rust and Cargo
//!
//! Instructions: Add to your cargo tomato and go!
//!
//! # Example 1: Basic fizzbuzz
//!
//! ```
//! use fx::Fx;
//!
//! for i in (1..101).map(fx::default) {
//!     println!("{}", i);
//! }
//! ```
//!
//! # Example 2: Sum of inverse
//!
//! ```
//! use fx::Fx;
//!
//! let sum_of_non_fizz_buzz_values = (1..101)
//!     .map(fx::default)
//!     .fold(0, |a,b| a + if let Fx::I(n) = b {
//!         n
//!     } else {
//!         0
//!     });
//!
//! assert!(sum_of_non_fizz_buzz_values == 2632);
//! ```
//!
//! # Macro use
//!
//! The fx! macro takes two forms. The first accepts Rust's range notation, e.g. 1..101 for values
//! 1 through 100 (the upper bound is exclusive in n..m range notation). The second instead accepts
//! inclusive lower and upper bounds, e.g. 1 and 100 for values 1 through 100.
//!
//! > fx!(1..101);
//! > fx!(1, 100);
//!
//! I mostly did this because it's kind of neat to me that macros wind up serving as a form of poor
//! man's function overloading. >.>

#[macro_export]
macro_rules! fx {
    ($range:expr) => {
        for i in ($range).map(fx::default) {
            println!("{}", i);
        }
    };

    ($n:expr, $m:expr) => {
        for i in ($n..($m + 1)).map(fx::default) {
            println!("{}", i);
        }
    };
}

/// Enum representing value status.
pub enum Fx {
    Fizz(u32),
    Buzz(u32),
    FizzBuzz(u32),
    I(u32),
}

impl Fx {
    /// Create new Fx enum using standard FizzBuzz rules.
    pub fn new(n: u32) -> Fx {
        Fx::arbitrary(n, |n| n % 3 == 0, |n| n % 5 == 0)
    }

    /// Create new Fx enum using arbitrary FizzBuzz rules.
    pub fn arbitrary<FA, FB>(n: u32, fa: FA, fb: FB) -> Fx
        where FA: Fn(u32) -> bool,
              FB: Fn(u32) -> bool
    {
        match (n, fa(n), fb(n)) {
            (n, true, true) => Fx::FizzBuzz(n),
            (n, true, _) => Fx::Fizz(n),
            (n, _, true) => Fx::Buzz(n),
            (n, _, _) => Fx::I(n),
        }
    }
}

/// Print Fx value to console.
impl std::fmt::Display for Fx {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            &Fx::FizzBuzz(_) => write!(f, "FizzBuzz"),
            &Fx::Fizz(_) => write!(f, "Fizz"),
            &Fx::Buzz(_) => write!(f, "Buzz"),
            &Fx::I(n) => write!(f, "{}", n),
        }
    }
}

/// Convenience method for creating a new default Fx enum.
pub fn default(n: u32) -> Fx {
    Fx::new(n)
}

#[cfg(test)]
mod test {
    use super::Fx;

    #[test]
    fn integers_work() {
        assert!(format!("{}", Fx::new(2)) == "2");
    }

    #[test]
    fn fizz_works() {
        assert!(format!("{}", Fx::new(3)) == "Fizz");
    }

    #[test]
    fn buzz_works() {
        assert!(format!("{}", Fx::new(5)) == "Buzz");
    }

    #[test]
    fn fizz_buzz_works() {
        assert!(format!("{}", Fx::new(15)) == "FizzBuzz");
    }
}
<|endoftext|>