<commit_before>use clap::{AppSettings, Parser};
use std::fmt::{self, Display};
use std::path::PathBuf;
use std::str::FromStr;
use syn_select::Selector;

#[derive(Parser)]
#[clap(bin_name = "cargo", version, author)]
pub enum Opts {
    /// Show the result of macro expansion.
    #[clap(
        name = "expand",
        version,
        author,
        setting = AppSettings::DeriveDisplayOrder,
        dont_collapse_args_in_usage = true
    )]
    Expand(Args),
}

#[derive(Parser, Debug)]
pub struct Args {
    /// Space-separated list of features to activate
    #[clap(long, value_name = "FEATURES")]
    pub features: Option<String>,

    /// Activate all available features
    #[clap(long)]
    pub all_features: bool,

    /// Do not activate the `default` feature
    #[clap(long)]
    pub no_default_features: bool,

    /// Expand only this package's library
    #[clap(long)]
    pub lib: bool,

    /// Expand only the specified binary
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub bin: Option<Option<String>>,

    /// Expand only the specified example
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub example: Option<Option<String>>,

    /// Expand only the specified test target
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub test: Option<Option<String>>,

    /// Include tests when expanding the lib or bin
    #[clap(long)]
    pub tests: bool,

    /// Expand only the specified bench target
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub bench: Option<Option<String>>,

    /// Target triple which compiles will be for
    #[clap(long, value_name = "TARGET")]
    pub target: Option<String>,

    /// Directory for all generated artifacts
    #[clap(long, value_name = "DIRECTORY", parse(from_os_str))]
    pub target_dir: Option<PathBuf>,

    /// Path to Cargo.toml
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to expand
    #[clap(
        short,
        long,
        value_name = "SPEC",
        min_values = 0,
        multiple_values = false
    )]
    pub package: Option<Option<String>>,

    /// Build artifacts in release mode, with optimizations
    #[clap(long)]
    pub release: bool,

    /// Number of parallel jobs, defaults to # of CPUs
    #[clap(short, long, value_name = "N")]
    pub jobs: Option<u64>,

    /// Print command lines as they are executed
    #[clap(long)]
    pub verbose: bool,

    /// Coloring: auto, always, never
    #[clap(long, value_name = "WHEN")]
    pub color: Option<Coloring>,

    /// Require Cargo.lock and cache are up to date
    #[clap(long)]
    pub frozen: bool,

    /// Require Cargo.lock is up to date
    #[clap(long)]
    pub locked: bool,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Unstable (nightly-only) flags to Cargo
    #[clap(short = 'Z', value_name = "FLAG")]
    pub unstable_flags: Vec<String>,

    /// Do not attempt to run rustfmt
    #[clap(long)]
    pub ugly: bool,

    /// Select syntax highlighting theme
    #[clap(long, value_name = "NAME")]
    pub theme: Option<String>,

    /// Print available syntax highlighting theme names
    #[clap(long)]
    pub themes: bool,

    /// Local path to module or other named item to expand, e.g. os::unix::ffi
    #[clap(value_name = "ITEM", parse(try_from_str = parse_selector))]
    pub item: Option<Selector>,
}

#[derive(Debug, Clone, Copy)]
pub enum Coloring {
    Auto,
    Always,
    Never,
}

impl FromStr for Coloring {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name {
            "auto" => Ok(Coloring::Auto),
            "always" => Ok(Coloring::Always),
            "never" => Ok(Coloring::Never),
            other => Err(format!(
                "must be auto, always, or never, but found `{}`",
                other,
            )),
        }
    }
}

impl Display for Coloring {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Coloring::Auto => "auto",
            Coloring::Always => "always",
            Coloring::Never => "never",
        };
        formatter.write_str(name)
    }
}

fn parse_selector(s: &str) -> Result<Selector, <Selector as FromStr>::Err> {
    if s.starts_with("::") {
        s[2..].parse()
    } else {
        s.parse()
    }
}

#[test]
fn test_cli() {
    <Opts as clap::CommandFactory>::command().debug_assert();
}
<commit_msg>Suppress clap 3.2 deprecations<commit_after>// Clap 3.2 upgrade in https://github.com/dtolnay/cargo-expand/pull/146
// blocked on https://github.com/TedDriggs/syn-select/pull/9
#![allow(deprecated)]

use clap::{AppSettings, Parser};
use std::fmt::{self, Display};
use std::path::PathBuf;
use std::str::FromStr;
use syn_select::Selector;

#[derive(Parser)]
#[clap(bin_name = "cargo", version, author)]
pub enum Opts {
    /// Show the result of macro expansion.
    #[clap(
        name = "expand",
        version,
        author,
        setting = AppSettings::DeriveDisplayOrder,
        dont_collapse_args_in_usage = true
    )]
    Expand(Args),
}

#[derive(Parser, Debug)]
pub struct Args {
    /// Space-separated list of features to activate
    #[clap(long, value_name = "FEATURES")]
    pub features: Option<String>,

    /// Activate all available features
    #[clap(long)]
    pub all_features: bool,

    /// Do not activate the `default` feature
    #[clap(long)]
    pub no_default_features: bool,

    /// Expand only this package's library
    #[clap(long)]
    pub lib: bool,

    /// Expand only the specified binary
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub bin: Option<Option<String>>,

    /// Expand only the specified example
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub example: Option<Option<String>>,

    /// Expand only the specified test target
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub test: Option<Option<String>>,

    /// Include tests when expanding the lib or bin
    #[clap(long)]
    pub tests: bool,

    /// Expand only the specified bench target
    #[clap(long, value_name = "NAME", min_values = 0, multiple_values = false)]
    pub bench: Option<Option<String>>,

    /// Target triple which compiles will be for
    #[clap(long, value_name = "TARGET")]
    pub target: Option<String>,

    /// Directory for all generated artifacts
    #[clap(long, value_name = "DIRECTORY", parse(from_os_str))]
    pub target_dir: Option<PathBuf>,

    /// Path to Cargo.toml
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    pub manifest_path: Option<PathBuf>,

