<commit_before>#![feature(old_path)]

extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate drag_controller;
extern crate sdl2_window;

use std::cell::RefCell;

use graphics::ImageSize;
use drag_controller::{
    DragController,
    Drag
};
use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window as Window;

fn main() {
    println!("Click in the red square and drag.");
    println!("Toggle grid with G.");
    println!("Reset grid with R.");

    let opengl = OpenGL::_3_2;
    let window = Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Deform".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let image = Path::new("./bin/assets/rust-logo.png");
    let image = Texture::from_path(&image).unwrap();

    let (width, height) = image.get_size();
    let width = width as f64;
    let height = height as f64;
    let mut grid = graphics::deform::DeformGrid::new(
        [0.0, 0.0, width, height],
        20, 20
    );

    let mut drag = DragController::new();
    let mut draw_grid = true;

    let mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::{ RenderEvent, PressEvent };

        drag.event(&e, |action| {
            match action {
                Drag::Start(x, y) => {
                    match grid.hit([x, y]) {
                        None => {
                            // Did not hit deformed grid.
                            grid.add_control_point([x, y]);
                        }
                        Some(pos) => {
                            // Add point to deformed grid.
                            grid.add_control_point(pos);
                            let n = grid.ps.len();
                            grid.set_current(n - 1, [x, y]);
                        }
                    }
                    grid.update();
                    true
                }
                Drag::Move(x, y) => {
                    let n = grid.ps.len();
                    grid.set_current(n - 1, [x, y]);
                    grid.update();
                    true
                }
                Drag::End(_, _) => false,
                // Continue dragging when receiving focus.
                Drag::Interrupt => true,
            }
        });
        if let Some(button) = e.press_args() {
            use piston::input::Button::Keyboard;
            use piston::input::keyboard::Key;

            if button == Keyboard(Key::G) {
                draw_grid = !draw_grid;
                println!("Draw grid {}", draw_grid);
            } else if button == Keyboard(Key::R) {
                grid.reset_control_points();
                grid.reset_vertices_and_texture_coords();
                grid.update();
                println!("Reset grid");
            }
        }
        if let Some(args) = e.render_args() {
            gl.draw(
                [0, 0, args.width as i32, args.height as i32],
                |c, g| {

            graphics::clear(graphics::color::WHITE, g);

            // Draw deformed image.
            grid.draw_image(&image, &c.draw_state, c.transform, g);

            if draw_grid {
                // Draw grid.
                grid.draw_vertical_lines(
                    &graphics::Line::new([0.0, 1.0, 0.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
                grid.draw_horizontal_lines(
                    &graphics::Line::new([0.0, 0.0, 1.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
            }

            // Draw rect of the original grid.
            graphics::Rectangle::border([1.0, 0.0, 0.0, 1.0], 1.5)
                .draw([0.0, 0.0, width, height], &c.draw_state, c.transform, g);

            // Draw control points.
            let original = graphics::Ellipse::new([1.0, 0.0, 0.0, 0.5]);
            let current = graphics::Ellipse::new([0.0, 0.0, 0.0, 0.5]);
            for i in (0..grid.ps.len()) {
                use graphics::ellipse::circle;

                // Original positions.
                let x = grid.ps[i][0];
                let y = grid.ps[i][1];
                original.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);

                // Current positions.
                let x = grid.qs[i][0];
                let y = grid.qs[i][1];
                current.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);
            };

            });
        } // end render
    }
}

<commit_msg>Fix old_path import in deform example<commit_after>#![feature(old_path)]

extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate drag_controller;
extern crate sdl2_window;

use std::old_path::*;

use std::cell::RefCell;

use graphics::ImageSize;
use drag_controller::{
    DragController,
    Drag
};
use opengl_graphics::{ GlGraphics, OpenGL, Texture };
use sdl2_window::Sdl2Window as Window;

fn main() {
    println!("Click in the red square and drag.");
    println!("Toggle grid with G.");
    println!("Reset grid with R.");

    let opengl = OpenGL::_3_2;
    let window = Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Deform".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let image = Path::new("./bin/assets/rust-logo.png");
    let image = Texture::from_path(&image).unwrap();

    let (width, height) = image.get_size();
    let width = width as f64;
    let height = height as f64;
    let mut grid = graphics::deform::DeformGrid::new(
        [0.0, 0.0, width, height],
        20, 20
    );

    let mut drag = DragController::new();
    let mut draw_grid = true;

    let mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        drag.event(&e, |action| {
            match action {
                Drag::Start(x, y) => {
                    match grid.hit([x, y]) {
                        None => {
                            // Did not hit deformed grid.
                            grid.add_control_point([x, y]);
                        }
                        Some(pos) => {
                            // Add point to deformed grid.
                            grid.add_control_point(pos);
                            let n = grid.ps.len();
                            grid.set_current(n - 1, [x, y]);
                        }
                    }
                    grid.update();
                    true
                }
                Drag::Move(x, y) => {
                    let n = grid.ps.len();
                    grid.set_current(n - 1, [x, y]);
                    grid.update();
                    true
                }
                Drag::End(_, _) => false,
                // Continue dragging when receiving focus.
                Drag::Interrupt => true,
            }
        });
        if let Some(button) = e.press_args() {
            use piston::input::Button::Keyboard;
            use piston::input::keyboard::Key;

            if button == Keyboard(Key::G) {
                draw_grid = !draw_grid;
                println!("Draw grid {}", draw_grid);
            } else if button == Keyboard(Key::R) {
                grid.reset_control_points();
                grid.reset_vertices_and_texture_coords();
                grid.update();
                println!("Reset grid");
            }
        }
        if let Some(args) = e.render_args() {
            gl.draw(
                [0, 0, args.width as i32, args.height as i32],
                |c, g| {

            graphics::clear(graphics::color::WHITE, g);

            // Draw deformed image.
            grid.draw_image(&image, &c.draw_state, c.transform, g);

            if draw_grid {
                // Draw grid.
                grid.draw_vertical_lines(
                    &graphics::Line::new([0.0, 1.0, 0.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
                grid.draw_horizontal_lines(
                    &graphics::Line::new([0.0, 0.0, 1.0, 1.0], 0.5),
                    &c.draw_state,
                    c.transform,
                    g
                );
            }

            // Draw rect of the original grid.
            graphics::Rectangle::border([1.0, 0.0, 0.0, 1.0], 1.5)
                .draw([0.0, 0.0, width, height], &c.draw_state, c.transform, g);

            // Draw control points.
            let original = graphics::Ellipse::new([1.0, 0.0, 0.0, 0.5]);
            let current = graphics::Ellipse::new([0.0, 0.0, 0.0, 0.5]);
            for i in (0..grid.ps.len()) {
                use graphics::ellipse::circle;

                // Original positions.
                let x = grid.ps[i][0];
                let y = grid.ps[i][1];
                original.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);

                // Current positions.
                let x = grid.qs[i][0];
                let y = grid.qs[i][1];
                current.draw(circle(x, y, 3.0), &c.draw_state, c.transform, g);
            };

            });
        } // end render
    }
}

<|endoftext|>


<commit_before>use crate::config::CONF;

use fluent::{FluentArgs, FluentBundle, FluentResource, FluentValue};
use fluent_fallback::Localization;
use regex::Regex;
use rust_embed::RustEmbed;
use std::{iter, ops, path, str, sync, vec};
use unic_langid::LanguageIdentifier;

// List of Fluent resource filenames to scan for keys from each locale directory.
static FTL_RESOURCES: &[&str] = &["cli.ftl"];

/// Embed everything in the assets folder directly into the binary
#[derive(RustEmbed)]
#[folder = "assets/"]
pub struct Asset;

lazy_static! {
    /// List of Locales in order of closeness to the runtime config
    pub static ref LOCALES: sync::RwLock<Locales> =
        sync::RwLock::new(Locales::new(CONF.get_string("language").expect("Unable to retrieve language from config")));
}

/// A prioritized locale fallback stack
#[derive(Debug)]
pub struct Locales(Vec<LanguageIdentifier>);

impl ops::Deref for Locales {
    type Target = Vec<LanguageIdentifier>;

    fn deref(&self) -> &Vec<LanguageIdentifier> {
        &self.0
    }
}

impl Locales {
    /// Negotiate a locale based on user preference and what we have available
    pub fn new(language: String) -> Locales {
        let language = normalize_lang(&language);
        let available = self::list_available_locales();
        let requested = fluent_langneg::accepted_languages::parse(&language);
        let default: LanguageIdentifier = crate::DEFAULT_LOCALE
            .parse()
            .expect("Unable to parse default locale");
        Locales(
            fluent_langneg::negotiate_languages(
                &requested,
                &available,
                Some(&default),
                fluent_langneg::NegotiationStrategy::Filtering,
            )
            .iter()
            .copied()
            .cloned()
            .collect(),
        )
    }
}

/// A Fluent key plus any variables that will be needed to format it.
#[derive(Debug)]
pub struct LocalText<'a> {
    key: String,
    args: Option<FluentArgs<'a>>,
}

impl<'a> LocalText<'a> {
    /// Make a new localizable text placeholder for a Fluent key with no args
    pub fn new(key: &str) -> LocalText {
        LocalText {
            key: String::from(key),
            args: None,
        }
    }

    /// Add values for variables to be passed as arguments to Fluent
    pub fn arg(self, var: &'a str, val: impl ToString) -> LocalText<'a> {
        let value = FluentValue::from(val.to_string());
        let args: Option<FluentArgs<'a>> = match self.args {
            Some(mut args) => {
                args.insert(var, value);
                Some(args)
            }
            None => {
                let mut args: FluentArgs<'a> = FluentArgs::new();
                args.insert(var, value);
                Some(args)
            }
        };
        LocalText {
            key: String::from(&self.key),
            args,
        }
    }

    /// Format and return a string for the given key and args using the prefered locale fallback
    /// stack as negotiated at runtime.
    pub fn fmt(&self) -> String {
        let locales = LOCALES
            .read()
            .expect("Unable to read negotiated locale list");
        let mut res_path_scheme = path::PathBuf::new();
        res_path_scheme.push("{locale}");
        res_path_scheme.push("{res_id}");
        let generate_messages = |res_ids: &[String]| {
            let mut resolved_locales = locales.iter();
            let res_path_scheme = res_path_scheme
                .to_str()
                .expect("Locale resource path not valid");
            let res_ids = res_ids.to_vec();
            iter::from_fn(move || {
                resolved_locales.next().map(|locale| {
                    let x = vec![locale.clone()];
                    let mut bundle = FluentBundle::new(&x);
                    let res_path = res_path_scheme.replace("{locale}", &locale.to_string());
                    for res_id in &res_ids {
                        let path = res_path.replace("{res_id}", res_id);
                        if let Some(source) = Asset::get(&path) {
                            let data = str::from_utf8(source.as_ref())
                                .expect("Fluent data source not valid UTF-8");
                            let res = FluentResource::try_new(data.to_string())
                                .expect("Fluent data source not valid resource");
                            bundle
                                .add_resource(res)
                                .expect("Unable to add Fluent resource to bundle");
                        }
                    }
                    bundle
                })
            })
        };
        let loc = Localization::new(
            FTL_RESOURCES.iter().map(|s| s.to_string()).collect(),
            generate_messages,
        );
        // let value: String = loc.format_value(&self.key, &self.args).to_string();
        let value: String = loc.format_value(&self.key, self.args.as_ref()).to_string();
        value
    }
}

/// Strip off any potential system locale encoding on the end of LC_LANG
pub fn normalize_lang(input: &str) -> String {
    let re = Regex::new(r"\..*$").unwrap();
    re.replace(input, "").to_string()
}

/// Scan our embedded assets for what recognisable locale data we have on hand
// https://github.com/projectfluent/fluent-rs/blob/c9e45651/fluent-resmgr/examples/simple-resmgr.rs#L35
pub fn list_available_locales() -> Locales {
    let mut embeded = vec![];
    for asset in Asset::iter() {
        let asset_name = asset.to_string();
        let path = path::Path::new(&asset_name);
        let mut components = path.components();
        if let Some(path::Component::Normal(part)) = components.next() {
            let bytes = part
                .to_str()
                .expect("Cannot handle directory name in assets")
                .as_bytes();
            if let Ok(langid) = LanguageIdentifier::from_bytes(bytes) {
                if let Some(path::Component::Normal(part)) = components.next() {
                    if self::FTL_RESOURCES
                        .iter()
                        .any(|v| v == &part.to_str().unwrap())
                    {
                        embeded.push(langid);
                    }
                }
            }
        }
    }
    embeded.dedup();
    Locales(embeded)
}

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

    #[test]
    fn trim_systemd_locale() {
        let out = normalize_lang(&String::from("en_US.utf8"));
        assert_eq!(out, String::from("en_US"));
    }

    #[test]
    fn parse_locale() {
        let out = &fluent_langneg::accepted_languages::parse("tr_tr")[0];
        let tr: LanguageIdentifier = "tr-TR".parse().unwrap();
        assert_eq!(out.to_string(), tr.to_string());
    }
}
<commit_msg>refactor(build): Update rust-embedded usage for new crate requirements<commit_after>use crate::config::CONF;

use fluent::{FluentArgs, FluentBundle, FluentResource, FluentValue};
use fluent_fallback::Localization;
use regex::Regex;
use rust_embed::RustEmbed;
use std::{iter, ops, path, str, sync, vec};
use unic_langid::LanguageIdentifier;

// List of Fluent resource filenames to scan for keys from each locale directory.
static FTL_RESOURCES: &[&str] = &["cli.ftl"];

/// Embed everything in the assets folder directly into the binary
#[derive(RustEmbed)]
#[folder = "assets/"]
pub struct Asset;

lazy_static! {
    /// List of Locales in order of closeness to the runtime config
    pub static ref LOCALES: sync::RwLock<Locales> =
        sync::RwLock::new(Locales::new(CONF.get_string("language").expect("Unable to retrieve language from config")));
}

/// A prioritized locale fallback stack
#[derive(Debug)]
pub struct Locales(Vec<LanguageIdentifier>);

impl ops::Deref for Locales {
    type Target = Vec<LanguageIdentifier>;

    fn deref(&self) -> &Vec<LanguageIdentifier> {
        &self.0
    }
}

impl Locales {
    /// Negotiate a locale based on user preference and what we have available
    pub fn new(language: String) -> Locales {
        let language = normalize_lang(&language);
        let available = self::list_available_locales();
        let requested = fluent_langneg::accepted_languages::parse(&language);
        let default: LanguageIdentifier = crate::DEFAULT_LOCALE
            .parse()
            .expect("Unable to parse default locale");
        Locales(
            fluent_langneg::negotiate_languages(
                &requested,
                &available,
                Some(&default),
                fluent_langneg::NegotiationStrategy::Filtering,
            )
            .iter()
            .copied()
            .cloned()
            .collect(),
        )
    }
}

/// A Fluent key plus any variables that will be needed to format it.
#[derive(Debug)]
pub struct LocalText<'a> {
    key: String,
    args: Option<FluentArgs<'a>>,
}

impl<'a> LocalText<'a> {
    /// Make a new localizable text placeholder for a Fluent key with no args
    pub fn new(key: &str) -> LocalText {
        LocalText {
            key: String::from(key),
            args: None,
        }
    }

    /// Add values for variables to be passed as arguments to Fluent
    pub fn arg(self, var: &'a str, val: impl ToString) -> LocalText<'a> {
        let value = FluentValue::from(val.to_string());
        let args: Option<FluentArgs<'a>> = match self.args {
            Some(mut args) => {
                args.insert(var, value);
                Some(args)
            }
            None => {
                let mut args: FluentArgs<'a> = FluentArgs::new();
                args.insert(var, value);
                Some(args)
            }
        };
        LocalText {
            key: String::from(&self.key),
            args,
        }
    }

    /// Format and return a string for the given key and args using the prefered locale fallback
    /// stack as negotiated at runtime.
    pub fn fmt(&self) -> String {
        let locales = LOCALES
            .read()
            .expect("Unable to read negotiated locale list");
        let mut res_path_scheme = path::PathBuf::new();
        res_path_scheme.push("{locale}");
        res_path_scheme.push("{res_id}");
        let generate_messages = |res_ids: &[String]| {
            let mut resolved_locales = locales.iter();
            let res_path_scheme = res_path_scheme
                .to_str()
                .expect("Locale resource path not valid");
            let res_ids = res_ids.to_vec();
            iter::from_fn(move || {
                resolved_locales.next().map(|locale| {
                    let x = vec![locale.clone()];
                    let mut bundle = FluentBundle::new(&x);
                    let res_path = res_path_scheme.replace("{locale}", &locale.to_string());
                    for res_id in &res_ids {
                        let path = res_path.replace("{res_id}", res_id);
                        if let Some(source) = Asset::get(&path) {
                            let data = str::from_utf8(source.data.as_ref())
                                .expect("Fluent data source not valid UTF-8");
                            let res = FluentResource::try_new(data.to_string())
                                .expect("Fluent data source not valid resource");
                            bundle
                                .add_resource(res)
                                .expect("Unable to add Fluent resource to bundle");
                        }
                    }
                    bundle
                })
            })
        };
        let loc = Localization::new(
            FTL_RESOURCES.iter().map(|s| s.to_string()).collect(),
            generate_messages,
        );
        // let value: String = loc.format_value(&self.key, &self.args).to_string();
        let value: String = loc.format_value(&self.key, self.args.as_ref()).to_string();
        value
    }
}

/// Strip off any potential system locale encoding on the end of LC_LANG
pub fn normalize_lang(input: &str) -> String {
    let re = Regex::new(r"\..*$").unwrap();
    re.replace(input, "").to_string()
}

/// Scan our embedded assets for what recognisable locale data we have on hand
// https://github.com/projectfluent/fluent-rs/blob/c9e45651/fluent-resmgr/examples/simple-resmgr.rs#L35
pub fn list_available_locales() -> Locales {
    let mut embeded = vec![];
    for asset in Asset::iter() {
        let asset_name = asset.to_string();
        let path = path::Path::new(&asset_name);
        let mut components = path.components();
        if let Some(path::Component::Normal(part)) = components.next() {
            let bytes = part
                .to_str()
                .expect("Cannot handle directory name in assets")
                .as_bytes();
            if let Ok(langid) = LanguageIdentifier::from_bytes(bytes) {
                if let Some(path::Component::Normal(part)) = components.next() {
                    if self::FTL_RESOURCES
                        .iter()
                        .any(|v| v == &part.to_str().unwrap())
                    {
                        embeded.push(langid);
                    }
                }
            }
        }
    }
    embeded.dedup();
    Locales(embeded)
}

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

    #[test]
    fn trim_systemd_locale() {
        let out = normalize_lang(&String::from("en_US.utf8"));
        assert_eq!(out, String::from("en_US"));
    }

    #[test]
    fn parse_locale() {
        let out = &fluent_langneg::accepted_languages::parse("tr_tr")[0];
        let tr: LanguageIdentifier = "tr-TR".parse().unwrap();
        assert_eq!(out.to_string(), tr.to_string());
    }
}
<|endoftext|>