    /// Package to expand
    #[clap(
        short,
        long,
        value_name = "SPEC",
        min_values = 0,
        multiple_values = false
    )]
    pub package: Option<Option<String>>,

    /// Build artifacts in release mode, with optimizations
    #[clap(long)]
    pub release: bool,

    /// Number of parallel jobs, defaults to # of CPUs
    #[clap(short, long, value_name = "N")]
    pub jobs: Option<u64>,

    /// Print command lines as they are executed
    #[clap(long)]
    pub verbose: bool,

    /// Coloring: auto, always, never
    #[clap(long, value_name = "WHEN")]
    pub color: Option<Coloring>,

    /// Require Cargo.lock and cache are up to date
    #[clap(long)]
    pub frozen: bool,

    /// Require Cargo.lock is up to date
    #[clap(long)]
    pub locked: bool,

    /// Run without accessing the network
    #[clap(long)]
    pub offline: bool,

    /// Unstable (nightly-only) flags to Cargo
    #[clap(short = 'Z', value_name = "FLAG")]
    pub unstable_flags: Vec<String>,

    /// Do not attempt to run rustfmt
    #[clap(long)]
    pub ugly: bool,

    /// Select syntax highlighting theme
    #[clap(long, value_name = "NAME")]
    pub theme: Option<String>,

    /// Print available syntax highlighting theme names
    #[clap(long)]
    pub themes: bool,

    /// Local path to module or other named item to expand, e.g. os::unix::ffi
    #[clap(value_name = "ITEM", parse(try_from_str = parse_selector))]
    pub item: Option<Selector>,
}

#[derive(Debug, Clone, Copy)]
pub enum Coloring {
    Auto,
    Always,
    Never,
}

impl FromStr for Coloring {
    type Err = String;

    fn from_str(name: &str) -> Result<Self, Self::Err> {
        match name {
            "auto" => Ok(Coloring::Auto),
            "always" => Ok(Coloring::Always),
            "never" => Ok(Coloring::Never),
            other => Err(format!(
                "must be auto, always, or never, but found `{}`",
                other,
            )),
        }
    }
}

impl Display for Coloring {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Coloring::Auto => "auto",
            Coloring::Always => "always",
            Coloring::Never => "never",
        };
        formatter.write_str(name)
    }
}

fn parse_selector(s: &str) -> Result<Selector, <Selector as FromStr>::Err> {
    if s.starts_with("::") {
        s[2..].parse()
    } else {
        s.parse()
    }
}

#[test]
fn test_cli() {
    <Opts as clap::CommandFactory>::command().debug_assert();
}
<|endoftext|>


<commit_before>extern crate libc;

use std::mem;
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
use std::fs::File;
use std::process::Stdio;

#[derive(Debug)]
pub struct Handle {
    // The struct *owns* this file descriptor, and will close it in drop().
    fd: RawFd,
}

impl Handle {
    // TODO: Is giving unlocked access to the standard descriptors unsafe?
    pub fn stdin() -> Handle {
        dup_or_panic(libc::STDIN_FILENO)
    }

    pub fn stdout() -> Handle {
        dup_or_panic(libc::STDOUT_FILENO)
    }

    pub fn stderr() -> Handle {
        dup_or_panic(libc::STDERR_FILENO)
    }

    pub fn from_file(file: File) -> Handle {
        unsafe { Handle::from_raw_fd(file.into_raw_fd()) }
    }

    pub fn to_file(self) -> File {
        unsafe { File::from_raw_fd(self.into_raw_fd()) }
    }

    pub fn to_stdio(self) -> Stdio {
        unsafe { Stdio::from_raw_fd(self.into_raw_fd()) }
    }
}

impl Clone for Handle {
    fn clone(&self) -> Self {
        dup_or_panic(self.fd)
    }
}

impl FromRawFd for Handle {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        Handle { fd: fd }
    }
}

impl IntoRawFd for Handle {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);  // prevent drop() from closing the fd
        fd
    }
}

impl Drop for Handle {
    fn drop(&mut self) {
        let error = unsafe { libc::close(self.fd) };
        assert_eq!(error, 0);
    }
}

// (read, write)
// TODO: error handling
pub fn open_pipe() -> (Handle, Handle) {
    unsafe {
        let mut pipes = [0, 0];
        let error = libc::pipe(pipes.as_mut_ptr());
        assert_eq!(error, 0);
        // prevent child processes from inheriting these by default
        for fd in &pipes {
            let ret = libc::ioctl(*fd, libc::FIOCLEX);
            assert_eq!(ret, 0);
        }
        (Handle::from_raw_fd(pipes[0]), Handle::from_raw_fd(pipes[1]))
    }
}

fn dup_or_panic(fd: RawFd) -> Handle {
    unsafe {
        let new_fd = libc::dup(fd);
        assert!(new_fd >= 0, "dup() returned an error");
        FromRawFd::from_raw_fd(new_fd)
    }
}

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

    #[test]
    fn it_works() {
        let (r, w) = open_pipe();
        let mut r_file = r.clone().to_file();
        let mut w_file = w.clone().to_file();
        drop(w);
        w_file.write_all(b"some stuff").unwrap();
        drop(w_file);
        let mut output = Vec::new();
        r_file.read_to_end(&mut output).unwrap();
    }
}
<commit_msg>s/it_works/test_pipes/<commit_after>extern crate libc;

use std::mem;
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
use std::fs::File;
use std::process::Stdio;

#[derive(Debug)]
pub struct Handle {
    // The struct *owns* this file descriptor, and will close it in drop().
    fd: RawFd,
}

impl Handle {
    // TODO: Is giving unlocked access to the standard descriptors unsafe?
    pub fn stdin() -> Handle {
        dup_or_panic(libc::STDIN_FILENO)
    }

    pub fn stdout() -> Handle {
        dup_or_panic(libc::STDOUT_FILENO)
    }

    pub fn stderr() -> Handle {
        dup_or_panic(libc::STDERR_FILENO)
    }

    pub fn from_file(file: File) -> Handle {
        unsafe { Handle::from_raw_fd(file.into_raw_fd()) }
    }

    pub fn to_file(self) -> File {
        unsafe { File::from_raw_fd(self.into_raw_fd()) }
    }

    pub fn to_stdio(self) -> Stdio {
        unsafe { Stdio::from_raw_fd(self.into_raw_fd()) }
    }
}

impl Clone for Handle {
    fn clone(&self) -> Self {
        dup_or_panic(self.fd)
    }
}

impl FromRawFd for Handle {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        Handle { fd: fd }
    }
}

impl IntoRawFd for Handle {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);  // prevent drop() from closing the fd
        fd
    }
}

impl Drop for Handle {
    fn drop(&mut self) {
        let error = unsafe { libc::close(self.fd) };
        assert_eq!(error, 0);
    }
}

// (read, write)
// TODO: error handling
pub fn open_pipe() -> (Handle, Handle) {
    unsafe {
        let mut pipes = [0, 0];
        let error = libc::pipe(pipes.as_mut_ptr());
        assert_eq!(error, 0);
        // prevent child processes from inheriting these by default
        for fd in &pipes {
            let ret = libc::ioctl(*fd, libc::FIOCLEX);
            assert_eq!(ret, 0);
        }
        (Handle::from_raw_fd(pipes[0]), Handle::from_raw_fd(pipes[1]))
    }
}

fn dup_or_panic(fd: RawFd) -> Handle {
    unsafe {
        let new_fd = libc::dup(fd);
        assert!(new_fd >= 0, "dup() returned an error");
        FromRawFd::from_raw_fd(new_fd)
    }
}

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

    #[test]
    fn test_pipes() {
        let (r, w) = open_pipe();
        let mut r_file = r.clone().to_file();
        let mut w_file = w.clone().to_file();
        drop(w);
        w_file.write_all(b"some stuff").unwrap();
        drop(w_file);
        let mut output = Vec::new();
        r_file.read_to_end(&mut output).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Implements polynomial operations in GF(2^8).

use std::rand;

use gf256::*;

/// Evaluate a polynomial, returning the Y value for the given X value.
pub fn eval(p: &Vec<u8>, x: u8) -> u8 {
    p.iter().rev().fold(0u8, |res, &v| mul(res, x) ^ v)
}

/// Generates a random polynomial of the Nth degree with an X-intercept with the
/// given value.
pub fn generate<T: rand::Rng>(n: u8, x: u8, rng: &mut T) -> Vec<u8> {
    // Generate a random polynomial.
    let mut p: Vec<u8> = rng.gen_iter().take(n as usize).collect();

    // Set its X-intercept to the given value.
    p[0] = x;

    // Ensure the Nth coefficient is non-zero, otherwise it's an (N-1)th-degree
    // polynomial.
    p[n as usize - 1] = rng.gen_range(1, 255);

    p
}

/// Interpolates a vector of (X, Y) points, returning the Y value for the given
/// X value.
pub fn interpolate<'a>(points: &'a Vec<(u8, u8)>, x: u8) -> u8 {
    let mut value = 0u8;
    for (i, &(ax, ay)) in points.iter().enumerate() {
        let mut weight = 1u8;
        for (j, &(bx, _)) in points.iter().enumerate() {
            if i != j {
                let top = x ^ bx;
                let bottom = ax ^ bx;
                let factor = div(top, bottom);
                weight = mul(weight, factor);
            }
        }
        value ^= mul(weight, ay)
    }
    value
}

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

    #[test]
    fn test_eval() {
        assert_eq!(eval(&vec![1, 0, 2, 3], 2), 17);
    }

    #[test]
    fn test_generate() {
        let mut rng = rand::ChaChaRng::new_unseeded();
        assert_eq!(generate(5, 50, &mut rng),
                   vec![50, 160, 64, 83, 161])
    }

    #[test]
    fn test_interpolate() {
        assert_eq!(interpolate(&vec![(1,1), (2,2), (3,3)], 0), 0);
    }
}
<commit_msg>I miss gofmt.<commit_after>//! Implements polynomial operations in GF(2^8).

use std::rand;

use gf256::*;

/// Evaluate a polynomial, returning the Y value for the given X value.
pub fn eval(p: &Vec<u8>, x: u8) -> u8 {
    p.iter().rev().fold(0u8, |res, &v| mul(res, x) ^ v)
}

/// Generates a random polynomial of the Nth degree with an X-intercept with the
/// given value.
pub fn generate<T: rand::Rng>(n: u8, x: u8, rng: &mut T) -> Vec<u8> {
    // Generate a random polynomial.
    let mut p: Vec<u8> = rng.gen_iter().take(n as usize).collect();

    // Set its X-intercept to the given value.
    p[0] = x;

    // Ensure the Nth coefficient is non-zero, otherwise it's an (N-1)th-degree
    // polynomial.
    p[n as usize - 1] = rng.gen_range(1, 255);

    p
}

/// Interpolates a vector of (X, Y) points, returning the Y value for the given
/// X value.
pub fn interpolate<'a>(points: &'a Vec<(u8, u8)>, x: u8) -> u8 {
    let mut value = 0u8;
    for (i, &(ax, ay)) in points.iter().enumerate() {
        let mut weight = 1u8;
        for (j, &(bx, _)) in points.iter().enumerate() {
            if i != j {
                let top = x ^ bx;
                let bottom = ax ^ bx;
                let factor = div(top, bottom);
                weight = mul(weight, factor);
            }
        }
        value ^= mul(weight, ay)
    }
    value
}

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

    #[test]
    fn test_eval() {
        assert_eq!(eval(&vec![1, 0, 2, 3], 2), 17);
    }

    #[test]
    fn test_generate() {
        let mut rng = rand::ChaChaRng::new_unseeded();
        assert_eq!(generate(5, 50, &mut rng),
                   vec![50, 160, 64, 83, 161])
    }

    #[test]
    fn test_interpolate() {
        assert_eq!(interpolate(&vec![(1,1), (2,2), (3,3)], 0), 0);
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::WidgetSignals;
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    w.1.refresh();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);
    let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    let mut kill_button = gtk::Button::new_with_label("End task").unwrap();

    kill_button.set_sensitive(false);
    timeout::add(1500, update_window, &mut (&mut list_store, &mut sys));

    vertical_layout.add(&scroll);
    vertical_layout.add(&kill_button);
    window.add(&vertical_layout);
    window.show_all();
    gtk::main();
}
<commit_msg>Advancement<commit_after>#![crate_type = "bin"]
#![feature(collections)]