<commit_before>use blocking::unblock;
use futures::lock::Mutex;
use futures::TryStreamExt;
use futures_timer::Delay;
use log::trace;
use mobc::{async_trait, Manager, Pool};
use reql::cmd::connect::Options;
use reql::cmd::run::{self, Arg};
use reql::{r, Client, Connection, Error, Query, Result};
use reql_types::{Change, ServerStatus};
use std::cmp::Ordering;
use std::io;
use std::net::{IpAddr, TcpStream};
use std::ops::Deref;
use std::sync::Arc;
use std::time::{Duration, Instant};

#[async_trait]
pub trait GetConn {
    async fn get_conn(&self) -> Result<PooledConnection>;
}

#[async_trait]
impl GetConn for Pool<ReqlConnectionManager> {
    async fn get_conn(&self) -> Result<PooledConnection> {
        Ok(PooledConnection {
            conn: self.get().await.map_err(to_reql)?,
        })
    }
}

pub struct PooledConnection {
    conn: mobc::Connection<ReqlConnectionManager>,
}

impl Deref for PooledConnection {
    type Target = Connection;

    fn deref(&self) -> &Self::Target {
        &self.conn
    }
}

impl AsRef<Connection> for PooledConnection {
    fn as_ref(&self) -> &Connection {
        self.deref()
    }
}