extern crate gtk;
extern crate glib;
extern crate sysinfo;

use gtk::{WindowTrait, ContainerTrait, WidgetTrait};
use glib::{Type, timeout};
use sysinfo::*;
use gtk::signal::Inhibit;
use gtk::signal::{WidgetSignals, TreeViewSignals};
use std::collections::VecMap;
use std::str::FromStr;

fn append_column(title: &str, v: &mut Vec<gtk::TreeViewColumn>) {
    let l = v.len();
    let renderer = gtk::CellRendererText::new().unwrap();

    v.push(gtk::TreeViewColumn::new().unwrap());
    let tmp = v.get_mut(l).unwrap();

    tmp.set_title(title);
    tmp.pack_start(&renderer, true);
    tmp.add_attribute(&renderer, "text", l as i32);
}

fn create_and_fill_model(list_store: &mut gtk::ListStore, pid: i64, name: &str, cpu: f32, memory: u64) {
    if name.len() < 1 {
        return;
    }
    let mut top_level = gtk::TreeIter::new();

    list_store.append(&mut top_level);
    list_store.set_string(&top_level, 0, &format!("{}", pid));
    list_store.set_string(&top_level, 1, name);
    list_store.set_string(&top_level, 2, &format!("{}", cpu));
    list_store.set_string(&top_level, 3, &format!("{}", memory));
}

fn update_window(w: &mut (&mut gtk::ListStore, &mut sysinfo::System)) -> i32 {
    let mut model = w.0.get_model().unwrap();
    let mut iter = gtk::TreeIter::new();

    w.1.refresh();
    let mut entries : VecMap<Processus> = (*w.1.get_processus_list()).clone();
    let mut nb = model.iter_n_children(None);
    let mut i = 0;

    while i < nb {
        if model.iter_nth_child(&mut iter, None, i) {
            let pid : i64 = i64::from_str(&model.get_value(&iter, 0).get_string().unwrap()).unwrap();
            let mut to_delete = false;

            match entries.get(&(pid as usize)) {
                Some(p) => {
                    //w.0.set_string(&iter, 1, &p.name);
                    w.0.set_string(&iter, 2, &format!("{}", p.cpu_usage));
                    w.0.set_string(&iter, 3, &format!("{}", p.memory));
                    to_delete = true;
                }
                None => {
                    w.0.remove(&iter);
                }
            }
            if to_delete {
                entries.remove(&(pid as usize));
                nb = model.iter_n_children(None);
                i += 1;
            }
        } else {
            i += 1;
        }
    }
    for (_, pro) in entries {
        create_and_fill_model(&mut w.0, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }
    1
}

fn main() {
    gtk::init();

    let mut window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();
    let mut sys = sysinfo::System::new();

    window.set_title("Processus viewer");
    window.set_window_position(gtk::WindowPosition::Center);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut left_tree = gtk::TreeView::new().unwrap();
    let mut scroll = gtk::ScrolledWindow::new(None, None).unwrap();
    let mut current_pid : Option<String> = None;

    scroll.set_min_content_height(800);
    scroll.set_min_content_width(600);

    let mut columns : Vec<gtk::TreeViewColumn> = Vec::new();

    append_column("pid", &mut columns);
    append_column("process name", &mut columns);
    append_column("cpu usage", &mut columns);
    append_column("memory usage", &mut columns);

    for i in columns {
        left_tree.append_column(&i);
    }

    let mut list_store = gtk::ListStore::new(&[Type::String, Type::String, Type::String, Type::String]).unwrap();
    sys.refresh();
    for (_, pro) in sys.get_processus_list() {
        create_and_fill_model(&mut list_store, pro.pid, &pro.name, pro.cpu_usage, pro.memory);
    }

    left_tree.set_model(&list_store.get_model().unwrap());
    left_tree.set_headers_visible(true);
    scroll.add(&left_tree);
    let mut vertical_layout = gtk::Box::new(gtk::Orientation::Vertical, 0).unwrap();
    let mut kill_button = gtk::Button::new_with_label("End task").unwrap();

    left_tree.connect_cursor_changed(|tree_view| {
        /*let mut path = gtk::TreePath::new().unwrap();
        tree_view.get_cursor(Some(&mut path), None);
        let mut iter = gtk::TreeIter::new();
        let model = tree_view.get_model().unwrap();

        if model.get_iter(&mut iter, &path) {
            current_pid = Some(model.get_value(&iter, 0).get_string().unwrap());
        }*/
        println!("current pid : {:?}", current_pid);
    });
    kill_button.set_sensitive(false);
    timeout::add(1500, update_window, &mut (&mut list_store, &mut sys));

    vertical_layout.add(&scroll);
    vertical_layout.add(&kill_button);
    window.add(&vertical_layout);
    window.show_all();
    gtk::main();
}
<|endoftext|>


<commit_before>//! # Sink module.
//!
//! The Sink module send metrics to Warp10.
use std::thread;
use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use time;
use std::cmp;
use std::io::prelude::*;
use std::fs;
use std::fs::File;
use std::error::Error;
use std::ffi::OsStr;
use std::path::PathBuf;
use hyper;

use config;

/// Thread sleeping time.
const REST_TIME: u64 = 10;

/// Sink loop.
pub fn sink(sink: &config::Sink, parameters: &config::Parameters, sigint: Arc<AtomicBool>) {
    loop {
        let start = time::now_utc();

        match send(sink, parameters) {
            Err(err) => error!("post fail: {}", err),
            Ok(_) => info!("post success"),
        }

        let elapsed = (time::now_utc() - start).num_milliseconds() as u64;
        let sleep_time = if elapsed > parameters.scan_period {
            REST_TIME
        } else {
            cmp::max(parameters.scan_period - elapsed, REST_TIME)
        };
        for _ in 0..sleep_time / REST_TIME {
            thread::sleep(Duration::from_millis(REST_TIME));
            if sigint.load(Ordering::Relaxed) {
                return;
            }
        }
    }
}

/// Send send sink metrics to Warp10.
fn send(sink: &config::Sink, parameters: &config::Parameters) -> Result<(), Box<Error>> {
    debug!("post {}", &sink.url);
    loop {
        let entries = try!(fs::read_dir(&parameters.sink_dir));
        let mut files = Vec::with_capacity(parameters.batch_count as usize);
        let mut metrics = String::new();

        // Load metrics
        let mut batch_size = 0;
        for (i, entry) in entries.enumerate() {
            let entry = try!(entry);
            let file_name = String::from(entry.file_name().to_str().unwrap_or(""));
            // Look only for metrics files of the sink
            if entry.path().extension() != Some(OsStr::new("metrics")) ||
               !file_name.starts_with(&sink.name) {
                continue;
            }

            // Split metrics in capped batch
            if i > parameters.batch_count as usize || batch_size > parameters.batch_size as usize {
                break;
            }

            debug!("open sink file {}", format!("{:?}", entry.path()));
            let file = match read(entry.path()) {
                Err(_) => continue,
                Ok(v) => v,
            };

            files.push(entry.path());
            batch_size += file.len();
            metrics.push_str(&file);
            metrics.push_str("\n");
        }

        // Nothing to do
        if metrics.len() == 0 {
            break;
        }

        // Send metrics
        let client = hyper::Client::new();
        let mut headers = hyper::header::Headers::new();
        headers.set_raw(sink.token_header.clone(), vec![sink.token.clone().into()]);

        debug!("post metrics");
        let request = client.post(&sink.url).headers(headers).body(&metrics);
        let res = try!(request.send());
        if !res.status.is_success() {
            return Err(From::from("non 200 received"));
        }

        // Delete sended data
        for f in files {
            debug!("delete sink file {}", format!("{:?}", f));
            try!(fs::remove_file(f));
        }
    }

    Ok(())
}

/// Read a file as String.
fn read(path: PathBuf) -> Result<String, Box<Error>> {
    let mut file = try!(File::open(path));

    let mut content = String::new();
    try!(file.read_to_string(&mut content));

    Ok(content)
}
<commit_msg>feat(sinks) log sinks response<commit_after>//! # Sink module.
//!
//! The Sink module send metrics to Warp10.
use std::thread;
use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use time;
use std::cmp;
use std::io::prelude::*;
use std::fs;
use std::fs::File;
use std::error::Error;
use std::ffi::OsStr;
use std::path::PathBuf;
use hyper;

use config;

/// Thread sleeping time.
const REST_TIME: u64 = 10;

/// Sink loop.
pub fn sink(sink: &config::Sink, parameters: &config::Parameters, sigint: Arc<AtomicBool>) {
    loop {
        let start = time::now_utc();

        match send(sink, parameters) {
            Err(err) => error!("post fail: {}", err),
            Ok(_) => info!("post success"),
        }

        let elapsed = (time::now_utc() - start).num_milliseconds() as u64;
        let sleep_time = if elapsed > parameters.scan_period {
            REST_TIME
        } else {
            cmp::max(parameters.scan_period - elapsed, REST_TIME)
        };
        for _ in 0..sleep_time / REST_TIME {
            thread::sleep(Duration::from_millis(REST_TIME));
            if sigint.load(Ordering::Relaxed) {
                return;
            }
        }
    }
}

/// Send send sink metrics to Warp10.
fn send(sink: &config::Sink, parameters: &config::Parameters) -> Result<(), Box<Error>> {
    debug!("post {}", &sink.url);
    loop {
        let entries = try!(fs::read_dir(&parameters.sink_dir));
        let mut files = Vec::with_capacity(parameters.batch_count as usize);
        let mut metrics = String::new();

        // Load metrics
        let mut batch_size = 0;
        for (i, entry) in entries.enumerate() {
            let entry = try!(entry);
            let file_name = String::from(entry.file_name().to_str().unwrap_or(""));
            // Look only for metrics files of the sink
            if entry.path().extension() != Some(OsStr::new("metrics")) ||
               !file_name.starts_with(&sink.name) {
                continue;
            }

            // Split metrics in capped batch
            if i > parameters.batch_count as usize || batch_size > parameters.batch_size as usize {
                break;
            }

            debug!("open sink file {}", format!("{:?}", entry.path()));
            let file = match read(entry.path()) {
                Err(_) => continue,
                Ok(v) => v,
            };

            files.push(entry.path());
            batch_size += file.len();
            metrics.push_str(&file);
            metrics.push_str("\n");
        }

        // Nothing to do
        if metrics.len() == 0 {
            break;
        }

        // Send metrics
        let client = hyper::Client::new();
        let mut headers = hyper::header::Headers::new();
        headers.set_raw(sink.token_header.clone(), vec![sink.token.clone().into()]);

        debug!("post metrics");
        let request = client.post(&sink.url).headers(headers).body(&metrics);
        let mut res = try!(request.send());
        if !res.status.is_success() {
            let mut body = String::new();
            try!(res.read_to_string(&mut body));
            debug!("data {}", &body);

            return Err(From::from("non 200 received"));
        }

        // Delete sended data
        for f in files {
            debug!("delete sink file {}", format!("{:?}", f));
            try!(fs::remove_file(f));
        }
    }

    Ok(())
}

/// Read a file as String.
fn read(path: PathBuf) -> Result<String, Box<Error>> {
    let mut file = try!(File::open(path));

    let mut content = String::new();
    try!(file.read_to_string(&mut content));

    Ok(content)
}
<|endoftext|>


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

//!
//! # Regular language
//!
//! This provides a data structure, `Pattern<Symbol>` representing a regular language. This is a more generalised form
//! of a regular expression (it supports symbol types other than simple strings). A pattern using the `char` symbol
//! forms a simple regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..10);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters.
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<commit_msg>Add derive(Debug) to Pattern<Symbol><commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure, `Pattern<Symbol>` representing a regular language. This is a more generalised form
//! of a regular expression (it supports symbol types other than simple strings). A pattern using the `char` symbol
//! forms a simple regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters.
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<|endoftext|>


<commit_before>use cairo::{Context, Surface};
use pango::{FontDescription, Layout, LayoutExt};
use pangocairo::CairoContextExt;

#[derive(Clone, Debug)]
pub struct Color {
    red: f64,
    green: f64,
    blue: f64,
}

macro_rules! color {
    ($name:ident, ($r:expr, $g:expr, $b:expr)) => {
        #[allow(dead_code)]
        pub fn $name() -> Color {
            Color {
                red: $r, green: $g, blue: $b,
            }
        }
    }
}

impl Color {
    color!(red, (1.0, 0.0, 0.0));
    color!(green, (0.0, 1.0, 0.0));
    color!(blue, (0.0, 0.0, 1.0));
    color!(white, (1.0, 1.0, 1.0));
    color!(black, (0.0, 0.0, 0.0));

    pub fn apply_to_context(&self, cr: &Context) {
        cr.set_source_rgb(self.red, self.green, self.blue);
    }
}

#[derive(Clone, Debug)]
pub struct Padding {
    left: f64,
    right: f64,
    top: f64,
    bottom: f64,
}

impl Padding {
    pub fn new(left: f64, right: f64, top: f64, bottom: f64) -> Padding {
        Padding {
            left,
            right,
            top,
            bottom,
        }
    }
}

#[derive(Clone)]
pub struct Attributes {
    pub font: FontDescription,
    pub fg_color: Color,
    pub bg_color: Option<Color>,
    pub padding: Padding,
}

impl Attributes {
    #[allow(dead_code)]
    pub fn with_font(&self, font: FontDescription) -> Attributes {
        let mut new = self.clone();
        new.font = font;
        new
    }

    #[allow(dead_code)]
    pub fn with_fg_color(&self, fg_color: Color) -> Attributes {
        let mut new = self.clone();
        new.fg_color = fg_color;
        new
    }

    #[allow(dead_code)]
    pub fn with_bg_color(&self, bg_color: Option<Color>) -> Attributes {
        let mut new = self.clone();
        new.bg_color = bg_color;
        new
    }

    #[allow(dead_code)]
    pub fn with_padding(&self, padding: Padding) -> Attributes {
        let mut new = self.clone();
        new.padding = padding;
        new
    }
}

#[derive(Clone)]
pub struct Text {
    pub attr: Attributes,
    pub text: String,
    pub stretch: bool,
}

impl Text {
    pub fn layout(self, surface: &Surface) -> TextLayout {
        let context = Context::new(&surface);

        let layout = context.create_pango_layout();
        layout.set_text(&self.text, self.text.len() as i32);
        layout.set_font_description(Some(&self.attr.font));

        TextLayout {
            attr: self.attr.clone(),
            stretch: self.stretch,
            width: None,
            height: None,
            context: context,
            layout: layout,
        }
    }
}

pub struct TextLayout {
    attr: Attributes,
    stretch: bool,
    width: Option<f64>,
    height: Option<f64>,
    context: Context,
    layout: Layout,
}

impl TextLayout {
    pub fn width(&self) -> f64 {
        self.width
            .unwrap_or_else(|| {
                                let text_width = self.layout.get_pixel_size().0 as f64;
                                text_width + self.attr.padding.left + self.attr.padding.right
                            })
    }

    pub fn height(&self) -> f64 {
        self.height
            .unwrap_or_else(|| {
                                let text_height = self.layout.get_pixel_size().1 as f64;
                                text_height + self.attr.padding.top + self.attr.padding.bottom
                            })
    }

    pub fn set_width(&mut self, width: f64) {
        self.width = Some(width);
    }

    pub fn set_height(&mut self, height: f64) {
        self.height = Some(height);
    }

    pub fn stretch(&self) -> bool {
        self.stretch
    }

    pub fn render(&self, x: f64, y: f64) {
        self.context.save();
        self.context.translate(x, y + self.attr.padding.top);

        if let Some(ref bg_color) = self.attr.bg_color {
            bg_color.apply_to_context(&self.context);
            // FIXME: The use of `height` isnt' right here: we want to do the
            // full height of the bar, not the full height of the text. It
            // would be useful if we could do Surface.get_height(), but that
            // doesn't seem to be available in cairo-rs for some reason?
            self.context
                .rectangle(0.0, 0.0, self.width(), self.height());
            self.context.fill();
        }

        self.attr.fg_color.apply_to_context(&self.context);
        self.context
            .translate(self.attr.padding.left, self.attr.padding.top);
        self.context.show_pango_layout(&self.layout);

        self.context.restore();
    }
}
<commit_msg>Remove some unused code.<commit_after>use cairo::{Context, Surface};
use pango::{FontDescription, Layout, LayoutExt};
use pangocairo::CairoContextExt;

#[derive(Clone, Debug)]
pub struct Color {
    red: f64,
    green: f64,
    blue: f64,
}

macro_rules! color {
    ($name:ident, ($r:expr, $g:expr, $b:expr)) => {
        #[allow(dead_code)]
        pub fn $name() -> Color {
            Color {
                red: $r, green: $g, blue: $b,
            }
        }
    }
}

impl Color {
    color!(red, (1.0, 0.0, 0.0));
    color!(green, (0.0, 1.0, 0.0));
    color!(blue, (0.0, 0.0, 1.0));
    color!(white, (1.0, 1.0, 1.0));
    color!(black, (0.0, 0.0, 0.0));

    pub fn apply_to_context(&self, cr: &Context) {
        cr.set_source_rgb(self.red, self.green, self.blue);
    }
}

#[derive(Clone, Debug)]
pub struct Padding {
    left: f64,
    right: f64,
    top: f64,
    bottom: f64,
}

impl Padding {
    pub fn new(left: f64, right: f64, top: f64, bottom: f64) -> Padding {
        Padding {
            left,
            right,
            top,
            bottom,
        }
    }
}

#[derive(Clone)]
pub struct Attributes {
    pub font: FontDescription,
    pub fg_color: Color,
    pub bg_color: Option<Color>,
    pub padding: Padding,
}

impl Attributes {
    #[allow(dead_code)]
    pub fn with_font(&self, font: FontDescription) -> Attributes {
        let mut new = self.clone();
        new.font = font;
        new
    }

    #[allow(dead_code)]
    pub fn with_fg_color(&self, fg_color: Color) -> Attributes {
        let mut new = self.clone();
        new.fg_color = fg_color;
        new
    }

    #[allow(dead_code)]
    pub fn with_bg_color(&self, bg_color: Option<Color>) -> Attributes {
        let mut new = self.clone();
        new.bg_color = bg_color;
        new
    }

    #[allow(dead_code)]
    pub fn with_padding(&self, padding: Padding) -> Attributes {
        let mut new = self.clone();
        new.padding = padding;
        new
    }
}

#[derive(Clone)]
pub struct Text {
    pub attr: Attributes,
    pub text: String,
    pub stretch: bool,
}

impl Text {
    pub fn layout(self, surface: &Surface) -> TextLayout {
        let context = Context::new(&surface);

        let layout = context.create_pango_layout();
        layout.set_text(&self.text, self.text.len() as i32);
        layout.set_font_description(Some(&self.attr.font));

        TextLayout {
            attr: self.attr.clone(),
            stretch: self.stretch,
            width: None,
            context: context,
            layout: layout,
        }
    }
}

pub struct TextLayout {
    attr: Attributes,
    stretch: bool,
    width: Option<f64>,
    context: Context,
    layout: Layout,
}

impl TextLayout {
    pub fn width(&self) -> f64 {
        self.width
            .unwrap_or_else(|| {
                                let text_width = self.layout.get_pixel_size().0 as f64;
                                text_width + self.attr.padding.left + self.attr.padding.right
                            })
    }

    pub fn height(&self) -> f64 {
        let text_height = self.layout.get_pixel_size().1 as f64;
        text_height + self.attr.padding.top + self.attr.padding.bottom
    }

    pub fn set_width(&mut self, width: f64) {
        self.width = Some(width);
    }

    pub fn stretch(&self) -> bool {
        self.stretch
    }

    pub fn render(&self, x: f64, y: f64) {
        self.context.save();
        self.context.translate(x, y + self.attr.padding.top);

        if let Some(ref bg_color) = self.attr.bg_color {
            bg_color.apply_to_context(&self.context);
            // FIXME: The use of `height` isnt' right here: we want to do the
            // full height of the bar, not the full height of the text. It
            // would be useful if we could do Surface.get_height(), but that
            // doesn't seem to be available in cairo-rs for some reason?
            self.context
                .rectangle(0.0, 0.0, self.width(), self.height());
            self.context.fill();
        }

        self.attr.fg_color.apply_to_context(&self.context);
        self.context
            .translate(self.attr.padding.left, self.attr.padding.top);
        self.context.show_pango_layout(&self.layout);

        self.context.restore();
    }
}
<|endoftext|>


<commit_before>use std::error::{Error, FromError};
use std::fmt::{self, Display, Formatter};
use std::old_io::IoError;
use std::old_io::net::ip::IpAddr;

use hyper::client::Client;
use hyper::header::Headers;
use hyper::HttpError;

// Content of the request.
const EXTERNAL_IP_REQUEST: &'static str =
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <SOAP-ENV:Body>
        <m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        </m:GetExternalIPAddress>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>";

// Content of the SOAPAction header.
const SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"";

// Errors
pub enum RequestError {
    HttpError(HttpError),
    InvalidResponse,
    IoError(IoError),
}

impl Display for RequestError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            RequestError::HttpError(ref err) => err.fmt(f),
            RequestError::InvalidResponse => write!(f, "Invalid response received from router."), // TODO const
            RequestError::IoError(ref err) => err.fmt(f),
        }
    }
}