impl<'a> Arg<'a> for &'a PooledConnection {
    fn into_run_opts(self) -> (&'a Connection, run::Options) {
        self.deref().into_run_opts()
    }
}

#[derive(Debug, Clone, Eq, Hash)]
struct Server {
    name: String,
    addresses: Vec<IpAddr>,
    port: u16,
    latency: Duration,
}

impl Ord for Server {
    fn cmp(&self, other: &Server) -> Ordering {
        self.latency.cmp(&other.latency)
    }
}

impl PartialOrd for Server {
    fn partial_cmp(&self, other: &Server) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Server {
    fn eq(&self, other: &Server) -> bool {
        self.name == other.name
    }
}

impl Server {
    fn from_status(status: ServerStatus) -> Self {
        let network = status.network;
        let addresses = network.canonical_addresses.into_iter().map(move |x| x.host);
        Self {
            name: status.name,
            addresses: addresses.collect(),
            port: network.reql_port,
            latency: Duration::from_millis(u64::MAX),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ReqlConnectionManager {
    opts: Options,
    servers: Arc<Mutex<Vec<Server>>>,
}

impl ReqlConnectionManager {
    pub fn new(opts: Options) -> Self {
        Self {
            opts,
            servers: Arc::new(Mutex::new(Vec::new())),
        }
    }

    pub async fn discover_hosts(&self) -> Result<()> {
        let conn = self.connect().await?;
        *self.servers.lock().await = self.get_servers(&conn).await?;
        let manager = self.clone();
        self.spawn_task(async move {
            let mut wait = 1;
            loop {
                if let Err(error) = manager.listen_for_hosts().await {
                    trace!(
                        "listening for host changes; error: {}, wait: {}s",
                        error,
                        wait
                    );
                    Delay::new(Duration::from_secs(wait)).await;
                    wait += 1;
                }
            }
        });
        Ok(())
    }

    async fn listen_for_hosts(&self) -> Result<()> {
        let conn = self.connect().await?;
        let mut query = server_status()
            .changes(())
            .run::<_, Change<ServerStatus, ServerStatus>>(&conn);
        let conn = self.connect().await?;
        while let Some(_) = query.try_next().await? {
            *self.servers.lock().await = self.get_servers(&conn).await?;
        }
        Ok(())
    }

    async fn get_servers(&self, conn: &Connection) -> Result<Vec<Server>> {
        let mut servers = Vec::new();
        let mut query = server_status().run(conn);
        while let Some(status) = query.try_next().await? {
            servers.push(Server::from_status(status));
        }
        set_latency(&mut servers).await;
        servers.sort();
        Ok(servers)
    }
}

async fn set_latency(servers: &mut Vec<Server>) {
    for server in servers {
        let port = server.port;
        for host in &server.addresses {
            let host = *host;
            let latency = unblock(move || {
                let start = Instant::now();
                if let Ok(_) = TcpStream::connect((host, port)) {
                    return Some(start.elapsed());
                }
                None
            })
            .await;
            if let Some(latency) = latency {
                if latency > server.latency {
                    server.latency = latency;
                }
            }
        }
    }
}

fn server_status() -> Query {
    r.db("rethinkdb").table("server_status")
}

#[async_trait]
impl Manager for ReqlConnectionManager {
    type Connection = Connection;
    type Error = Error;

    async fn connect(&self) -> Result<Self::Connection> {
        let opts = &self.opts;
        let servers = &self.servers.lock().await;
        if servers.is_empty() {
            trace!(
                "no discovered servers; host: {}, port: {}",
                opts.host,
                opts.port
            );
            return Ok(r.connect(opts.clone()).await?);
        } else {
            for server in servers.iter() {
                for host in &server.addresses {
                    trace!(
                        "discovered server {}; host: {}, port: {}",
                        server.name,
                        host,
                        server.port
                    );
                    let addr = (*host, server.port);
                    if let Ok(conn) = r.connect((addr, opts.clone())).await {
                        return Ok(conn);
                    }
                }
            }
        }
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            "no RethinkDB servers available",
        )
        .into())
    }

    async fn check(&self, conn: Self::Connection) -> Result<Self::Connection> {
        let msg = 200;
        match r.expr(msg).run(&conn).try_next().await? {
            Some(res) => verify(res, msg)?,
            None => {
                return Err(Client::ConnectionBroken.into());
            }
        }
        Ok(conn)
    }

    fn validate(&self, conn: &mut Self::Connection) -> bool {
        !conn.is_broken()
    }
}

fn verify(res: u32, msg: u32) -> Result<()> {
    if res != msg {
        return Err(Client::ConnectionBroken.into());
    }
    Ok(())
}

fn to_reql(error: mobc::Error<Error>) -> Error {
    match error {
        mobc::Error::Inner(error) => error,
        mobc::Error::Timeout => io::Error::from(io::ErrorKind::TimedOut).into(),
        mobc::Error::BadConn => Client::ConnectionBroken.into(),
    }
}
<commit_msg>reset timer after successfully pulling servers<commit_after>use blocking::unblock;
use futures::lock::Mutex;
use futures::TryStreamExt;
use futures_timer::Delay;
use log::trace;
use mobc::{async_trait, Manager, Pool};
use reql::cmd::connect::Options;
use reql::cmd::run::{self, Arg};
use reql::{r, Client, Connection, Error, Query, Result};
use reql_types::{Change, ServerStatus};
use std::cmp::Ordering;
use std::io;
use std::net::{IpAddr, TcpStream};
use std::ops::Deref;
use std::sync::Arc;
use std::time::{Duration, Instant};

#[async_trait]
pub trait GetConn {
    async fn get_conn(&self) -> Result<PooledConnection>;
}

#[async_trait]
impl GetConn for Pool<ReqlConnectionManager> {
    async fn get_conn(&self) -> Result<PooledConnection> {
        Ok(PooledConnection {
            conn: self.get().await.map_err(to_reql)?,
        })
    }
}

pub struct PooledConnection {
    conn: mobc::Connection<ReqlConnectionManager>,
}

impl Deref for PooledConnection {
    type Target = Connection;