impl FromError<IoError> for RequestError {
    fn from_error(err: IoError) -> RequestError {
        RequestError::IoError(err)
    }
}

impl FromError<HttpError> for RequestError {
    fn from_error(err: HttpError) -> RequestError {
        RequestError::HttpError(err)
    }
}

impl Error for RequestError {
    fn description(&self) -> &str {
        match *self {
            RequestError::HttpError(ref err) => err.description(),
            RequestError::InvalidResponse => "Invalid response received from router.", // TODO const
            RequestError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            RequestError::HttpError(ref err) => err.cause(),
            RequestError::InvalidResponse => None,
            RequestError::IoError(ref err) => err.cause(),
        }
    }
}

// Get the external IP address.
// TODO return IpAddr instead of String
pub fn get_external_ip(url: &str) -> Result<IpAddr, RequestError>  {
    let mut client = Client::new();

    let mut headers = Headers::new();
    headers.set_raw("SOAPAction", vec![String::from_str(SOAP_ACTION).into_bytes()]); // TODO clean-up

    let mut builder = client.post(url);
    builder = builder.headers(headers);
    builder = builder.body(EXTERNAL_IP_REQUEST);

    let mut res = try!(builder.send());
    let text = try!(res.read_to_string());
    extract_address(text)
}

// Extract the address from the text.
fn extract_address(text: String) -> Result<IpAddr, RequestError> {
    let re = regex!(r"<NewExternalIPAddress>(\d+\.\d+\.\d+\.\d+)</NewExternalIPAddress>");
    match re.captures(text.as_slice()) {
        None => Err(RequestError::InvalidResponse),
        Some(cap) => {
            match cap.at(1) {
                None => Err(RequestError::InvalidResponse),
                Some(ip) => Ok(ip.parse::<IpAddr>().unwrap()),
            }
        },
    }
}
<commit_msg>Fix and clean up things.<commit_after>use std::error::{Error, FromError};
use std::fmt::{self, Display, Formatter};
use std::old_io::IoError;
use std::old_io::net::ip::IpAddr;