    fn deref(&self) -> &Self::Target {
        &self.conn
    }
}

impl AsRef<Connection> for PooledConnection {
    fn as_ref(&self) -> &Connection {
        self.deref()
    }
}

impl<'a> Arg<'a> for &'a PooledConnection {
    fn into_run_opts(self) -> (&'a Connection, run::Options) {
        self.deref().into_run_opts()
    }
}

#[derive(Debug, Clone, Eq, Hash)]
struct Server {
    name: String,
    addresses: Vec<IpAddr>,
    port: u16,
    latency: Duration,
}

impl Ord for Server {
    fn cmp(&self, other: &Server) -> Ordering {
        self.latency.cmp(&other.latency)
    }
}

impl PartialOrd for Server {
    fn partial_cmp(&self, other: &Server) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Server {
    fn eq(&self, other: &Server) -> bool {
        self.name == other.name
    }
}

impl Server {
    fn from_status(status: ServerStatus) -> Self {
        let network = status.network;
        let addresses = network.canonical_addresses.into_iter().map(move |x| x.host);
        Self {
            name: status.name,
            addresses: addresses.collect(),
            port: network.reql_port,
            latency: Duration::from_millis(u64::MAX),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ReqlConnectionManager {
    opts: Options,
    servers: Arc<Mutex<Vec<Server>>>,
}

impl ReqlConnectionManager {
    pub fn new(opts: Options) -> Self {
        Self {
            opts,
            servers: Arc::new(Mutex::new(Vec::new())),
        }
    }

    pub async fn discover_hosts(&self) -> Result<()> {
        let conn = self.connect().await?;
        *self.servers.lock().await = self.get_servers(&conn).await?;
        let manager = self.clone();
        self.spawn_task(async move {
            let mut wait = 0;
            loop {
                if let Err(error) = manager.listen_for_hosts(&mut wait).await {
                    trace!(
                        "listening for host changes; error: {}, wait: {}s",
                        error,
                        wait
                    );
                    Delay::new(Duration::from_secs(wait)).await;
                    wait += 1;
                }
            }
        });
        Ok(())
    }

    async fn listen_for_hosts(&self, wait: &mut u64) -> Result<()> {
        let conn = self.connect().await?;
        let mut query = server_status()
            .changes(())
            .run::<_, Change<ServerStatus, ServerStatus>>(&conn);
        let conn = self.connect().await?;
        while let Some(_) = query.try_next().await? {
            *self.servers.lock().await = self.get_servers(&conn).await?;
            *wait = 0;
        }
        Ok(())
    }

    async fn get_servers(&self, conn: &Connection) -> Result<Vec<Server>> {
        let mut servers = Vec::new();
        let mut query = server_status().run(conn);
        while let Some(status) = query.try_next().await? {
            servers.push(Server::from_status(status));
        }
        set_latency(&mut servers).await;
        servers.sort();
        Ok(servers)
    }
}

async fn set_latency(servers: &mut Vec<Server>) {
    for server in servers {
        let port = server.port;
        for host in &server.addresses {
            let host = *host;
            let latency = unblock(move || {
                let start = Instant::now();
                if let Ok(_) = TcpStream::connect((host, port)) {
                    return Some(start.elapsed());
                }
                None
            })
            .await;
            if let Some(latency) = latency {
                if latency > server.latency {
                    server.latency = latency;
                }
            }
        }
    }
}

fn server_status() -> Query {
    r.db("rethinkdb").table("server_status")
}

#[async_trait]
impl Manager for ReqlConnectionManager {
    type Connection = Connection;
    type Error = Error;

    async fn connect(&self) -> Result<Self::Connection> {
        let opts = &self.opts;
        let servers = &self.servers.lock().await;
        if servers.is_empty() {
            trace!(
                "no discovered servers; host: {}, port: {}",
                opts.host,
                opts.port
            );
            return Ok(r.connect(opts.clone()).await?);
        } else {
            for server in servers.iter() {
                for host in &server.addresses {
                    trace!(
                        "discovered server {}; host: {}, port: {}",
                        server.name,
                        host,
                        server.port
                    );
                    let addr = (*host, server.port);
                    if let Ok(conn) = r.connect((addr, opts.clone())).await {
                        return Ok(conn);
                    }
                }
            }
        }
        Err(io::Error::new(
            io::ErrorKind::ConnectionRefused,
            "no RethinkDB servers available",
        )
        .into())
    }

    async fn check(&self, conn: Self::Connection) -> Result<Self::Connection> {
        let msg = 200;
        match r.expr(msg).run(&conn).try_next().await? {
            Some(res) => verify(res, msg)?,
            None => {
                return Err(Client::ConnectionBroken.into());
            }
        }
        Ok(conn)
    }

    fn validate(&self, conn: &mut Self::Connection) -> bool {
        !conn.is_broken()
    }
}

fn verify(res: u32, msg: u32) -> Result<()> {
    if res != msg {
        return Err(Client::ConnectionBroken.into());
    }
    Ok(())
}

fn to_reql(error: mobc::Error<Error>) -> Error {
    match error {
        mobc::Error::Inner(error) => error,
        mobc::Error::Timeout => io::Error::from(io::ErrorKind::TimedOut).into(),
        mobc::Error::BadConn => Client::ConnectionBroken.into(),
    }
}
<|endoftext|>


<commit_before>//! Mock request dispatcher and credentials for unit testing rusoto AWS service clients
//!
//! All rusoto generated service clients come with a constuctor function named `new_with` which
//! accepts three arguments
//!
//! * A `rusoto_core::DispatchSignedRequest` implementation
//! * A `rusoto_core::credential::ProvideAwsCredentials` implementation
//! * A `rusoto_core::Region`
//!
//! This crate provides mock implementations to satisfy the first two.
//!
//! # Example
//!
//! The following is an example for the `rusoto_s3` crate but should
//! work for all service crates just the same. The code is commented
//! out for illustration but also to avoid a cyclic dependency in this crate.
//!
//! ```rust
//! extern crate rusoto_mock;
//! // extern crate rusoto_s3;
//!
//! use rusoto_mock::{MockCredentialsProvider, MockRequestDispatcher, MockResponseReader};
//!
//! fn main() {
//!    // let s3 = rusoto_s3::S3Client::new_with(
//!    //   MockRequestDispatcher::default().with_body(
//!    //      MockResponseReader::read_response("test-data", "s3-response.json")
//!    //   ),
//!    //   MockCredentialsProvider,
//!    //   Default::default()
//!    // );
//! }
//! ```
#![deny(missing_docs)]
extern crate chrono;
extern crate futures;
extern crate http;
extern crate rusoto_core;
extern crate serde;
extern crate serde_json;

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use futures::future::{ok, FutureResult};
use futures::stream::once;
use http::{HttpTryFrom, StatusCode};
use rusoto_core::credential::{AwsCredentials, CredentialsError, ProvideAwsCredentials};
use rusoto_core::request::{Headers, HttpResponse};
use rusoto_core::signature::SignedRequest;
use rusoto_core::{DispatchSignedRequest, HttpDispatchError};
use serde::Serialize;

/// Provides a set of credentials that always resolve
/// successfully
pub struct MockCredentialsProvider;

impl ProvideAwsCredentials for MockCredentialsProvider {
    type Future = FutureResult<AwsCredentials, CredentialsError>;

    fn credentials(&self) -> Self::Future {
        ok(AwsCredentials::new("mock_key", "mock_secret", None, None))
    }
}

/// Composes mock API responses
///
/// A Default is provided which returns an successful response with an empty body
///
/// These can be constructed using either a Default implementation or
///  with the [with_status](method.with_status) function.
///
#[derive(Default)]
pub struct MockRequestDispatcher {
    status: StatusCode,
    body: Vec<u8>,
    headers: HashMap<String, String>,
    request_checker: Option<Box<Fn(&SignedRequest) + Send + Sync>>,
}

impl MockRequestDispatcher {
    /// Returns a instance that mocks the status code that would
    /// be returned from AWS
    pub fn with_status(status: u16) -> MockRequestDispatcher {
        MockRequestDispatcher {
            status: StatusCode::try_from(status).unwrap(),
            ..MockRequestDispatcher::default()
        }
    }

    /// Mocks the service response body what would be
    /// returned from AWS
    pub fn with_body(mut self, body: &str) -> MockRequestDispatcher {
        self.body = body.as_bytes().to_vec();
        self
    }

    /// Mocks the json serialized response body what would be
    /// returned from AWS
    pub fn with_json_body<B>(mut self, body: B) -> MockRequestDispatcher
        where B: Serialize {
        self.body = serde_json::to_vec(&body).expect("failed to deserialize into json");
        self
    }

    /// Mocks the signed request checking applied to a request before sending
    /// to AWS
    pub fn with_request_checker<F>(mut self, checker: F) -> MockRequestDispatcher
    where
        F: Fn(&SignedRequest) + Send + Sync + 'static,
    {
        self.request_checker = Some(Box::new(checker));
        self
    }

    /// Mocks a single service header that would be returned from AWS
    pub fn with_header(mut self, key: &str, value: &str) -> MockRequestDispatcher {
        self.headers.insert(key.into(), value.into());
        self
    }
}

impl DispatchSignedRequest for MockRequestDispatcher {
    type Future = FutureResult<HttpResponse, HttpDispatchError>;

    fn dispatch(&self, request: SignedRequest, _timeout: Option<Duration>) -> Self::Future {
        if self.request_checker.is_some() {
            self.request_checker.as_ref().unwrap()(&request);
        }
        ok(HttpResponse {
            status: self.status,
            body: Box::new(once(Ok(self.body.clone()))),
            headers: Headers::new(self.headers.iter().map(|(k, v)| (k.as_ref(), v.to_owned()))),
        })
    }
}

/// An interface for producing response body content
pub trait ReadMockResponse {
    /// Return a response body string for a given directory and file name
    fn read_response(dir_name: &str, file_name: &str) -> String;
}

/// Reads response body content from disk
pub struct MockResponseReader;

impl ReadMockResponse for MockResponseReader {
    fn read_response(dir_name: &str, response_name: &str) -> String {
        let file_name = format!("{}/{}", dir_name, response_name);

        let mut input_file = File::open(&file_name).expect("couldn't find file");

        let mut mock_response = String::new();

        input_file
            .read_to_string(&mut mock_response)
            .expect(&format!("Failed to read {:?}", file_name,));

        mock_response
    }
}
<commit_msg>fix rusoto_mock<commit_after>//! Mock request dispatcher and credentials for unit testing rusoto AWS service clients
//!
//! All rusoto generated service clients come with a constuctor function named `new_with` which
//! accepts three arguments
//!
//! * A `rusoto_core::DispatchSignedRequest` implementation
//! * A `rusoto_core::credential::ProvideAwsCredentials` implementation
//! * A `rusoto_core::Region`
//!
//! This crate provides mock implementations to satisfy the first two.
//!
//! # Example
//!
//! The following is an example for the `rusoto_s3` crate but should
//! work for all service crates just the same. The code is commented
//! out for illustration but also to avoid a cyclic dependency in this crate.
//!
//! ```rust
//! extern crate rusoto_mock;
//! // extern crate rusoto_s3;
//!
//! use rusoto_mock::{MockCredentialsProvider, MockRequestDispatcher, MockResponseReader};
//!
//! fn main() {
//!    // let s3 = rusoto_s3::S3Client::new_with(
//!    //   MockRequestDispatcher::default().with_body(
//!    //      MockResponseReader::read_response("test-data", "s3-response.json")
//!    //   ),
//!    //   MockCredentialsProvider,
//!    //   Default::default()
//!    // );
//! }
//! ```
#![deny(missing_docs)]
extern crate chrono;
extern crate futures;
extern crate http;
extern crate rusoto_core;
extern crate serde;
extern crate serde_json;

use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::time::Duration;

use rusoto_core::{DispatchSignedRequest, HttpDispatchError, ByteStream};
use rusoto_core::credential::{ProvideAwsCredentials, CredentialsError, AwsCredentials};
use rusoto_core::request::{Headers, HttpResponse};
use rusoto_core::signature::SignedRequest;
use futures::future::{FutureResult, ok};
use http::{HttpTryFrom, StatusCode};
use serde::Serialize;

/// Provides a set of credentials that always resolve
/// successfully
pub struct MockCredentialsProvider;

impl ProvideAwsCredentials for MockCredentialsProvider {
    type Future = FutureResult<AwsCredentials, CredentialsError>;

    fn credentials(&self) -> Self::Future {
        ok(AwsCredentials::new("mock_key", "mock_secret", None, None))
    }
}

/// Composes mock API responses
///
/// A Default is provided which returns an successful response with an empty body
///
/// These can be constructed using either a Default implementation or
///  with the [with_status](method.with_status) function.
///
#[derive(Default)]
pub struct MockRequestDispatcher {
    status: StatusCode,
    body: Vec<u8>,
    headers: HashMap<String, String>,
    request_checker: Option<Box<Fn(&SignedRequest) + Send + Sync>>,
}

impl MockRequestDispatcher {
    /// Returns a instance that mocks the status code that would
    /// be returned from AWS
    pub fn with_status(status: u16) -> MockRequestDispatcher {
        MockRequestDispatcher {
            status: StatusCode::try_from(status).unwrap(),
            ..MockRequestDispatcher::default()
        }
    }

    /// Mocks the service response body what would be
    /// returned from AWS
    pub fn with_body(mut self, body: &str) -> MockRequestDispatcher {
        self.body = body.as_bytes().to_vec();
        self
    }

    /// Mocks the json serialized response body what would be
    /// returned from AWS
    pub fn with_json_body<B>(mut self, body: B) -> MockRequestDispatcher
        where B: Serialize {
        self.body = serde_json::to_vec(&body).expect("failed to deserialize into json");
        self
    }

    /// Mocks the signed request checking applied to a request before sending
    /// to AWS
    pub fn with_request_checker<F>(mut self, checker: F) -> MockRequestDispatcher
    where
        F: Fn(&SignedRequest) + Send + Sync + 'static,
    {
        self.request_checker = Some(Box::new(checker));
        self
    }

    /// Mocks a single service header that would be returned from AWS
    pub fn with_header(mut self, key: &str, value: &str) -> MockRequestDispatcher {
        self.headers.insert(key.into(), value.into());
        self
    }
}

impl DispatchSignedRequest for MockRequestDispatcher {
    type Future = FutureResult<HttpResponse, HttpDispatchError>;

    fn dispatch(&self, request: SignedRequest, _timeout: Option<Duration>) -> Self::Future {
        if self.request_checker.is_some() {
            self.request_checker.as_ref().unwrap()(&request);
        }
        ok(HttpResponse {
            status: self.status,
            body: ByteStream::from(self.body.clone()),
            headers: Headers::new(self.headers.iter().map(|(k, v)| (k.as_ref(), v.to_owned()))),
        })
    }
}

/// An interface for producing response body content
pub trait ReadMockResponse {
    /// Return a response body string for a given directory and file name
    fn read_response(dir_name: &str, file_name: &str) -> String;
}

/// Reads response body content from disk
pub struct MockResponseReader;

impl ReadMockResponse for MockResponseReader {
    fn read_response(dir_name: &str, response_name: &str) -> String {
        let file_name = format!("{}/{}", dir_name, response_name);

        let mut input_file = File::open(&file_name).expect("couldn't find file");

        let mut mock_response = String::new();

        input_file
            .read_to_string(&mut mock_response)
            .expect(&format!("Failed to read {:?}", file_name,));

        mock_response
    }
}
<|endoftext|>


<commit_before>use hyper;
use rustc_serialize::json::Json;
use rustc_serialize::json::Json::{
    Boolean,
    F64,
    I64,
    Array,
    Null,
    String,
    U64,
};
use std::io;
use std::io::Read;
use std::error;

use SensuError::{InitError, EventError};
use defaults;

/// An Event: [The event data](http://sensuapp.org/docs/latest/event_data)
/// formatted as a struct.
#[derive(Debug, PartialEq)]
pub struct Event {
    /// Client configuration
    pub client: Client,
    /// Check Configuration
    pub check: Check,
    /// Count of the number of times this event has been going continuosly
    pub occurrences: u64,
    /// One of "create", "resolve"
    pub action: Option<String>,
}

/// The configuration of the client that sent this event
#[derive(Debug, PartialEq)]
pub struct Client {
    /// The name the client registered as
    pub name: String,
    /// The address registered by the client
    pub address: String,
    /// The subscriptions the client registered for
    pub subscriptions: Vec<String>,
    pub timestamp: i64,
    /// **Everything else**
    pub additional: Json
}

/// The client-side definition of the check plus some extra status. See the
/// [check documentation](http://sensuapp.org/docs/latest/checks) for details.
#[derive(Debug, PartialEq)]
pub struct Check {
    /* ====(  client-configured things  )==== */
    /// Name of the check (from check definition)
    pub name: String,
    /// Command being executed (from check definition)
    pub command: String,
    /// Subscription channel for the check (from check definition)
    pub subscribers: Vec<String>,
    /// How often to run the check (from check definition)
    pub interval: u64,
    /// Array of handlers to run when check results in an event (from check definition)
    pub handlers: Option<Vec<String>>,
    /// Single handler to run when check results in an event (from check definition)
    pub handler: Option<String>,

    /* ====(  Semi-standard client configs  )==== */
    /// Whether or not to alert (custom for sensu-handler)
    pub alert: Option<bool>,
    /// Minimum number of occurrences required to alert (custom for sensu-handler)
    pub occurrences: Option<u64>,
    /// Interval to run handlers (custom for sensu-handler)
    pub refresh: u64,

    /* ====(  Results, added by Sensu  )==== */
    /// When the check was issued (added by Sensu daemon)
    pub issued: i64,
    /// Check command output (added by Sensu daemon)
    pub output: String,
    /// Check exit status (added by Sensu daemon)
    pub status: i8,
    /// History of exit statuses (added by Sensu server)
    pub history: Vec<String>,
    /// Whether the check is currently flapping (added by Sensu server)
    pub flapping: bool,

    /// **Everything else**
    pub additional: Option<Json>,
}

#[derive(Debug)]
pub enum SensuError {
    InitError(String),
    EventError(String),
    ParseError(String),
    HttpError(hyper::Error)
}

pub type SensuResult<T> = Result<T, SensuError>;

impl<E: error::Error> From<E> for SensuError {
    fn from(_: E) -> SensuError {
        super::init::SensuError::ParseError(String::from("bad"))
    }
}

/// Extract a generic JS object, given a type
/// Early return an error if it can't be extracted
macro_rules! jk{
    ($j:ident -> $k:expr => $p:ident) => (
        match $j.find($k) {
            Some(value) => match value {
                &$p(ref v) => v.clone(),
                _ => return Err(EventError(format!("Wrong type for '{}': {}", $k, value)))
            },
            None => return Err(EventError(format!("couldn't find {} in event", $k)))
        }
    )
}

macro_rules! find_default{
    ($j:ident, $p:ident($k:expr), $default:expr) => (
        match $j.find($k) {
            Some(value) => match value {
                &$p(ref v) => v.clone(),
                _ => return Err(EventError(format!("Wrong type for '{}': {}", $k, value)))
            },
            None => $default
        }
    )
}

/// Extract any kind of number as an i64
/// Early return an error if it can't be extracted
macro_rules! jki {
    ($event:ident, $field:expr) => {
        match $event.find($field) {
            Some(value) => match value {
                &Json::I64(ref v) => v.clone(),
                &Json::U64(ref v) => v.clone() as i64,
                &Json::F64(ref v) => v.clone() as i64,
                _ => return Err(EventError(format!("Wrong type for '{}': {}", $field, value)))
            },
            None => return Err(EventError(format!("couldn't find '{}' in event", $field)))
        };
    }
}

macro_rules! find {
    ($event:ident, $pat:ident($field:expr)) => (
        match $event.find($field) {
            Some(value) => match *value {
                $pat(v) => Some(v),
                _ => return Err(EventError(format!("Wrong type for '{}': '{}'", $field, value)))
            },
            None => None
        }
    )
}

/// Read stdin, and parse it into an Event
pub fn init() -> SensuResult<Event> {
    let mut s = String::new();
    match io::stdin().read_to_string(&mut s) {
        Ok(_bytes) => read_event(&s),
        Err(e) => Err(InitError(format!("couldn't read stdin: {}", e)))
    }
}

/// Parse an &str into an Event, making sure that all the types match up
pub fn read_event(input: &str) -> SensuResult<Event> {
    let event: Json = match Json::from_str(input) {
        Ok(v) => v,
        Err(e) => return Err(InitError(format!("couldn't parse json: {:?}", e)))
    };

    let client = try!(read_client(&event));
    let check = try!(read_check(&event));
    let action = match event.find("action") {
        Some(action) => match *action {
            Json::String(ref a) => Some(a.clone()),
            _ => return Err(InitError(format!("Wrong type for action: {}", action)))
        },
        None => None
    };
    let occurrences = match event.find("occurrences") {
        Some(occurrences) => match *occurrences {
            Json::U64(o) => o,
            Json::I64(o) => o as u64,
            Json::F64(o) => o as u64,
            _ => return Err(InitError(format!("Wrong type for occurrences: {}", occurrences)))
        },
        None => return Err(InitError(format!("No occurrences in event data")))
    };
    Ok(Event{
        client: client,
        check: check,
        action: action,
        occurrences: occurrences,
    })
}

fn extract_list_of_strings(list: &Json, field_name: &str) -> SensuResult<Vec<String>> {
    match *list {
        Json::Array(ref subs) => {
            let mut result = Vec::new();
            for sub in subs.iter() {
                match *sub {
                    Json::String(ref s) => result.push(s.clone()),
                    _ => return Err(InitError(format!("Wrong type in {}: {}",
                                                      field_name, sub)))
                }
            }
            Ok(result)
        },
        _ => return Err(InitError(format!("{} is not a list ({})", field_name, list)))
    }
}

fn find_list_of_strings(obj: &Json, field_name: &str) -> SensuResult<Vec<String>> {
    let contained = obj.find(field_name);
    println!("{} is {:?}", field_name, contained);
    let result = match contained {
        Some(subs) => {
            try!(extract_list_of_strings(subs, field_name))
        },
        None => return Err(InitError(format!("Couldn't build {} for check", field_name)))
    };
    Ok(result)
}

fn read_client(input: &Json) -> SensuResult<Client> {
    let event = match input.find("client") {
        Some(client) => client,
        None => return Err(InitError("No client in event".to_string()))
    };

    let unverified_subs = jk!(event->"subscriptions" => Array);
    let mut subs: Vec<String> = Vec::new();
    for sub in unverified_subs.iter() {
        match *sub {
            Json::String(ref s) => subs.push(s.clone()),
            _ => return Err(EventError(format!("Invalid subscription type {}", sub)))
        }
    }

    let client = Client {
        name: jk!(event->"name" => String),
        address: jk!(event->"address" => String),
        subscriptions: subs,
        timestamp: jki!(event, "timestamp"),
        additional: Json::Null
    };
    Ok(client)
}

fn read_check(event: &Json) -> SensuResult<Check> {
    let check = match event.find("check") {
        Some(check) => check,
        None => return Err(InitError("No check in event".to_string()))
    };

    let subscribers = try!(find_list_of_strings(check, "subscribers"));

    Ok(Check {
        name: jk!(check->"name" => String),
        issued: jki!(check, "issued"),
        output: jk!(check->"output" => String),
        status: jki!(check, "status") as i8,
        command: jk!(check->"command" => String),
        subscribers: subscribers,

        alert: find!(check, Boolean("alert")),
        occurrences: find!(check, U64("occurrences")),

        interval: find_default!(check, U64("interval"), defaults().interval),
        refresh: find_default!(check, U64("refresh"), defaults().refresh),

        handler: match check.find("handler") {
            Some(handler) => match *handler {
                Json::String(ref h) => Some(h.clone()),
                _ => return Err(InitError(format!("Wrong type for handler ({})", handler)))
            },
            None => None
        },
        handlers: match check.find("handlers") {
            Some(handlers) => Some(try!(extract_list_of_strings(handlers, "handlers"))),
            None => None
        },
        history: try!(find_list_of_strings(check, "history")),
        flapping: jk!(check->"flapping" => Boolean),
        additional: None
    })
}

#[cfg(test)]
mod build_objects {
    use rustc_serialize::json::{self, Json};
    use super::{read_event, read_check, read_client, Check};

    #[test]
    fn can_build_event() {
        let event = r#"{
            "occurrences": 1,
            "action": "create",
            "client": {
                "name": "hello",
                "address": "192.168.1.1",
                "subscriptions": ["one", "two"],
                "timestamp": 127897
            },
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "handler": "default",
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#;
        match read_event(event) {
            Ok(e) => println!("Parsed event: {}", e),
            Err(e) => panic!("ERROR: {}", e)
        };
    }

    #[test]
    fn can_build_client() {
        let event = Json::from_str(r#"{
            "client": {
                "name": "hello",
                "address": "192.168.1.1",
                "subscriptions": ["one", "two"],
                "timestamp": 127897
            }
        }"#).unwrap();
        let client = read_client(&event);
        match client {
            Ok(cl) => println!("Parsed: {}", cl),
            Err(e) => panic!("ERROR: {}", e)
        }
    }

    #[test]
    fn can_build_check() {
        let event = Json::from_str(r#"{
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "refresh": 1800,
                "handler": "default",
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#).unwrap();
        match read_check(&event) {
            Ok(check) => {
                println!("Parsed: {}", check);
                assert_eq!(check, Check {
                    name: "test-check".into_string(),
                    issued: 1416069607i64,
                    output: "we have output".into_string(),
                    status: 0,
                    command: "echo 'we have output'".into_string(),
                    subscribers: vec!("examples".into_string(),
                                      "tests".into_string()),
                    alert: None,
                    occurrences: None,
                    interval: 60,
                    refresh: 1800,
                    handler: Some("default".into_string()),
                    handlers: None,
                    history: Vec::from_fn(3, |_| "0".into_string()),
                    flapping: false,
                    additional: None });
            },
            Err(e) => panic!("ERROR: {}", e)
        }
    }

        #[test]
    fn can_build_check_with_alert() {
        let event = Json::from_str(r#"{
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "refresh": 1800,
                "alert": false,
                "occurrences": 5,
                "handler": "default",
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#).unwrap();
        match read_check(&event) {
            Ok(check) => {
                println!("Parsed: {}", check);
                assert_eq!(check, Check {
                    name: "test-check".into_string(),
                    issued: 1416069607i64,
                    output: "we have output".into_string(),
                    status: 0,
                    command: "echo 'we have output'".into_string(),
                    subscribers: vec!("examples".into_string(),
                                      "tests".into_string()),

                    alert: Some(false),
                    occurrences: Some(5),

                    refresh: 1800,
                    interval: 60,
                    handler: Some("default".into_string()),
                    handlers: None,
                    history: Vec::from_fn(3, |_| "0".into_string()),
                    flapping: false,
                    additional: None });
            },
            Err(e) => panic!("ERROR: {}", e)
        }
    }

    #[test]
    fn can_build_check_with_handlers() {
        let event = Json::from_str(r#"{
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "handlers": ["default", "pagerduty"],
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#).unwrap();
        match read_check(&event) {
            Ok(cl) => println!("Parsed: {}", cl),
            Err(e) => panic!("ERROR: {}", e)
        }
    }
}
<commit_msg>all tests build, but with warnings<commit_after>use hyper;
use rustc_serialize::json::Json;
use rustc_serialize::json::Json::{
    Boolean,
    F64,
    I64,
    Array,
    Null,
    String,
    U64,
};
use std::io;
use std::io::Read;
use std::error;

use SensuError::{InitError, EventError};
use defaults;

/// An Event: [The event data](http://sensuapp.org/docs/latest/event_data)
/// formatted as a struct.
#[derive(Debug, PartialEq)]
pub struct Event {
    /// Client configuration
    pub client: Client,
    /// Check Configuration
    pub check: Check,
    /// Count of the number of times this event has been going continuosly
    pub occurrences: u64,
    /// One of "create", "resolve"
    pub action: Option<String>,
}

/// The configuration of the client that sent this event
#[derive(Debug, PartialEq)]
pub struct Client {
    /// The name the client registered as
    pub name: String,
    /// The address registered by the client
    pub address: String,
    /// The subscriptions the client registered for
    pub subscriptions: Vec<String>,
    pub timestamp: i64,
    /// **Everything else**
    pub additional: Json
}

/// The client-side definition of the check plus some extra status. See the
/// [check documentation](http://sensuapp.org/docs/latest/checks) for details.
#[derive(Debug, PartialEq)]
pub struct Check {
    /* ====(  client-configured things  )==== */
    /// Name of the check (from check definition)
    pub name: String,
    /// Command being executed (from check definition)
    pub command: String,
    /// Subscription channel for the check (from check definition)
    pub subscribers: Vec<String>,
    /// How often to run the check (from check definition)
    pub interval: u64,
    /// Array of handlers to run when check results in an event (from check definition)
    pub handlers: Option<Vec<String>>,
    /// Single handler to run when check results in an event (from check definition)
    pub handler: Option<String>,

    /* ====(  Semi-standard client configs  )==== */
    /// Whether or not to alert (custom for sensu-handler)
    pub alert: Option<bool>,
    /// Minimum number of occurrences required to alert (custom for sensu-handler)
    pub occurrences: Option<u64>,
    /// Interval to run handlers (custom for sensu-handler)
    pub refresh: u64,

    /* ====(  Results, added by Sensu  )==== */
    /// When the check was issued (added by Sensu daemon)
    pub issued: i64,
    /// Check command output (added by Sensu daemon)
    pub output: String,
    /// Check exit status (added by Sensu daemon)
    pub status: i8,
    /// History of exit statuses (added by Sensu server)
    pub history: Vec<String>,
    /// Whether the check is currently flapping (added by Sensu server)
    pub flapping: bool,

    /// **Everything else**
    pub additional: Option<Json>,
}

#[derive(Debug)]
pub enum SensuError {
    InitError(String),
    EventError(String),
    ParseError(String),
    HttpError(hyper::Error)
}

pub type SensuResult<T> = Result<T, SensuError>;

impl<E: error::Error> From<E> for SensuError {
    fn from(_: E) -> SensuError {
        super::init::SensuError::ParseError(String::from("bad"))
    }
}

/// Extract a generic JS object, given a type
/// Early return an error if it can't be extracted
macro_rules! jk{
    ($j:ident -> $k:expr => $p:ident) => (
        match $j.find($k) {
            Some(value) => match value {
                &$p(ref v) => v.clone(),
                _ => return Err(EventError(format!("Wrong type for '{}': {}", $k, value)))
            },
            None => return Err(EventError(format!("couldn't find {} in event", $k)))
        }
    )
}

macro_rules! find_default{
    ($j:ident, $p:ident($k:expr), $default:expr) => (
        match $j.find($k) {
            Some(value) => match value {
                &$p(ref v) => v.clone(),
                _ => return Err(EventError(format!("Wrong type for '{}': {}", $k, value)))
            },
            None => $default
        }
    )
}

/// Extract any kind of number as an i64
/// Early return an error if it can't be extracted
macro_rules! jki {
    ($event:ident, $field:expr) => {
        match $event.find($field) {
            Some(value) => match value {
                &Json::I64(ref v) => v.clone(),
                &Json::U64(ref v) => v.clone() as i64,
                &Json::F64(ref v) => v.clone() as i64,
                _ => return Err(EventError(format!("Wrong type for '{}': {}", $field, value)))
            },
            None => return Err(EventError(format!("couldn't find '{}' in event", $field)))
        };
    }
}

macro_rules! find {
    ($event:ident, $pat:ident($field:expr)) => (
        match $event.find($field) {
            Some(value) => match *value {
                $pat(v) => Some(v),
                _ => return Err(EventError(format!("Wrong type for '{}': '{}'", $field, value)))
            },
            None => None
        }
    )
}

/// Read stdin, and parse it into an Event
pub fn init() -> SensuResult<Event> {
    let mut s = String::new();
    match io::stdin().read_to_string(&mut s) {
        Ok(_bytes) => read_event(&s),
        Err(e) => Err(InitError(format!("couldn't read stdin: {}", e)))
    }
}

/// Parse an &str into an Event, making sure that all the types match up
pub fn read_event(input: &str) -> SensuResult<Event> {
    let event: Json = match Json::from_str(input) {
        Ok(v) => v,
        Err(e) => return Err(InitError(format!("couldn't parse json: {:?}", e)))
    };

    let client = try!(read_client(&event));
    let check = try!(read_check(&event));
    let action = match event.find("action") {
        Some(action) => match *action {
            Json::String(ref a) => Some(a.clone()),
            _ => return Err(InitError(format!("Wrong type for action: {}", action)))
        },
        None => None
    };
    let occurrences = match event.find("occurrences") {
        Some(occurrences) => match *occurrences {
            Json::U64(o) => o,
            Json::I64(o) => o as u64,
            Json::F64(o) => o as u64,
            _ => return Err(InitError(format!("Wrong type for occurrences: {}", occurrences)))
        },
        None => return Err(InitError(format!("No occurrences in event data")))
    };
    Ok(Event{
        client: client,
        check: check,
        action: action,
        occurrences: occurrences,
    })
}

fn extract_list_of_strings(list: &Json, field_name: &str) -> SensuResult<Vec<String>> {
    match *list {
        Json::Array(ref subs) => {
            let mut result = Vec::new();
            for sub in subs.iter() {
                match *sub {
                    Json::String(ref s) => result.push(s.clone()),
                    _ => return Err(InitError(format!("Wrong type in {}: {}",
                                                      field_name, sub)))
                }
            }
            Ok(result)
        },
        _ => return Err(InitError(format!("{} is not a list ({})", field_name, list)))
    }
}

fn find_list_of_strings(obj: &Json, field_name: &str) -> SensuResult<Vec<String>> {
    let contained = obj.find(field_name);
    println!("{} is {:?}", field_name, contained);
    let result = match contained {
        Some(subs) => {
            try!(extract_list_of_strings(subs, field_name))
        },
        None => return Err(InitError(format!("Couldn't build {} for check", field_name)))
    };
    Ok(result)
}

fn read_client(input: &Json) -> SensuResult<Client> {
    let event = match input.find("client") {
        Some(client) => client,
        None => return Err(InitError("No client in event".to_string()))
    };

    let unverified_subs = jk!(event->"subscriptions" => Array);
    let mut subs: Vec<String> = Vec::new();
    for sub in unverified_subs.iter() {
        match *sub {
            Json::String(ref s) => subs.push(s.clone()),
            _ => return Err(EventError(format!("Invalid subscription type {}", sub)))
        }
    }

    let client = Client {
        name: jk!(event->"name" => String),
        address: jk!(event->"address" => String),
        subscriptions: subs,
        timestamp: jki!(event, "timestamp"),
        additional: Json::Null
    };
    Ok(client)
}

fn read_check(event: &Json) -> SensuResult<Check> {
    let check = match event.find("check") {
        Some(check) => check,
        None => return Err(InitError("No check in event".to_string()))
    };

    let subscribers = try!(find_list_of_strings(check, "subscribers"));

    Ok(Check {
        name: jk!(check->"name" => String),
        issued: jki!(check, "issued"),
        output: jk!(check->"output" => String),
        status: jki!(check, "status") as i8,
        command: jk!(check->"command" => String),
        subscribers: subscribers,

        alert: find!(check, Boolean("alert")),
        occurrences: find!(check, U64("occurrences")),

        interval: find_default!(check, U64("interval"), defaults().interval),
        refresh: find_default!(check, U64("refresh"), defaults().refresh),

        handler: match check.find("handler") {
            Some(handler) => match *handler {
                Json::String(ref h) => Some(h.clone()),
                _ => return Err(InitError(format!("Wrong type for handler ({})", handler)))
            },
            None => None
        },
        handlers: match check.find("handlers") {
            Some(handlers) => Some(try!(extract_list_of_strings(handlers, "handlers"))),
            None => None
        },
        history: try!(find_list_of_strings(check, "history")),
        flapping: jk!(check->"flapping" => Boolean),
        additional: None
    })
}

#[cfg(test)]
mod build_objects {
    use rustc_serialize::json::{self, Json};
    use super::{read_event, read_check, read_client, Check};

    #[test]
    fn can_build_event() {
        let event = r#"{
            "occurrences": 1,
            "action": "create",
            "client": {
                "name": "hello",
                "address": "192.168.1.1",
                "subscriptions": ["one", "two"],
                "timestamp": 127897
            },
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "handler": "default",
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#;
        match read_event(event) {
            Ok(e) => println!("Parsed event: {:?}", e),
            Err(e) => panic!("ERROR: {:?}", e)
        };
    }

    #[test]
    fn can_build_client() {
        let event = Json::from_str(r#"{
            "client": {
                "name": "hello",
                "address": "192.168.1.1",
                "subscriptions": ["one", "two"],
                "timestamp": 127897
            }
        }"#).unwrap();
        let client = read_client(&event);
        match client {
            Ok(cl) => println!("Parsed: {:?}", cl),
            Err(e) => panic!("ERROR: {:?}", e)
        }
    }

    #[test]
    fn can_build_check() {
        let event = Json::from_str(r#"{
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "refresh": 1800,
                "handler": "default",
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#).unwrap();
        match read_check(&event) {
            Ok(check) => {
                println!("Parsed: {:?}", check);
                assert_eq!(check, Check {
                    name: "test-check".into(),
                    issued: 1416069607i64,
                    output: "we have output".into(),
                    status: 0,
                    command: "echo 'we have output'".into(),
                    subscribers: vec!("examples".into(),
                                      "tests".into()),
                    alert: None,
                    occurrences: None,
                    interval: 60,
                    refresh: 1800,
                    handler: Some("default".into()),
                    handlers: None,
                    history: vec!["0".into(); 3],
                    flapping: false,
                    additional: None });
            },
            Err(e) => panic!("ERROR: {:?}", e)
        }
    }

        #[test]
    fn can_build_check_with_alert() {
        let event = Json::from_str(r#"{
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "refresh": 1800,
                "alert": false,
                "occurrences": 5,
                "handler": "default",
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#).unwrap();
        match read_check(&event) {
            Ok(check) => {
                println!("Parsed: {:?}", check);
                assert_eq!(check, Check {
                    name: "test-check".into(),
                    issued: 1416069607i64,
                    output: "we have output".into(),
                    status: 0,
                    command: "echo 'we have output'".into(),
                    subscribers: vec!("examples".into(),
                                      "tests".into()),

                    alert: Some(false),
                    occurrences: Some(5),

                    refresh: 1800,
                    interval: 60,
                    handler: Some("default".into()),
                    handlers: None,
                    history: vec!["0".into(); 3],
                    flapping: false,
                    additional: None });
            },
            Err(e) => panic!("ERROR: {:?}", e)
        }
    }

    #[test]
    fn can_build_check_with_handlers() {
        let event = Json::from_str(r#"{
            "check": {
                "name": "test-check",
                "issued": 1416069607,
                "output": "we have output",
                "status": 0,
                "command": "echo 'we have output'",
                "subscribers": ["examples", "tests"],
                "interval": 60,
                "handlers": ["default", "pagerduty"],
                "history": ["0", "0", "0"],
                "flapping": false,
                "additional": null
            }
        }"#).unwrap();
        match read_check(&event) {
            Ok(cl) => println!("Parsed: {:?}", cl),
            Err(e) => panic!("ERROR: {:?}", e)
        }
    }
}
<|endoftext|>


<commit_before>// use std::cell::{Cell, RefCell};

use super::{Lexer, LexerState};
use super::Tokn;
use super::error::Error;
use ::util::*;

/*
 Lexer用の各種基本関数
*/
impl<'a> Lexer<'a> {
    pub fn new<I>(iter: &'a mut I) -> Lexer
    where I: Iterator<Item=u8> {
        let c = iter.next().unwrap();
        Lexer { iter: iter,
            current_char: c, state: LexerState::Normal,
            token_bytes: vec![], token: Err(Error::First), eof: false, }
    }

    pub fn finish_error(&mut self, e: Error) {
        self.finish(Err(e), LexerState::Normal);
    }

    pub fn advance(&mut self, c: u8, next: LexerState) {
        self.token_bytes.push(c);
        self.consume_char();
        self.state = next;
    }

    pub fn delimit(&mut self, c: u8, t: Tokn) {
        self.token_bytes.push(c);
        self.consume_char();
        self.finish(Ok(t), LexerState::Normal);
    }

    pub fn reset_token(&mut self) {
        self.token_bytes.clear();
        self.token = Err(
            Error::First);
    }

    pub fn finish(&mut
        self, tokn: Result<Tokn, Error>, next: LexerState) {
        self.token = tokn;
        self.state = next;
    }

    pub fn consume_char(&mut self) {
        if let Some(c) = self.iter.next() {
            self.current_char = c;
        } else {
            self.eof = true;
        }
    }

    pub fn get_token_string(&self) -> String {
        String::from_utf8(self.token_bytes.clone()).expect("Found invalid UTF-8")
    }

    pub fn is_first_otag_letter(&self, c: u8) -> bool {
        is_alphabetic_uppercase(c) || self.is_otag_sign(c)
    }

    pub fn is_dispatcher_sign(&self, c: u8) -> bool {
        c == b'|'
    }

    pub fn is_otag_sign(&self, c: u8) -> bool {
        c == b':'
        // 区切り文字ならここでNameを終わらせる必要がある
        // ただし、全ての区切り文字がここで判断されるわけではない
        // b'[' | b']' | b'(' | b')' | b'{' | b'}' | b':' | b',' => self.finish_with_state(state),
    }
}
<commit_msg>fix unnecessary new line<commit_after>// use std::cell::{Cell, RefCell};

use super::{Lexer, LexerState};
use super::Tokn;
use super::error::Error;
use ::util::*;

/*
 Lexer用の各種基本関数
*/
impl<'a> Lexer<'a> {
    pub fn new<I>(iter: &'a mut I) -> Lexer
    where I: Iterator<Item=u8> {
        let c = iter.next().unwrap();
        Lexer { iter: iter,
            current_char: c, state: LexerState::Normal,
            token_bytes: vec![], token: Err(Error::First), eof: false, }
    }

    pub fn finish_error(&mut self, e: Error) {
        self.finish(Err(e), LexerState::Normal);
    }

    pub fn advance(&mut self, c: u8, next: LexerState) {
        self.token_bytes.push(c);
        self.consume_char();
        self.state = next;
    }

    pub fn delimit(&mut self, c: u8, t: Tokn) {
        self.token_bytes.push(c);
        self.consume_char();
        self.finish(Ok(t), LexerState::Normal);
    }

    pub fn reset_token(&mut self) {
        self.token_bytes.clear();
        self.token = Err(
            Error::First);
    }

    pub fn finish(&mut self, tokn: Result<Tokn, Error>, next: LexerState) {
        self.token = tokn;
        self.state = next;
    }

    pub fn consume_char(&mut self) {
        if let Some(c) = self.iter.next() {
            self.current_char = c;
        } else {
            self.eof = true;
        }
    }

    pub fn get_token_string(&self) -> String {
        String::from_utf8(self.token_bytes.clone()).expect("Found invalid UTF-8")
    }

    pub fn is_first_otag_letter(&self, c: u8) -> bool {
        is_alphabetic_uppercase(c) || self.is_otag_sign(c)
    }

    pub fn is_dispatcher_sign(&self, c: u8) -> bool {
        c == b'|'
    }

    pub fn is_otag_sign(&self, c: u8) -> bool {
        c == b':'
        // 区切り文字ならここでNameを終わらせる必要がある
        // ただし、全ての区切り文字がここで判断されるわけではない
        // b'[' | b']' | b'(' | b')' | b'{' | b'}' | b':' | b',' => self.finish_with_state(state),
    }
}
<|endoftext|>


<commit_before>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> =
        RwLock::new(HashMap::new());
}

#[derive(Eq, PartialEq, Clone)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for sym in self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Box<FnOnce() + Send + Sync>;

pub fn get(keys: KeyPress) -> Option<KeyEvent> {
    let mut val: Option<KeyEvent>;
    {
        let bindings = BINDINGS.read().unwrap();
        val = bindings.get(keys).cloned();
    }
    val
}

pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.set(value.0, value.1);
    }
}

pub fn register_keypress(press: KeyPress, func: KeyEvent) {

}
<commit_msg>Use Arc<T> in keybindings, code compiles<commit_after>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> =
        RwLock::new(HashMap::new());
}

#[derive(Eq, PartialEq, Clone)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<FnOnce() + Send + Sync>>;

pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<|endoftext|>