use hyper::client::Client;
use hyper::header::Headers;
use hyper::HttpError;

// Content of the request.
const EXTERNAL_IP_REQUEST: &'static str =
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <SOAP-ENV:Body>
        <m:GetExternalIPAddress xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">
        </m:GetExternalIPAddress>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>";

// Content of the SOAPAction header.
const SOAP_ACTION: &'static str = "\"urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress\"";

// RequestError::InvalidResponse text.
const ERR_INVALID_RESPONSE: &'static str = "Invalid response received from router";

// Errors
pub enum RequestError {
    HttpError(HttpError),
    InvalidResponse,
    IoError(IoError),
}

impl Display for RequestError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            RequestError::HttpError(ref err) => err.fmt(f),
            RequestError::InvalidResponse => write!(f, ERR_INVALID_RESPONSE),
            RequestError::IoError(ref err) => err.fmt(f),
        }
    }
}

impl FromError<IoError> for RequestError {
    fn from_error(err: IoError) -> RequestError {
        RequestError::IoError(err)
    }
}

impl FromError<HttpError> for RequestError {
    fn from_error(err: HttpError) -> RequestError {
        RequestError::HttpError(err)
    }
}

impl Error for RequestError {
    fn description(&self) -> &str {
        match *self {
            RequestError::HttpError(ref err) => err.description(),
            RequestError::InvalidResponse => ERR_INVALID_RESPONSE,
            RequestError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            RequestError::HttpError(ref err) => err.cause(),
            RequestError::InvalidResponse => None,
            RequestError::IoError(ref err) => err.cause(),
        }
    }
}

// Get the external IP address.
pub fn get_external_ip(url: &str) -> Result<IpAddr, RequestError>  {
    let mut client = Client::new();

    let mut headers = Headers::new();
    headers.set_raw("SOAPAction", vec![String::from_str(SOAP_ACTION).into_bytes()]); // TODO clean-up

    let mut builder = client.post(url);
    builder = builder.headers(headers);
    builder = builder.body(EXTERNAL_IP_REQUEST);

    let mut res = try!(builder.send());
    let text = try!(res.read_to_string());
    extract_address(text)
}

// Extract the address from the text.
fn extract_address(text: String) -> Result<IpAddr, RequestError> {
    let re = regex!(r"<NewExternalIPAddress>(\d+\.\d+\.\d+\.\d+)</NewExternalIPAddress>");
    match re.captures(text.as_slice()) {
        None => Err(RequestError::InvalidResponse),
        Some(cap) => {
            match cap.at(1) {
                None => Err(RequestError::InvalidResponse),
                Some(ip) => Ok(ip.parse::<IpAddr>().unwrap()),
            }
        },
    }
}
<|endoftext|>


<commit_before>use screen::*;
use context::{Context, GameState};
use ui::{create_ui, Ui};
use piston_window::{self, PistonWindow};
use conrod::{Canvas, Button, Widget, Positionable, Sizeable, Labelable};
use conrod::color::{self, Colorable};

pub struct MainMenu {
    ui: Ui,
    state: Option<State>,
}

impl MainMenu {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        MainMenu {
            ui: create_ui(&window, &context.assets_path),
            state: None,
        }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenu {
    fn on_input(&mut self, _: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        self.ui.handle_event(window);
        let mut result = Vec::new();

        match self.state.take() {
            Some(State::NewGame) => {
                result.push(InputResult::PopScreen);

                if let GameState::NotStarted = context.game_state {
                    // Start new game.
                    result.push(InputResult::PushScreen(Box::new(Battle::new(&window, context))));
                    context.game_state = GameState::InProgress;
                }
            }
            Some(State::Options) => {
                result.push(InputResult::PushScreen(Box::new(Options::new(&window, context))));
            }
            Some(State::Exit) => {
                result.push(InputResult::Exit);
            }
            None => {}
        }

        result
    }

    fn on_draw(&mut self, _: &piston_window::RenderArgs, window: &PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, _: &piston_window::UpdateArgs) {
        let button_color = color::rgb(0.4, 0.75, 0.6);

        let state = &mut self.state;

        self.ui.set_widgets(|mut ui| {
            Canvas::new()
                .pad(30.)
                .color(color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .color(button_color)
                .label("New game")
                .react(|| *state = Some(State::NewGame))
                .set(NEW_GAME_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_GAME_BUTTON, 45.0)
                .color(button_color)
                .label("Options")
                .react(|| *state = Some(State::Options))
                .set(OPTIONS_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(OPTIONS_BUTTON, 45.0)
                .color(button_color)
                .label("Exit")
                .react(|| *state = Some(State::Exit))
                .set(EXIT_BUTTON, &mut ui);
        });
    }
}

widget_ids! {
    CANVAS,
    NEW_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}
<commit_msg>NEW_GAME_BUTTON -> NEW_OR_CONTINUE_GAME_BUTTON<commit_after>use screen::*;
use context::{Context, GameState};
use ui::{create_ui, Ui};
use piston_window::{self, PistonWindow};
use conrod::{Canvas, Button, Widget, Positionable, Sizeable, Labelable};
use conrod::color::{self, Colorable};

pub struct MainMenu {
    ui: Ui,
    state: Option<State>,
}

impl MainMenu {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        MainMenu {
            ui: create_ui(&window, &context.assets_path),
            state: None,
        }
    }
}

enum State {
    NewGame,
    Options,
    Exit,
}

impl Screen for MainMenu {
    fn on_input(&mut self, _: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        self.ui.handle_event(window);
        let mut result = Vec::new();

        match self.state.take() {
            Some(State::NewGame) => {
                result.push(InputResult::PopScreen);

                if let GameState::NotStarted = context.game_state {
                    // Start new game.
                    result.push(InputResult::PushScreen(Box::new(Battle::new(&window, context))));
                    context.game_state = GameState::InProgress;
                }
            }
            Some(State::Options) => {
                result.push(InputResult::PushScreen(Box::new(Options::new(&window, context))));
            }
            Some(State::Exit) => {
                result.push(InputResult::Exit);
            }
            None => {}
        }

        result
    }

    fn on_draw(&mut self, _: &piston_window::RenderArgs, window: &PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, _: &piston_window::UpdateArgs) {
        let button_color = color::rgb(0.4, 0.75, 0.6);

        let state = &mut self.state;

        self.ui.set_widgets(|mut ui| {
            Canvas::new()
                .pad(30.)
                .color(color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .color(button_color)
                .label("New game")
                .react(|| *state = Some(State::NewGame))
                .set(NEW_OR_CONTINUE_GAME_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_GAME_BUTTON, 45.0)
                .color(button_color)
                .label("Options")
                .react(|| *state = Some(State::Options))
                .set(OPTIONS_BUTTON, &mut ui);

            Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(OPTIONS_BUTTON, 45.0)
                .color(button_color)
                .label("Exit")
                .react(|| *state = Some(State::Exit))
                .set(EXIT_BUTTON, &mut ui);
        });
    }
}

widget_ids! {
    CANVAS,
    NEW_OR_CONTINUE_GAME_BUTTON,
    OPTIONS_BUTTON,
    EXIT_BUTTON,
}
<|endoftext|>