<commit_before>//! Responsavel pelo parsing e de gerar a AST do programa BIRL

/// Representa as keywords da linguagem
mod kw {
    // Definições
    /// Usada para declaração de globais
    static KW_GLOBAL: &'static str = "SAI DE CASA";
    /// Usada para definição de seções
    static KW_SECTION: &'static str = "JAULA";

    // Comandos
    /// Copia o valor de uma variavel a outra
    static KW_MOVE: &'static str = "BORA";
    /// Limpa o valor de uma variavel
    static KW_CLEAR: &'static str = "NUM VAI DA NAO";
    /// Xor (operador binário)
    static KW_XOR: &'static str = "TRAPEZIO DESCENDENTE";
    /// And (operador binário)
    static KW_AND: &'static str = "FIBRA";
    /// Or (operador binário)
    static KW_OR: &'static str = "TRAPEZIO";
    /// Adição
    static KW_ADD: &'static str = "CONSTROI";
    /// Diminuição
    static KW_REM: &'static str = "NEGATIVA";
    /// Divisão
    static KW_DIV: &'static str = "AGUA COM MUSCULO";
    /// Multiplicação
    static KW_MUL: &'static str = "CONSTROI FIBRA";
    /// Declara uma variável
    static KW_DECL: &'static str = "VEM";
    /// Declara uma variável com um valor
    static KW_DECLWV: &'static str = "VEM PORRA";
    /// Realiza um "pulo" de uma seção para outra
    static KW_JUMP: &'static str = "HORA DO";
    /// Comparação
    static KW_CMP: &'static str = "E ELE QUE A GENTE QUER";
}

/// Representa um valor que pode ser atribuido a uma variavel
pub enum Value {
    /// Numero inteiro de 64 bits
    Integer(i64),
    /// Numero de ponto flutuante de 64 bits
    FloatP(f64),
    /// Caractere UTF-8
    Char(char),
    /// Texto em UTF-8, guarda apenas a referencia ao valor no heap
    Str(Box<String>),
}

/// Representa um comando, que é executado dentro do contexto atual
/// Os valores passados aos comandos têm nomes fantasia alfabéticos para exemplificação
pub enum Command {
    /// Move (copia) o conteudo da variavel no endereco a pro b
    Move(u64, u64),
    /// Limpa o valor da variavel no endereco a
    Clear(u64),
    /// Aplica xor na variavel no endereco a com o valor b
    Xor(u64, i64),
    /// Aplica and na variavel no endereco a com o valor b
    And(u64, i64),
    /// Aplica or  na variavel no endereco a com o valor b
    Or(u64, i64),
    /// Adiciona b ao valor da variavel no endereco a
    Add(u64, i64),
    /// Remove b do valor da variavel no endereco a
    Rem(u64, i64),
    /// Divide o valor da variavel no endereco a com o valor b
    Div(u64, i64),
    /// Multiplica o valor da variavel no endereco a com o valor b
    Mul(u64, i64),
    /// Declara a variavel com nome a
    Decl(String),
    /// Declara a variavel com nome a e valor b
    DeclWV(String, Value),
    /// Passa a execução para outra seção com nome a, retornando uma instrução à frente
    Jump(String),
    /// Compara os valores de a e b, usado em condicionais
    Cmp(u64, u64),
}

/// Faz parsing de um comando
fn parse_cmd(cmd: &str) -> Option<Command> {
    unimplemented!();
}

/// Representa uma unidade (arquivo compilado) contendo o conteudo a ser executado
pub struct Unit {
    /// Conjunto de seções para execução
    sects: Vec<Section>,
    /// Conjunto de globais
    consts: Vec<Global>,
}

/// Realiza a interpretação de um arquivo e retorna sua unidade compilada
pub fn parse(file: &str) -> Unit {
    unimplemented!();
}

/// Representa uma área chamável que pode ser executada
pub struct Section {
    /// Nome da seção
    name: String,
    /// Conjunto de linhas/comandos para execução
    lines: Vec<Command>,
}

/// Faz parsing de uma seção
fn parse_section(sect_str: &str) -> Section {
    unimplemented!();
}

/// Representa um valor global, constante
pub struct Global {
    /// Identificador do valor global
    identifier: String,
    /// Valor do global
    value: Value,
}

/// Faz parsing de um global
fn parse_global(glb: &str) -> Global {
    unimplemented!();
}<commit_msg>Parser quase completo<commit_after>//! Responsavel pelo parsing e de gerar a AST do programa BIRL

#![allow(dead_code)]

/// Representa as keywords da linguagem
pub mod kw {
    // Definições
    /// Usada para declaração de globais
    pub const KW_GLOBAL: &'static str = "SAI DE CASA";
    /// Usada para definição de seções
    pub const KW_SECTION: &'static str = "JAULA";
    /// Usada para finalizar a definição de seções
    pub const KW_SECTEND: &'static str = "SAINDO DA JAULA";

    // Comandos
    /// Copia o valor de uma variavel a outra
    pub const KW_MOVE: &'static str = "BORA";
    /// Limpa o valor de uma variavel
    pub const KW_CLEAR: &'static str = "NUM VAI DA NAO";
    /// Xor (operador binário)
    pub const KW_XOR: &'static str = "TRAPEZIO DESCENDENTE";
    /// And (operador binário)
    pub const KW_AND: &'static str = "FIBRA";
    /// Or (operador binário)
    pub const KW_OR: &'static str = "TRAPEZIO";
    /// Adição
    pub const KW_ADD: &'static str = "CONSTROI";
    /// Diminuição
    pub const KW_REM: &'static str = "NEGATIVA";
    /// Divisão
    pub const KW_DIV: &'static str = "AGUA COM MUSCULO";
    /// Multiplicação
    pub const KW_MUL: &'static str = "CONSTROI FIBRA";
    /// Declara uma variável
    pub const KW_DECL: &'static str = "VEM";
    /// Declara uma variável com um valor
    pub const KW_DECLWV: &'static str = "VEM PORRA";
    /// Realiza um "pulo" de uma seção para outra
    pub const KW_JUMP: &'static str = "HORA DO";
    /// Comparação
    pub const KW_CMP: &'static str = "E ELE QUE A GENTE QUER";
}

/// Representa um valor que pode ser atribuido a uma variavel
pub enum Value {
    /// Numero inteiro de 64 bits
    Integer(i64),
    /// Numero de ponto flutuante de 64 bits
    FloatP(f64),
    /// Caractere UTF-8
    Char(char),
    /// Texto em UTF-8, guarda apenas a referencia ao valor no heap
    Str(Box<String>),
    /// Simbolo, que representa uma variavel no contexto do programa
    Symbol(String),
}

/// Sub-modulo responsavel por fazer parsing de expressões
mod value {

    use super::*;

    /// Tenta fazer parsing de uma expressão e retornar seu valor
    pub fn parse_expr(expr: &str) -> Option<Value> {
        let e = String::from(expr.trim());
        if e == "" {
            None
        } else {
            let fchar = e.chars().collect::<Vec<char>>()[0];
            match fchar {
                '0'...'9' => {}
                '\"' => {
                    // last_escape é se o ultimo caractere foi uma barra de escape, ignore ela
                    let (mut value, mut last_escape) = (String::new(), false);
                    let chars = e.chars().collect::<Vec<char>>();
                    for c in 1..chars.len() {
                        let actual = chars[c];
                        if actual == '\\' {
                            if last_escape {
                                value.push('\\');
                                last_escape = false;
                            } else {
                                last_escape = true;
                            }
                            continue;
                        }
                        if last_escape {
                            match actual {
                                'n' => value.push('\n'),
                                '\"' => value.push('\"'),
                                't' => value.push('\t'),
                                'r' => value.push('\r'),
                                '\'' => value.push('\''),
                                _ => {
                                    println!("Aviso: Sequencia de escape não reconhecida: \"{}\".",
                                             actual)
                                }
                            }
                            last_escape = false;
                            continue;
                        }
                        if actual == '\"' {
                            // Fim da string
                            return Some(Value::Str(Box::new(value)));
                        }
                        value.push(actual);
                    }
                }
                _ => println!("Erro, caractere \"{}\" encontrado durante parsing.", fchar),
            }
            None
        }
    }
}

/// Representa um comando, que é executado dentro do contexto atual
/// Os valores passados aos comandos têm nomes fantasia alfabéticos para exemplificação
pub enum Command {
    /// Move (copia) o conteudo da variavel no endereco a pro b
    Move(u64, u64),
    /// Limpa o valor da variavel no endereco a
    Clear(u64),
    /// Aplica xor na variavel no endereco a com o valor b
    Xor(u64, i64),
    /// Aplica and na variavel no endereco a com o valor b
    And(u64, i64),
    /// Aplica or  na variavel no endereco a com o valor b
    Or(u64, i64),
    /// Adiciona b ao valor da variavel no endereco a
    Add(u64, i64),
    /// Remove b do valor da variavel no endereco a
    Rem(u64, i64),
    /// Divide o valor da variavel no endereco a com o valor b
    Div(u64, i64),
    /// Multiplica o valor da variavel no endereco a com o valor b
    Mul(u64, i64),
    /// Declara a variavel com nome a
    Decl(String),
    /// Declara a variavel com nome a e valor b
    DeclWV(String, Value),
    /// Passa a execução para outra seção com nome a, retornando uma instrução à frente
    Jump(String),
    /// Compara os valores de a e b, usado em condicionais
    Cmp(u64, u64),
}

/// Procura pelo caractere c em src e retorna quantas vezes ele foi encontrado
fn n_of_char(c: char, src: &str) -> i32 {
    if src.len() <= 0 {
        0
    } else {
        let mut num = 0i32;
        for curr in src.chars() {
            if curr == c {
                num += 1;
            }
        }
        num
    }
}

/// Faz parsing de um comando
fn parse_cmd(cmd: &str) -> Option<Command> {
    // Estrutura de um comando:
    // COMANDO: var1, var2, ...
    let cmd = cmd.trim();
    let cmd_parts = cmd.split(':').collect::<Vec<&str>>();
    // Tipo/nome do comando
    let cmd_type = cmd_parts[0];
    let mut arguments: Vec<&str> = vec![];
    if n_of_char(',', cmd_parts[1]) == 0 {
        // Apenas um argumento
        arguments.push(cmd_parts[1].trim());
    } else {
        arguments = cmd_parts[1].split(',').collect::<Vec<&str>>();
    }
    match cmd_type {
        kw::KW_MOVE => {}
        kw::KW_CLEAR => {}
        kw::KW_XOR => {}
        kw::KW_AND => {}
        kw::KW_OR => {}
        kw::KW_ADD => {}
        kw::KW_REM => {}
        kw::KW_DIV => {}
        kw::KW_MUL => {}
        kw::KW_DECL => {}
        kw::KW_DECLWV => {}
        kw::KW_JUMP => {}
        kw::KW_CMP => {}
        _ => panic!("Erro: Tipo de comando \"{}\" não existe.", cmd_type),
    }
    None
}

/// Representa uma unidade (arquivo compilado) contendo o conteudo a ser executado
pub struct Unit {
    /// Conjunto de seções para execução
    sects: Vec<Section>,
    /// Conjunto de globais
    consts: Vec<Global>,
}

/// Realiza a interpretação de um arquivo e retorna sua unidade compilada
pub fn parse(file: &str) -> Unit {
    unimplemented!();
}

/// Representa uma área chamável que pode ser executada
pub struct Section {
    /// Nome da seção
    name: String,
    /// Conjunto de linhas/comandos para execução
    lines: Vec<Command>,
}

/// Faz parsing de uma seção
fn parse_section(sect_str: &str) -> Section {
    // Separa a seção em linhas
    let lines = sect_str.split('\n').collect::<Vec<&str>>();
    if lines.len() <= 1 {
        panic!("Erro fazendo parsing da seção. Número incorreto de linhas.")
    } else {
        // Checagens de declaração e finalização são feitas em parse
        // Declaração de uma seção:
        // PALAVRA_CHAVE nome
        if !lines[0].contains(' ') {
            panic!("Erro na declaração da seção! Falta nome depois da palavra chave");
        }
        let mut sect = Section {
            name: String::from(lines[0].split(' ').collect::<Vec<&str>>()[0]),
            lines: vec![],
        };
        for l in 1..lines.len() - 1 {
            let line = lines[l];
            sect.lines.push(parse_cmd(line).unwrap());
        }
        sect
    }
}

/// Representa um valor global, constante
pub struct Global {
    /// Identificador do valor global
    identifier: String,
    /// Valor do global
    value: Value,
}

/// Faz parsing de um global
fn parse_global(glb: &str) -> Global {
    // Estrutura da declaração de um global: PALAVRA_CHAVE: nome: valor
    let global = String::from(glb.trim());
    let words = global.split(':').collect::<Vec<&str>>();
    // Separa o nome e valor do global
    let (glb_name, glb_value) = (words[1].trim(), words[2].trim());
    let glb_value = match value::parse_expr(glb_value) {
        Some(val) => val,
        None => panic!(),
    };
    Global {
        identifier: String::from(glb_name),
        value: glb_value,
    }
}
<|endoftext|>


<commit_before>//! Protocol-related utilities
//!
//! This module contains several handlers to manage the wayland protocol
//! and the clients.

pub mod compositor;
pub mod output;
pub mod seat;
pub mod shm;
pub mod shell;
<commit_msg>wayland: document general behaviour of the client handlers<commit_after>//! Protocol-related utilities
//!
//! This module contains several handlers to manage the wayland protocol
//! and the clients.
//!
//! Most utilities provided in this module work in the wame way:
//!
//! - An init function or method will take the event loop as argument and
//!   insert one or more globals into it.
//! - These functions will return the `Global` handles and, if applicable,
//!   a `StateToken` allowing you to access the associated state value in
//!   this event loop.
//! - If you want to remove a previously inserted global, just call the
//!   `destroy()` method on the associated `Global`. If you don't plan to
//!   destroy the global at all, you don't need to bother keeping the
//!   `Global` around.
//! - You should not remove a state value from the event loop if you have
//!   not previously destroyed all the globals using it, otherwise you'll
//!   quickly encounter a panic.

pub mod compositor;
pub mod output;
pub mod seat;
pub mod shm;
pub mod shell;
<|endoftext|>


<commit_before>use config::{PollerSettingsProvider, AwsCredentialsProviderType};
use std::result::Result;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
use std::sync::Arc;
use rusoto::{ProvideAwsCredentials, AwsCredentials, DefaultCredentialsProviderSync, EnvironmentProvider,
             ProfileProvider, InstanceMetadataProvider, ContainerProvider, CredentialsError,
             Region, ParseRegionError, HttpDispatchError};
use rusoto::ec2;
use rusoto::default_tls_client;
use hyper;
use std::ascii::AsciiExt;
use std::iter::Iterator;

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum PollerError {
    InvalidCredentials(String),
    InsufficientPermissions(String),
    BadRegion(String),
    NetworkError(String),
    UnknownError(String),
    NoError
}

impl fmt::Display for PollerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl From<CredentialsError> for PollerError {
    fn from(error: CredentialsError) -> Self {
        PollerError::InvalidCredentials(String::from(error.description()))
    }
}

impl From<ParseRegionError> for PollerError {
    fn from(error: ParseRegionError) -> Self {
        PollerError::BadRegion(String::from(error.description()))
    }
}

impl From<HttpDispatchError> for PollerError {
    fn from(error: HttpDispatchError) -> Self {
        PollerError::NetworkError(String::from(error.description()))
    }
}

impl From<ec2::DescribeInstancesError> for PollerError {
    fn from(e: ec2::DescribeInstancesError) -> Self {
        match e {
            ec2::DescribeInstancesError::HttpDispatch(dpt) => PollerError::from(dpt),
            ec2::DescribeInstancesError::Credentials(crd) => PollerError::from(crd),
            ec2::DescribeInstancesError::Validation(s) => PollerError::UnknownError(s),
            ec2::DescribeInstancesError::Unknown(s) => {
                if s.contains("DryRunOperation") {
                    PollerError::NoError
                } else if s.contains("UnauthorizedOperation") {
                    PollerError::InsufficientPermissions(String::from("DescribeInstances"))
                } else {
                    PollerError::UnknownError(s)
                }
            }
        }
    }
}

impl Error for PollerError {
    fn description(&self) -> &str {
        match *self {
            PollerError::InvalidCredentials(ref m) => &m,
            PollerError::InsufficientPermissions(ref m) => &m,
            PollerError::BadRegion(ref m) => &m,
            PollerError::NetworkError(ref m) => &m,
            PollerError::UnknownError(ref m) => &m,
            PollerError::NoError => "No error",
        }
    }
}

type PollerResult<T> = Result<T, PollerError>;

pub trait Poller : Sync + Send {
    fn poll(&self);
}

#[derive(Clone)]
struct CredentialsProviderWrapper {
    inner: Arc<ProvideAwsCredentials + Send + Sync>
}

impl ProvideAwsCredentials for CredentialsProviderWrapper {
    fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
        self.inner.credentials()
    }
}

type Ec2Client = ec2::Ec2Client<CredentialsProviderWrapper, hyper::Client>;

pub struct AwsPoller {
    credentials_provider: CredentialsProviderWrapper,
    region: Region,
    di_chunk_size: Option<i32>,
    expose_tags: Vec<String>,
}

impl AwsPoller {
    pub fn new(settings: &PollerSettingsProvider) -> PollerResult<AwsPoller> {
        let result = AwsPoller{
            credentials_provider: Self::new_credentials_provider(settings.credentials_provider())?,
            region : Region::from_str(settings.region())?,
            di_chunk_size: settings.describe_instances_chunk_size(),
            expose_tags: settings.expose_tags(),
        };
        if let Some(e) = result.test_credentials() { Err(e)? }
        else if let Some(e) = result.test_describe_instances() { Err(e)? }
        else { Ok(result) }
    }

    fn new_credentials_provider(provider_type: AwsCredentialsProviderType)
        -> Result<CredentialsProviderWrapper, CredentialsError> {
        Ok(CredentialsProviderWrapper {
            inner: match provider_type {
                AwsCredentialsProviderType::Default =>
                    Arc::new(DefaultCredentialsProviderSync::new()?),
                AwsCredentialsProviderType::Environment =>
                    Arc::new(EnvironmentProvider {}),
                AwsCredentialsProviderType::Profile =>
                    Arc::new(ProfileProvider::new()?),
                AwsCredentialsProviderType::Instance =>
                    Arc::new(InstanceMetadataProvider {}),
                AwsCredentialsProviderType::Container =>
                    Arc::new(ContainerProvider {})
            }
        })
    }

    /// Try to retrieve credentials from provider to be able to fail-fast if the credentials
    /// are not available.
    fn test_credentials(&self) -> Option<PollerError> {
        self.credentials_provider.credentials().err().map(|e| PollerError::from(e))
    }

    fn get_ec2_client(&self) -> Ec2Client {
        Ec2Client::new(default_tls_client().unwrap(), self.credentials_provider.clone(), self.region)
    }

    fn test_describe_instances(&self) -> Option<PollerError> {
        let client = self.get_ec2_client();
        let mut req : ec2::DescribeInstancesRequest = Default::default();
        req.dry_run = Some(true);

        match client.describe_instances(&req) {
            Err(e) => {
                match PollerError::from(e) {
                    PollerError::NoError => None,
                    e => Some(e)
                }
            }
            _ => None
        }
    }

}

struct DescribeInstancesIterator {
    current_page: Option<Vec<ec2::Instance>>,
    client: Ec2Client,
    req: ec2::DescribeInstancesRequest,
    error: Option<ec2::DescribeInstancesError>,
    first_chunk: bool,
}

impl DescribeInstancesIterator {
    fn new(client: Ec2Client, filters: Vec<ec2::Filter>, chunk_size: Option<i32>) -> Self {
        let mut req: ec2::DescribeInstancesRequest = Default::default();
        req.filters = Some(filters);
        req.max_results = chunk_size;
        DescribeInstancesIterator {
            current_page: None,
            client: client,
            req: req,
            error: None,
            first_chunk: true,
        }
    }

    fn next_page(&mut self) -> Option<Vec<ec2::Instance>> {
        if self.req.next_token.is_none() && !self.first_chunk {
            return None;
        }
        self.first_chunk = false;
        match self.client.describe_instances(&self.req) {
            Ok(ref mut resp) => {
                let mut chunk = vec![];
                if let Some(ref mut reservations) = resp.reservations {
                    for r in reservations {
                        if let Some(ref mut instances) = r.instances {
                            chunk.append(instances);
                        }
                    }
                }
                self.req.next_token = resp.next_token.clone();
                Some(chunk.into_iter().rev().collect())
            }
            Err(e) => {
                self.error = Some(e);
                None
            }
        }
    }
}

impl Iterator for DescribeInstancesIterator {
    type Item = ec2::Instance;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_page.is_none() {
            self.current_page = self.next_page();
            if self.current_page.is_none() {
                return None;
            }
        }
        match self.current_page.as_mut().unwrap().pop() {
            Some(i) => Some(i),
            None => {
                self.current_page = self.next_page();
                match self.current_page {
                    Some(_) => self.next(),
                    None => None
                }
            }
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct MetricLabel {
    key: String,
    value: String,
}

impl From<ec2::Tag> for MetricLabel {
    fn from(tag: ec2::Tag) -> Self {
        MetricLabel {
            key: tag.key.unwrap(),
            value: tag.value.unwrap(),
        }
    }
}

impl Poller for AwsPoller {
    fn poll(&self) {
        let running_filter = ec2::Filter{
            name: Some(String::from("instance-state-code")),
            values: Some(vec![String::from("16")])
        };
        let di = DescribeInstancesIterator::new(self.get_ec2_client(), vec![running_filter],
                                        self.di_chunk_size);
        for instance in di {
            if let Some(tags) = instance.tags {
                let mut labels = vec![MetricLabel
                    {
                        key: "id".to_owned(),
                        value: instance.instance_id.unwrap(),
                    }];
                let mut used_tags = tags.into_iter().filter(|t| {
                    self.expose_tags.clone().into_iter().any(
                        |e| t.clone().key.unwrap().eq_ignore_ascii_case(&e))
                }).map(|t| MetricLabel::from(t))
                    .collect::<Vec<MetricLabel>>();
                labels.append(&mut used_tags);
                println!("{:?}" , labels);
            }
        }
    }
}
<commit_msg>handle wrong credentials error<commit_after>use config::{PollerSettingsProvider, AwsCredentialsProviderType};
use std::result::Result;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
use std::sync::Arc;
use rusoto::{ProvideAwsCredentials, AwsCredentials, DefaultCredentialsProviderSync, EnvironmentProvider,
             ProfileProvider, InstanceMetadataProvider, ContainerProvider, CredentialsError,
             Region, ParseRegionError, HttpDispatchError};
use rusoto::ec2;
use rusoto::default_tls_client;
use hyper;
use std::ascii::AsciiExt;
use std::iter::Iterator;

#[derive(Debug, Eq, PartialEq, Clone)]
pub enum PollerError {
    InvalidCredentials(String),
    InsufficientPermissions(String),
    BadRegion(String),
    NetworkError(String),
    UnknownError(String),
    NoError
}

impl fmt::Display for PollerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl From<CredentialsError> for PollerError {
    fn from(error: CredentialsError) -> Self {
        PollerError::InvalidCredentials(String::from(error.description()))
    }
}

impl From<ParseRegionError> for PollerError {
    fn from(error: ParseRegionError) -> Self {
        PollerError::BadRegion(String::from(error.description()))
    }
}

impl From<HttpDispatchError> for PollerError {
    fn from(error: HttpDispatchError) -> Self {
        PollerError::NetworkError(String::from(error.description()))
    }
}

impl From<ec2::DescribeInstancesError> for PollerError {
    fn from(e: ec2::DescribeInstancesError) -> Self {
        match e {
            ec2::DescribeInstancesError::HttpDispatch(dpt) => PollerError::from(dpt),
            ec2::DescribeInstancesError::Credentials(crd) => PollerError::from(crd),
            ec2::DescribeInstancesError::Validation(s) => PollerError::InvalidCredentials(s),
            ec2::DescribeInstancesError::Unknown(s) => {
                if s.contains("DryRunOperation") {
                    PollerError::NoError
                } else if s.contains("UnauthorizedOperation") {
                    PollerError::InsufficientPermissions(String::from("DescribeInstances"))
                } else if s.contains("AuthFailure") {
                    PollerError::InvalidCredentials(s)
                } else {
                    PollerError::UnknownError(s)
                }
            }
        }
    }
}

impl Error for PollerError {
    fn description(&self) -> &str {
        match *self {
            PollerError::InvalidCredentials(ref m) => &m,
            PollerError::InsufficientPermissions(ref m) => &m,
            PollerError::BadRegion(ref m) => &m,
            PollerError::NetworkError(ref m) => &m,
            PollerError::UnknownError(ref m) => &m,
            PollerError::NoError => "No error",
        }
    }
}

type PollerResult<T> = Result<T, PollerError>;

pub trait Poller : Sync + Send {
    fn poll(&self);
}

#[derive(Clone)]
struct CredentialsProviderWrapper {
    inner: Arc<ProvideAwsCredentials + Send + Sync>
}

impl ProvideAwsCredentials for CredentialsProviderWrapper {
    fn credentials(&self) -> Result<AwsCredentials, CredentialsError> {
        self.inner.credentials()
    }
}

type Ec2Client = ec2::Ec2Client<CredentialsProviderWrapper, hyper::Client>;

pub struct AwsPoller {
    credentials_provider: CredentialsProviderWrapper,
    region: Region,
    di_chunk_size: Option<i32>,
    expose_tags: Vec<String>,
}

impl AwsPoller {
    pub fn new(settings: &PollerSettingsProvider) -> PollerResult<AwsPoller> {
        let result = AwsPoller{
            credentials_provider: Self::new_credentials_provider(settings.credentials_provider())?,
            region : Region::from_str(settings.region())?,
            di_chunk_size: settings.describe_instances_chunk_size(),
            expose_tags: settings.expose_tags(),
        };
        if let Some(e) = result.test_credentials() { Err(e)? }
        else if let Some(e) = result.test_describe_instances() { Err(e)? }
        else { Ok(result) }
    }

    fn new_credentials_provider(provider_type: AwsCredentialsProviderType)
        -> Result<CredentialsProviderWrapper, CredentialsError> {
        Ok(CredentialsProviderWrapper {
            inner: match provider_type {
                AwsCredentialsProviderType::Default =>
                    Arc::new(DefaultCredentialsProviderSync::new()?),
                AwsCredentialsProviderType::Environment =>
                    Arc::new(EnvironmentProvider {}),
                AwsCredentialsProviderType::Profile =>
                    Arc::new(ProfileProvider::new()?),
                AwsCredentialsProviderType::Instance =>
                    Arc::new(InstanceMetadataProvider {}),
                AwsCredentialsProviderType::Container =>
                    Arc::new(ContainerProvider {})
            }
        })
    }

    /// Try to retrieve credentials from provider to be able to fail-fast if the credentials
    /// are not available.
    fn test_credentials(&self) -> Option<PollerError> {
        self.credentials_provider.credentials().err().map(|e| PollerError::from(e))
    }

    fn get_ec2_client(&self) -> Ec2Client {
        Ec2Client::new(default_tls_client().unwrap(), self.credentials_provider.clone(), self.region)
    }

    fn test_describe_instances(&self) -> Option<PollerError> {
        let client = self.get_ec2_client();
        let mut req : ec2::DescribeInstancesRequest = Default::default();
        req.dry_run = Some(true);

        match client.describe_instances(&req) {
            Err(e) => {
                match PollerError::from(e) {
                    PollerError::NoError => None,
                    e => Some(e)
                }
            }
            _ => None
        }
    }

}

struct DescribeInstancesIterator {
    current_page: Option<Vec<ec2::Instance>>,
    client: Ec2Client,
    req: ec2::DescribeInstancesRequest,
    error: Option<ec2::DescribeInstancesError>,
    first_chunk: bool,
}

impl DescribeInstancesIterator {
    fn new(client: Ec2Client, filters: Vec<ec2::Filter>, chunk_size: Option<i32>) -> Self {
        let mut req: ec2::DescribeInstancesRequest = Default::default();
        req.filters = Some(filters);
        req.max_results = chunk_size;
        DescribeInstancesIterator {
            current_page: None,
            client: client,
            req: req,
            error: None,
            first_chunk: true,
        }
    }

    fn next_page(&mut self) -> Option<Vec<ec2::Instance>> {
        if self.req.next_token.is_none() && !self.first_chunk {
            return None;
        }
        self.first_chunk = false;
        match self.client.describe_instances(&self.req) {
            Ok(ref mut resp) => {
                let mut chunk = vec![];
                if let Some(ref mut reservations) = resp.reservations {
                    for r in reservations {
                        if let Some(ref mut instances) = r.instances {
                            chunk.append(instances);
                        }
                    }
                }
                self.req.next_token = resp.next_token.clone();
                Some(chunk.into_iter().rev().collect())
            }
            Err(e) => {
                self.error = Some(e);
                None
            }
        }
    }
}

impl Iterator for DescribeInstancesIterator {
    type Item = ec2::Instance;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_page.is_none() {
            self.current_page = self.next_page();
            if self.current_page.is_none() {
                return None;
            }
        }
        match self.current_page.as_mut().unwrap().pop() {
            Some(i) => Some(i),
            None => {
                self.current_page = self.next_page();
                match self.current_page {
                    Some(_) => self.next(),
                    None => None
                }
            }
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct MetricLabel {
    key: String,
    value: String,
}

impl From<ec2::Tag> for MetricLabel {
    fn from(tag: ec2::Tag) -> Self {
        MetricLabel {
            key: tag.key.unwrap(),
            value: tag.value.unwrap(),
        }
    }
}

impl Poller for AwsPoller {
    fn poll(&self) {
        let running_filter = ec2::Filter{
            name: Some(String::from("instance-state-code")),
            values: Some(vec![String::from("16")])
        };
        let di = DescribeInstancesIterator::new(self.get_ec2_client(), vec![running_filter],
                                        self.di_chunk_size);
        for instance in di {
            if let Some(tags) = instance.tags {
                let mut labels = vec![MetricLabel
                    {
                        key: "id".to_owned(),
                        value: instance.instance_id.unwrap(),
                    }];
                let mut used_tags = tags.into_iter().filter(|t| {
                    self.expose_tags.clone().into_iter().any(
                        |e| t.clone().key.unwrap().eq_ignore_ascii_case(&e))
                }).map(|t| MetricLabel::from(t))
                    .collect::<Vec<MetricLabel>>();
                labels.append(&mut used_tags);
                println!("{:?}" , labels);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;

use aho_corasick::{Automaton, AcAutomaton, FullAcAutomaton};
use memchr::memchr;

/// A prefix extracted from a compiled regular expression.
///
/// A regex prefix is a set of literal strings that *must* be matched at the
/// beginning of a regex in order for the entire regex to match.
///
/// There are a variety of ways to efficiently scan the search text for a
/// prefix. Currently, there are three implemented:
///
/// 1. The prefix is a single byte. Just use memchr.
/// 2. If the prefix is a set of two or more single byte prefixes, then
///    a single sparse map is created. Checking if there is a match is a lookup
///    in this map for each byte in the search text.
/// 3. In all other cases, build an Aho-Corasick automaton.
///
/// It's possible that there's room here for other substring algorithms,
/// such as Boyer-Moore for single-set prefixes greater than 1, or Rabin-Karp
/// for small sets of same-length prefixes.
#[derive(Clone)]
pub enum Prefix {
    /// No prefixes. (Never advances through the input.)
    Empty,
    /// A single byte prefix.
    Single(u8),
    /// A set of two or more single byte prefixes.
    /// This could be reduced to a bitset, which would use only 8 bytes,
    /// but I don't think we care.
    Singles {
        chars: Vec<u8>,
        sparse: Vec<bool>,
    },
    /// A full Aho-Corasick DFA automaton.
    Automaton(FullAcAutomaton),
}

impl Prefix {
    /// Create a new prefix matching machine.
    pub fn new(pfxs: Vec<String>) -> Prefix {
        if pfxs.len() == 0 || pfxs[0].len() == 0 {
            Prefix::Empty
        } else if pfxs.len() == 1 && pfxs[0].len() == 1 {
            Prefix::Single(pfxs[0].as_bytes()[0])
        } else if pfxs.len() >= 2 && pfxs.iter().all(|s| s.len() == 1) {
            let mut set = vec![false; 256];
            let mut chars = vec![];
            for p in pfxs {
                chars.push(p.as_bytes()[0]);
                set[p.as_bytes()[0] as usize] = true;
            }
            Prefix::Singles { chars: chars, sparse: set }
        } else {
            Prefix::Automaton(AcAutomaton::new(pfxs).into_full())
        }
    }

    /// Find the position of a prefix in `haystack` if it exists.
    ///
    /// In the matching engines, we only actually need the starting index
    /// because the prefix is used to only skip ahead---the matching engine
    /// still needs to run over the prefix input. However, we return the ending
    /// location as well in case the prefix corresponds to the entire regex,
    /// in which case, you need the end of the match.
    pub fn find(&self, haystack: &str) -> Option<(usize, usize)> {
        use self::Prefix::*;
        match *self {
            Empty => Some((0, 0)),
            Single(b) => memchr(b, haystack.as_bytes()).map(|i| (i, i+1)),
            Singles { ref sparse, .. } => {
                find_singles(sparse, haystack.as_bytes())
            }
            Automaton(ref aut) => {
                aut.find(haystack).next().map(|m| (m.start, m.end))
            }
        }
    }

    /// Returns true iff this prefix is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the number of prefixes in this machine.
    pub fn len(&self) -> usize {
        match *self {
            Prefix::Empty => 0,
            Prefix::Single(_) => 1,
            Prefix::Singles { ref chars, .. } => chars.len(),
            Prefix::Automaton(ref aut) => aut.len(),
        }
    }

    /// Returns true iff the prefix match preserves priority.
    ///
    /// For example, given the alternation `ab|a` and the target string `ab`,
    /// does the prefix machine guarantee that `ab` will match? (A full
    /// Aho-Corasick automaton does not!)
    pub fn preserves_priority(&self) -> bool {
        match *self {
            Prefix::Empty => true,
            Prefix::Single(_) => true,
            Prefix::Singles{..} => true,
            Prefix::Automaton(ref aut) => {
                // Okay, so the automaton can respect priority in one
                // particular case: when every pattern is of the same length.
                // The trick is that the automaton will report the leftmost
                // match, which in this case, corresponds to the correct
                // match for the regex engine. If any other alternate matches
                // at the same position, then they must be exactly equivalent.

                // Guaranteed at least one prefix by construction, so use
                // that for the length.
                aut.patterns().iter().all(|p| p.len() == aut.pattern(0).len())
            }
        }
    }
}

/// A very quick scan for multiple single byte prefixes using a sparse map.
fn find_singles(sparse: &[bool], haystack: &[u8]) -> Option<(usize, usize)> {
    for (hi, &b) in haystack.iter().enumerate() {
        if sparse[b as usize] {
            return Some((hi, hi+1));
        }
    }
    None
}

impl fmt::Debug for Prefix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Prefix::Empty => write!(f, "Empty"),
            Prefix::Single(b) => write!(f, "{:?}", b as char),
            Prefix::Singles { ref chars, .. } => {
                let chars: Vec<String> =
                    chars.iter()
                         .map(|&c| format!("{:?}", c as char))
                         .collect();
                write!(f, "{}", chars.connect(", "))
            }
            Prefix::Automaton(ref aut) => write!(f, "{:?}", aut),
        }
    }
}
<commit_msg>Add a Boyer-Moore-Horspool substring algorithm.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;

use aho_corasick::{Automaton, AcAutomaton, FullAcAutomaton};
use memchr::memchr;

/// A prefix extracted from a compiled regular expression.
///
/// A regex prefix is a set of literal strings that *must* be matched at the
/// beginning of a regex in order for the entire regex to match.
///
/// There are a variety of ways to efficiently scan the search text for a
/// prefix. Currently, there are three implemented:
///
/// 1. The prefix is a single byte. Just use memchr.
/// 2. If the prefix is a set of two or more single byte prefixes, then
///    a single sparse map is created. Checking if there is a match is a lookup
///    in this map for each byte in the search text.
/// 3. In all other cases, build an Aho-Corasick automaton.
///
/// It's possible that there's room here for other substring algorithms,
/// such as Boyer-Moore for single-set prefixes greater than 1, or Rabin-Karp
/// for small sets of same-length prefixes.
#[derive(Clone)]
pub enum Prefix {
    /// No prefixes. (Never advances through the input.)
    Empty,
    /// A single byte prefix.
    Byte(u8),
    /// A set of two or more single byte prefixes.
    /// This could be reduced to a bitset, which would use only 8 bytes,
    /// but I don't think we care.
    Bytes {
        chars: Vec<u8>,
        sparse: Vec<bool>,
    },
    Single(SingleSearch),
    /// A full Aho-Corasick DFA automaton.
    Automaton(FullAcAutomaton),
}

impl Prefix {
    /// Create a new prefix matching machine.
    pub fn new(mut pfxs: Vec<String>) -> Prefix {
        if pfxs.len() == 0 || pfxs[0].len() == 0 {
            Prefix::Empty
        } else if pfxs.len() == 1 && pfxs[0].len() == 1 {
            Prefix::Byte(pfxs[0].as_bytes()[0])
        } else if pfxs.len() >= 2 && pfxs.iter().all(|s| s.len() == 1) {
            let mut set = vec![false; 256];
            let mut chars = vec![];
            for p in pfxs {
                chars.push(p.as_bytes()[0]);
                set[p.as_bytes()[0] as usize] = true;
            }
            Prefix::Bytes { chars: chars, sparse: set }
        } else if pfxs.len() == 1 {
            Prefix::Single(SingleSearch::new(pfxs.pop().unwrap()))
        } else {
            Prefix::Automaton(AcAutomaton::new(pfxs).into_full())
        }
    }

    /// Find the position of a prefix in `haystack` if it exists.
    ///
    /// In the matching engines, we only actually need the starting index
    /// because the prefix is used to only skip ahead---the matching engine
    /// still needs to run over the prefix input. However, we return the ending
    /// location as well in case the prefix corresponds to the entire regex,
    /// in which case, you need the end of the match.
    pub fn find(&self, haystack: &str) -> Option<(usize, usize)> {
        use self::Prefix::*;
        match *self {
            Empty => Some((0, 0)),
            Byte(b) => memchr(b, haystack.as_bytes()).map(|i| (i, i+1)),
            Bytes { ref sparse, .. } => {
                find_singles(sparse, haystack.as_bytes())
            }
            Single(ref searcher) => {
                searcher.find(haystack).map(|i| (i, i + searcher.pat.len()))
            }
            Automaton(ref aut) => {
                aut.find(haystack).next().map(|m| (m.start, m.end))
            }
        }
    }

    /// Returns true iff this prefix is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the number of prefixes in this machine.
    pub fn len(&self) -> usize {
        match *self {
            Prefix::Empty => 0,
            Prefix::Byte(_) => 1,
            Prefix::Bytes { ref chars, .. } => chars.len(),
            Prefix::Single(_) => 1,
            Prefix::Automaton(ref aut) => aut.len(),
        }
    }

    /// Returns true iff the prefix match preserves priority.
    ///
    /// For example, given the alternation `ab|a` and the target string `ab`,
    /// does the prefix machine guarantee that `ab` will match? (A full
    /// Aho-Corasick automaton does not!)
    pub fn preserves_priority(&self) -> bool {
        match *self {
            Prefix::Empty => true,
            Prefix::Byte(_) => true,
            Prefix::Bytes{..} => true,
            Prefix::Single(_) => true,
            Prefix::Automaton(ref aut) => {
                // Okay, so the automaton can respect priority in one
                // particular case: when every pattern is of the same length.
                // The trick is that the automaton will report the leftmost
                // match, which in this case, corresponds to the correct
                // match for the regex engine. If any other alternate matches
                // at the same position, then they must be exactly equivalent.

                // Guaranteed at least one prefix by construction, so use
                // that for the length.
                aut.patterns().iter().all(|p| p.len() == aut.pattern(0).len())
            }
        }
    }

    /// Returns all of the prefixes participating in this machine.
    ///
    /// For debug/testing only! (It allocates.)
    #[allow(dead_code)]
    pub fn prefixes(&self) -> Vec<String> {
        match *self {
            Prefix::Empty => vec![],
            Prefix::Byte(b) => vec![format!("{}", b as char)],
            Prefix::Bytes { ref chars, .. } => {
                chars.iter().map(|&b| format!("{}", b as char)).collect()
            }
            Prefix::Single(ref searcher) => vec![searcher.pat.clone()],
            Prefix::Automaton(ref aut) => aut.patterns().to_vec(),
        }
    }
}

/// Provides an implementation of fast subtring search.
///
/// In particular, this uses Boyer-Moore-Horspool with Tim Raita's twist:
/// https://en.wikipedia.org/wiki/Raita_Algorithm
///
/// I'm skeptical of the utility here, because benchmarks suggest that it is
/// difficult to beat Aho-Corasick on random text. Namely, both algorithms are
/// dominated by the performance of `memchr` for the leading byte prefix.
/// With that said, BMH does seem to surpass AC when the search text gets
/// longer (see the `easy0_1MB` vs. `easy1_1MB` benchmarks).
///
/// More analysis needs to be done to test this on different search texts.
#[derive(Clone, Debug)]
struct SingleSearch {
    pat: String,
    shift: Vec<usize>,
}

impl SingleSearch {
    fn new(pat: String) -> SingleSearch {
        assert!(pat.len() >= 1);
        let mut shift = vec![pat.len(); 256];
        for i in 0..(pat.len() - 1) {
            shift[pat.as_bytes()[i] as usize] = pat.len() - i - 1;
        }
        SingleSearch {
            pat: pat,
            shift: shift,
        }
    }

    fn find(&self, haystack: &str) -> Option<usize> {
        let pat = self.pat.as_bytes();
        let haystack = haystack.as_bytes();
        if haystack.len() < pat.len() {
            return None;
        }
        let mut i = match memchr(pat[0], haystack) {
            None => return None,
            Some(i) => i,
        };
        while i <= haystack.len() - pat.len() {
            let b = haystack[i + pat.len() - 1];
            if b == pat[pat.len() - 1]
               && haystack[i] == pat[0]
               && haystack[i + (pat.len() / 2)] == pat[pat.len() / 2]
               && pat == &haystack[i..i + pat.len()] {
                return Some(i);
            }
            i += self.shift[b as usize];
            i += match memchr(pat[0], &haystack[i..]) {
                None => return None,
                Some(i) => i,
            };
        }
        None
    }
}

/// A quick scan for multiple single byte prefixes using a sparse map.
fn find_singles(sparse: &[bool], haystack: &[u8]) -> Option<(usize, usize)> {
    // TODO: Improve this with ideas found in jetscii crate.
    for (hi, &b) in haystack.iter().enumerate() {
        if sparse[b as usize] {
            return Some((hi, hi+1));
        }
    }
    None
}

impl fmt::Debug for Prefix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Prefix::Empty => write!(f, "Empty"),
            Prefix::Byte(b) => write!(f, "{:?}", b as char),
            Prefix::Bytes { ref chars, .. } => {
                let chars: Vec<String> =
                    chars.iter()
                         .map(|&c| format!("{:?}", c as char))
                         .collect();
                write!(f, "{}", chars.connect(", "))
            }
            Prefix::Single(ref searcher) => write!(f, "{:?}", searcher),
            Prefix::Automaton(ref aut) => write!(f, "{:?}", aut),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]

pub struct Bytes {
  a: u8,
  b: u8,
  c: u8,
  d: u8,
}

// CHECK-LABEL: small_array_alignment
// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target
// dependent alignment
#[no_mangle]
pub fn small_array_alignment(x: &mut [i8; 4]) {
// CHECK: [[VAR:%[0-9]+]] = load {{(\[4 x i8\]\*, )?}}[4 x i8]** %x
// CHECK: [[VAR2:%[0-9]+]] = bitcast [4 x i8]* [[VAR]] to i32*
// CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1
    *x = [0; 4];
}

// CHECK-LABEL: small_struct_alignment
// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target
// dependent alignment
#[no_mangle]
pub fn small_struct_alignment(x: &mut Bytes) {
// CHECK: [[VAR:%[0-9]+]] = load {{(%Bytes\*, )?}}%Bytes** %x
// CHECK: [[VAR2:%[0-9]+]] = bitcast %Bytes* [[VAR]] to i32*
// CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1
    *x = Bytes {
        a: 0,
        b: 0,
        c: 0,
        d: 0,
    };
}
<commit_msg>tests: Use arguments in codegen/stores.rs to turn aggregates into immediates.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]

pub struct Bytes {
  a: u8,
  b: u8,
  c: u8,
  d: u8,
}

// CHECK-LABEL: small_array_alignment
// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target
// dependent alignment
#[no_mangle]
pub fn small_array_alignment(x: &mut [i8; 4], y: [i8; 4]) {
// CHECK: [[VAR:%[0-9]+]] = bitcast [4 x i8]* %y to i32*
// CHECK: store i32 %{{.*}}, i32* [[VAR]], align 1
    *x = y;
}

// CHECK-LABEL: small_struct_alignment
// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target
// dependent alignment
#[no_mangle]
pub fn small_struct_alignment(x: &mut Bytes, y: Bytes) {
// CHECK: [[VAR:%[0-9]+]] = bitcast %Bytes* %y to i32*
// CHECK: store i32 %{{.*}}, i32* [[VAR]], align 1
    *x = y;
}
<|endoftext|>


<commit_before>use rand::{SeedableRng, Rng, rngs::SmallRng};

// Having more than 1 test does seem to make a difference
// (i.e., this calls ptr::swap which having just one test does not).
#[test]
fn simple1() {
    assert_eq!(4, 4);
}

#[test]
fn simple2() {
    assert_ne!(42, 24);
}

// A test that won't work on miri (tests disabling tests)
#[cfg(not(miri))]
#[test]
fn does_not_work_on_miri() {
    let x = 0u8;
    assert!(&x as *const _ as usize % 4 < 4);
}

// We also use this to test some external crates, that we cannot depend on in the compiletest suite.

#[test]
fn entropy_rng() {
    // Try seeding with "real" entropy.
    let mut rng = SmallRng::from_entropy();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();

    // Also try per-thread RNG.
    let mut rng = rand::thread_rng();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();
}

#[test]
fn num_cpus() {
    assert_eq!(num_cpus::get(), 1);
}
<commit_msg>disable num_cpus on Windows for now<commit_after>use rand::{SeedableRng, Rng, rngs::SmallRng};

// Having more than 1 test does seem to make a difference
// (i.e., this calls ptr::swap which having just one test does not).
#[test]
fn simple1() {
    assert_eq!(4, 4);
}

#[test]
fn simple2() {
    assert_ne!(42, 24);
}

// A test that won't work on miri (tests disabling tests)
#[cfg(not(miri))]
#[test]
fn does_not_work_on_miri() {
    let x = 0u8;
    assert!(&x as *const _ as usize % 4 < 4);
}

// We also use this to test some external crates, that we cannot depend on in the compiletest suite.

#[test]
fn entropy_rng() {
    // Try seeding with "real" entropy.
    let mut rng = SmallRng::from_entropy();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();

    // Also try per-thread RNG.
    let mut rng = rand::thread_rng();
    let _val = rng.gen::<i32>();
    let _val = rng.gen::<isize>();
    let _val = rng.gen::<i128>();
}

#[test]
fn num_cpus() {
    #[cfg(not(windows))] // FIXME: enable on Windows again once https://github.com/seanmonstar/num_cpus/pull/90 gets released.
    assert_eq!(num_cpus::get(), 1);
}
<|endoftext|>


<commit_before>extern crate rand;

use super::structure::{Program,Condition,Command,Expression,Sensor};

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			i @ 0...1 if i < 1 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			i @ 1...2 if i < 2 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			i @ 0...1  if i < 1  => Condition::True,
			i @ 1...2  if i < 2  => Condition::False,
			i @ 2...3  if i < 3  => Condition::Not(Box::new(Condition::rand(rng))),
			i @ 3...4  if i < 4  => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 4...5  if i < 5  => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 5...6  if i < 6  => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 6...7  if i < 7  => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 7...8  if i < 8  => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 8...9  if i < 9  => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 9...10 if i < 10 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			i @ 0...1 if i < 1 => Command::Skip,
			i @ 1...2 if i < 2 => Command::Left,
			i @ 2...3 if i < 3 => Command::Right,
			i @ 3...4 if i < 4 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Expression::Constant(rng.next_f32()),
			i @ 1...2 if i < 2 => Expression::Sensor(Sensor::rand(rng)),
			i @ 2...3 if i < 3 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 3...4 if i < 4 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 4...5 if i < 5 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 5...6 if i < 6 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Sensor::X,
			i @ 1...2 if i < 2 => Sensor::Y,
			i @ 2...3 if i < 3 => Sensor::Vx,
			i @ 3...4 if i < 4 => Sensor::Vy,
			i @ 4...5 if i < 5 => Sensor::O,
			i @ 5...6 if i < 6 => Sensor::W,
			_ => panic!(),
		}
	}
}<commit_msg>Create a pick macro<commit_after>extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			i @ 0...1 if i < 1 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			i @ 1...2 if i < 2 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			i @ 0...1  if i < 1  => Condition::True,
			i @ 1...2  if i < 2  => Condition::False,
			i @ 2...3  if i < 3  => Condition::Not(Box::new(Condition::rand(rng))),
			i @ 3...4  if i < 4  => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 4...5  if i < 5  => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 5...6  if i < 6  => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 6...7  if i < 7  => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 7...8  if i < 8  => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 8...9  if i < 9  => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 9...10 if i < 10 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			i @ 0...1 if i < 1 => Command::Skip,
			i @ 1...2 if i < 2 => Command::Left,
			i @ 2...3 if i < 3 => Command::Right,
			i @ 3...4 if i < 4 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Expression::Constant(rng.next_f32()),
			i @ 1...2 if i < 2 => Expression::Sensor(Sensor::rand(rng)),
			i @ 2...3 if i < 3 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 3...4 if i < 4 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 4...5 if i < 5 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 5...6 if i < 6 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Sensor::X,
			i @ 1...2 if i < 2 => Sensor::Y,
			i @ 2...3 if i < 3 => Sensor::Vx,
			i @ 3...4 if i < 4 => Sensor::Vy,
			i @ 4...5 if i < 5 => Sensor::O,
			i @ 5...6 if i < 6 => Sensor::W,
			_ => panic!(),
		}
	}
}

#[macro_export]
macro_rules! pick {
    ($total: expr, $( $lower: expr, $upper: expr, $expression: expr),+) => {{
        let mut rng = rand::thread_rng();
		    match rng.gen_range(0, $total) {
            $( i @ $lower...$upper if i < $upper => $expression,)+
			      _ => panic!(),
		    }
    }}
}
<|endoftext|>


<commit_before>// use log::debug;
use async_std::io;
use async_std::task;
use async_std::prelude::*;
use termion::{cursor,clear};
use crate::config::Config;
use crate::common::Result;

enum ScreenKind {
    Full,
    Inline,
}

impl ScreenKind {
    pub fn setup(&self) -> Option<String> {
        let setup = match self {
            Self::Full => format!("{}{}", csi!("?1049h"), cursor::Goto(1,1)),
            // FIXME: This doesn't work if the screen is full
            Self::Inline => "\r".to_string(),
        };

        Some(setup)
    }

    pub fn teardown(&self) -> Option<String> {
        let teardown = match self {
            Self::Full => csi!("?1049l").to_string(),
            Self::Inline => format!(
                "{}{}{}",
                clear::CurrentLine,
                clear::AfterCursor,
                "\r\n"
            ),
        };

        Some(teardown)
    }
}

pub struct Screen<W: io::Write + Send + Unpin + 'static> {
    writer: W,
    kind: ScreenKind,
}

// TODO: Make configurable
impl<W: io::Write + Send + Unpin + 'static> Screen<W> {
    pub async fn new(config: &Config, writer: W) -> Result<Self> {
        let kind = if config.screen.full {
            ScreenKind::Full
        } else {
            ScreenKind::Inline
        };

        let mut screen = Self { writer, kind };

        if let Some(setup) = screen.kind.setup() {
            screen.render(&setup).await?;
        }

        Ok(screen)
    }

    pub async fn render<L: std::fmt::Display>(&mut self, layout: &L) -> Result<()> {
        let rendered = format!(
            "{}{}{}",
            termion::cursor::Hide,
            layout,
            termion::cursor::Show,
        );
        self.writer.write_all(rendered.as_bytes()).await?;
        self.writer.flush().await?;

        Ok(())
    }
}

impl<W: io::Write + Send + Unpin + 'static> Drop for Screen<W> {
    fn drop(&mut self) {
        task::block_on(async {
            if let Some(teardown) = self.kind.teardown() {
                self.render(&teardown).await
                    .expect("Error writing to output");
            }
        });
    }
}
<commit_msg>Ensure inline screen has enough room to print the layout<commit_after>// use log::debug;
use async_std::io;
use async_std::task;
use async_std::prelude::*;
use termion::{cursor,clear};
use crate::config::Config;
use crate::common::Result;

enum ScreenKind {
    Full,
    Inline(usize),
}

impl ScreenKind {
    pub fn setup(&self) -> Option<String> {
        let setup = match self {
            Self::Full => format!("{}{}", csi!("?1049h"), cursor::Goto(1,1)),
            Self::Inline(height) => {
                let room = std::iter::repeat("\n")
                    .take(*height)
                    .collect::<Vec<&str>>()
                    .join("");

                let up = *height as u16;

                format!("{}{}\r", room, cursor::Up(up))
            },
        };

        Some(setup)
    }

    pub fn teardown(&self) -> Option<String> {
        let teardown = match self {
            Self::Full => csi!("?1049l").to_string(),
            Self::Inline(_) => format!(
                "{}{}{}",
                clear::CurrentLine,
                clear::AfterCursor,
                "\r\n"
            ),
        };

        Some(teardown)
    }
}

pub struct Screen<W: io::Write + Send + Unpin + 'static> {
    writer: W,
    kind: ScreenKind,
}

impl<W: io::Write + Send + Unpin + 'static> Screen<W> {
    pub async fn new(config: &Config, writer: W) -> Result<Self> {
        let kind = if config.screen.full {
            ScreenKind::Full
        } else {
            let (_, height) = config.screen.size;
            ScreenKind::Inline(height)
        };

        let mut screen = Self { writer, kind };

        if let Some(setup) = screen.kind.setup() {
            screen.render(&setup).await?;
        }

        Ok(screen)
    }

    pub async fn render<L: std::fmt::Display>(&mut self, layout: &L) -> Result<()> {
        let rendered = format!(
            "{}{}{}",
            termion::cursor::Hide,
            layout,
            termion::cursor::Show,
        );
        self.writer.write_all(rendered.as_bytes()).await?;
        self.writer.flush().await?;

        Ok(())
    }
}

impl<W: io::Write + Send + Unpin + 'static> Drop for Screen<W> {
    fn drop(&mut self) {
        task::block_on(async {
            if let Some(teardown) = self.kind.teardown() {
                self.render(&teardown).await
                    .expect("Error writing to output");
            }
        });
    }
}
<|endoftext|>


<commit_before>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use notify::{self, RecommendedWatcher, Watcher};
use std::fs;
use std::io::Read;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;

pub use luminance::{ProgramError, UniformUpdate};
use luminance::shader::stage;
pub use luminance_gl::gl33::{Program, Uniform};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: &GetUni) -> Result<Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else {
        if let Some(gs) = gs {
          Program::new(None, &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(None, &vs, None, &fs, get_uni)
        }
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn new_program_from_disk<GetUni, T>(tess_path: Option<(PathBuf, PathBuf)>, vs_path: PathBuf, gs_path: Option<PathBuf>, fs_path: PathBuf, get_uni: &GetUni) -> Result<Program<T>, ProgramError>
      where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  // load vertex and fragment shaders first
  let vs = try!(read_stage(vs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
  let fs = try!(read_stage(fs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

  match (tess_path, gs_path) {
    (None, None) => { // no tessellation nor geometry
      Program::new(None, &vs, None, &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), None) => { // tessellation without geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
    },
    (None, Some(gs_path)) => { // geometry without tessellation
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(None, &vs, Some(&gs), &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), Some(gs_path)) => { // tessellation and geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
    }
  }
}

pub fn read_stage<T>(path: PathBuf) -> Result<Stage<T>, StageError> where T: ShaderTypeable {
  info!("\tloading {:?} stage: \x1b[35m{:?}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

/// Add surveillance of a given `Program` by providing the path to all its shaders. When a change
/// occurs, the `Program` gets notified of the change via its `Receiver` channel part.
pub fn monitor_shader(tess: Option<(PathBuf, PathBuf)>, vs: PathBuf, gs: Option<PathBuf>, fs: PathBuf, sx: mpsc::Sender<()>) {
  let (wsx, wrx) = mpsc::channel();
  let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

  // vertex shader
  watcher.watch(vs);

  // fragment shader
  watcher.watch(fs);

  // tessellation, if needed
  if let Some((tcs, tes)) = tess {
    // tessellation control shader
    watcher.watch(tcs);
    // tessellation evaluation shader
    watcher.watch(tes);
  }

  // geometry shader, if needed
  if let Some(gs) = gs {
    watcher.watch(gs);
  }

  // start a new monitoring thread
  let _ = thread::spawn(move || {
    loop {
      if let Ok(notify::Event { path: Some(path), op: Ok(notify::op::WRITE) }) = wrx.recv() {
        deb!("{:?}’s content has changed!", path);
        sx.send(());
      }
    }
  });
}

/// A `Program` wrapped by **ion**.
///
/// That wrapper is used to enable hot-reloading of shader programs.
pub struct WrappedProgram<'a, T> {
  rx: mpsc::Receiver<()>,
  program: Program<T>,
  get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError> + 'a>,
  vs_path: PathBuf,
  fs_path: PathBuf,
  tess_path: Option<(PathBuf, PathBuf)>,
  gs_path: Option<PathBuf>
}

impl<'a, T> WrappedProgram<'a, T> {
  pub fn new<GetUni>(tess_path: Option<(PathBuf, PathBuf)>, vs_path: PathBuf, gs_path: Option<PathBuf>, fs_path: PathBuf, get_uni: GetUni) -> Result<Self, ProgramError>
      where GetUni: 'a + Fn(ProgramProxy) -> Result<T, ProgramError> {
    let program = try!(new_program_from_disk(tess_path.clone(), vs_path.clone(), gs_path.clone(), fs_path.clone(), &get_uni));
    let (sx, rx) = mpsc::channel();

    monitor_shader(tess_path.clone(), vs_path.clone(), gs_path.clone(), fs_path.clone(), sx);

    let wrapped = WrappedProgram {
      rx: rx,
      program: program,
      get_uni: Box::new(get_uni),
      vs_path: vs_path,
      fs_path: fs_path,
      tess_path: tess_path,
      gs_path: gs_path,
    };

    Ok(wrapped)
  }

  fn reload(&mut self) {
    let program = new_program_from_disk(self.tess_path.clone(), self.vs_path.clone(), self.gs_path.clone(), self.fs_path.clone(), &self.get_uni.as_ref());

    match program {
      Ok(program) => {
        self.program = program;
      },
      Err(err) => {
        warn!("reloading program has failed: {:?}", err);
      }
    }
  }

  /// Sync the embedded `Program`.
  pub fn sync(&mut self) {
    if self.rx.try_recv().is_ok() {
    }
  }
}
<commit_msg>NOW… it… should… just work.<commit_after>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use notify::{self, RecommendedWatcher, Watcher};
use std::fs;
use std::io::Read;
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;

pub use luminance::{ProgramError, UniformUpdate};
use luminance::shader::stage;
pub use luminance_gl::gl33::{Program, Uniform};

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: &GetUni) -> Result<Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else {
        if let Some(gs) = gs {
          Program::new(None, &vs, Some(&gs), &fs, get_uni)
        } else {
          Program::new(None, &vs, None, &fs, get_uni)
        }
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn new_program_from_disk<GetUni, T>(tess_path: Option<(PathBuf, PathBuf)>, vs_path: PathBuf, gs_path: Option<PathBuf>, fs_path: PathBuf, get_uni: &GetUni) -> Result<Program<T>, ProgramError>
      where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  // load vertex and fragment shaders first
  let vs = try!(read_stage(vs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
  let fs = try!(read_stage(fs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

  match (tess_path, gs_path) {
    (None, None) => { // no tessellation nor geometry
      Program::new(None, &vs, None, &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), None) => { // tessellation without geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
    },
    (None, Some(gs_path)) => { // geometry without tessellation
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(None, &vs, Some(&gs), &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), Some(gs_path)) => { // tessellation and geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
    }
  }
}

pub fn read_stage<T>(path: PathBuf) -> Result<Stage<T>, StageError> where T: ShaderTypeable {
  info!("\tloading {:?} stage: \x1b[35m{:?}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

/// Add surveillance of a given `Program` by providing the path to all its shaders. When a change
/// occurs, the `Program` gets notified of the change via its `Receiver` channel part.
pub fn monitor_shader(tess: Option<(PathBuf, PathBuf)>, vs: PathBuf, gs: Option<PathBuf>, fs: PathBuf, sx: mpsc::Sender<()>) {
  let (wsx, wrx) = mpsc::channel();
  let mut watcher: RecommendedWatcher = Watcher::new(wsx).unwrap();

  // vertex shader
  watcher.watch(vs);

  // fragment shader
  watcher.watch(fs);

  // tessellation, if needed
  if let Some((tcs, tes)) = tess {
    // tessellation control shader
    watcher.watch(tcs);
    // tessellation evaluation shader
    watcher.watch(tes);
  }

  // geometry shader, if needed
  if let Some(gs) = gs {
    watcher.watch(gs);
  }

  // start a new monitoring thread
  let _ = thread::spawn(move || {
    loop {
      if let Ok(notify::Event { path: Some(path), op: Ok(notify::op::WRITE) }) = wrx.recv() {
        deb!("{:?}’s content has changed!", path);
        sx.send(());
      }
    }
  });
}

/// A `Program` wrapped by **ion**.
///
/// That wrapper is used to enable hot-reloading of shader programs.
pub struct WrappedProgram<'a, T> {
  rx: mpsc::Receiver<()>,
  program: Program<T>,
  get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError> + 'a>,
  vs_path: PathBuf,
  fs_path: PathBuf,
  tess_path: Option<(PathBuf, PathBuf)>,
  gs_path: Option<PathBuf>
}

impl<'a, T> WrappedProgram<'a, T> {
  pub fn new<GetUni>(tess_path: Option<(PathBuf, PathBuf)>, vs_path: PathBuf, gs_path: Option<PathBuf>, fs_path: PathBuf, get_uni: GetUni) -> Result<Self, ProgramError>
      where GetUni: 'a + Fn(ProgramProxy) -> Result<T, ProgramError> {
    let program = try!(new_program_from_disk(tess_path.clone(), vs_path.clone(), gs_path.clone(), fs_path.clone(), &get_uni));
    let (sx, rx) = mpsc::channel();

    monitor_shader(tess_path.clone(), vs_path.clone(), gs_path.clone(), fs_path.clone(), sx);

    let wrapped = WrappedProgram {
      rx: rx,
      program: program,
      get_uni: Box::new(get_uni),
      vs_path: vs_path,
      fs_path: fs_path,
      tess_path: tess_path,
      gs_path: gs_path,
    };

    Ok(wrapped)
  }

  fn reload(&mut self) {
    let program = new_program_from_disk(self.tess_path.clone(), self.vs_path.clone(), self.gs_path.clone(), self.fs_path.clone(), &self.get_uni.as_ref());

    match program {
      Ok(program) => {
        self.program = program;
      },
      Err(err) => {
        warn!("reloading program has failed: {:?}", err);
      }
    }
  }

  /// Sync the embedded `Program`.
  pub fn sync(&mut self) {
    if self.rx.try_recv().is_ok() {
      self.reload();
    }
  }
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use std::collections::HashMap;
use std::kinds::marker::ContravariantLifetime;
use std::ptr;
use std::str;

pub struct ProgramHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ProgramHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ProgramHandle<'a> {
    let gl_id = unsafe {
      gl::CreateProgram()
    };

    assert!(gl_id != 0);

    ProgramHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ProgramHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteProgram(self.gl_id);
    }
  }
}

pub struct ShaderHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ShaderHandle<'a> {
  pub fn compile_from(
    _gl: &'a GLContextExistence,
    shader_source: String,
    typ: GLenum
  ) -> ShaderHandle<'a> {
    let gl_id = unsafe {
      gl::CreateShader(typ)
    };

    assert!(gl_id != 0);

    // Attempt to compile the shader
    shader_source.with_c_str(|ptr| unsafe { gl::ShaderSource(gl_id, 1, &ptr, ptr::null()) });
    unsafe {
      gl::CompileShader(gl_id);
    }

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      unsafe {
        gl::GetShaderiv(gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetShaderInfoLog(gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("error compiling 0x{:x} shader: {}", typ, str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
    }

    ShaderHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ShaderHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteShader(self.gl_id);
    }
  }
}

pub struct Shader<'a> {
  pub handle: ProgramHandle<'a>,
  pub components: Vec<ShaderHandle<'a>>,
  pub uniforms: HashMap<String, GLint>,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> Shader<'a> {
  pub fn new<T: Iterator<(String, GLenum)>>(
    gl: &'a GLContextExistence,
    mut shader_components: T,
  ) -> Shader<'a> {
    let handle = ProgramHandle::new(gl);

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = ShaderHandle::compile_from(gl, content, component);
      unsafe {
        gl::AttachShader(handle.gl_id, s.gl_id);
      }
      components.push(s);
    }

    unsafe {
      gl::LinkProgram(handle.gl_id);
    }

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(handle.gl_id, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      unsafe {
        gl::GetProgramiv(handle.gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetProgramInfoLog(handle.gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      handle: handle,
      components: components,
      uniforms: HashMap::new(),
      lifetime: ContravariantLifetime,
    }
  }

  pub fn use_shader(&self, _gl: &mut GLContext) {
    unsafe {
      gl::UseProgram(self.handle.gl_id)
    }
  }

  pub fn get_uniform_location(
    &mut self,
    name: &'static str,
  ) -> GLint {
    let s_name = String::from_str(name);
    let c_name = name.to_c_str();
    let p_name = c_name.as_ptr();
    match self.uniforms.get(&s_name) {
      None => {
        let loc = unsafe {
          gl::GetUniformLocation(self.handle.gl_id, p_name)
        };
        assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

        self.uniforms.insert(s_name, loc);
        loc
      },
      Some(&loc) => loc,
    }
  }
}
<commit_msg>Use HashMap::entry to avoid an extra lookup<commit_after>use gl;
use gl::types::*;
use gl_context::{GLContext, GLContextExistence};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::kinds::marker::ContravariantLifetime;
use std::ptr;
use std::str;

pub struct ProgramHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ProgramHandle<'a> {
  pub fn new(_gl: &'a GLContextExistence) -> ProgramHandle<'a> {
    let gl_id = unsafe {
      gl::CreateProgram()
    };

    assert!(gl_id != 0);

    ProgramHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ProgramHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteProgram(self.gl_id);
    }
  }
}

pub struct ShaderHandle<'a> {
  pub gl_id: GLuint,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> ShaderHandle<'a> {
  pub fn compile_from(
    _gl: &'a GLContextExistence,
    shader_source: String,
    typ: GLenum
  ) -> ShaderHandle<'a> {
    let gl_id = unsafe {
      gl::CreateShader(typ)
    };

    assert!(gl_id != 0);

    // Attempt to compile the shader
    shader_source.with_c_str(|ptr| unsafe { gl::ShaderSource(gl_id, 1, &ptr, ptr::null()) });
    unsafe {
      gl::CompileShader(gl_id);
    }

    // Get the compile status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetShaderiv(gl_id, gl::COMPILE_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len = 0;
      unsafe {
        gl::GetShaderiv(gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetShaderInfoLog(gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("error compiling 0x{:x} shader: {}", typ, str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
    }

    ShaderHandle {
      gl_id: gl_id,
      lifetime: ContravariantLifetime,
    }
  }
}

#[unsafe_destructor]
impl<'a> Drop for ShaderHandle<'a> {
  fn drop(&mut self) {
    unsafe {
      gl::DeleteShader(self.gl_id);
    }
  }
}

pub struct Shader<'a> {
  pub handle: ProgramHandle<'a>,
  pub components: Vec<ShaderHandle<'a>>,
  pub uniforms: HashMap<String, GLint>,
  pub lifetime: ContravariantLifetime<'a>,
}

impl<'a> Shader<'a> {
  pub fn new<T: Iterator<(String, GLenum)>>(
    gl: &'a GLContextExistence,
    mut shader_components: T,
  ) -> Shader<'a> {
    let handle = ProgramHandle::new(gl);

    let mut components = Vec::new();
    for (content, component) in shader_components {
      let s = ShaderHandle::compile_from(gl, content, component);
      unsafe {
        gl::AttachShader(handle.gl_id, s.gl_id);
      }
      components.push(s);
    }

    unsafe {
      gl::LinkProgram(handle.gl_id);
    }

    // Get the link status
    let mut status = gl::FALSE as GLint;
    unsafe {
      gl::GetProgramiv(handle.gl_id, gl::LINK_STATUS, &mut status);
    }

    // Fail on error
    if status != (gl::TRUE as GLint) {
      let mut len: GLint = 0;
      unsafe {
        gl::GetProgramiv(handle.gl_id, gl::INFO_LOG_LENGTH, &mut len);
      }
      let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
      unsafe {
        gl::GetProgramInfoLog(handle.gl_id, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
      }
      panic!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
    }

    Shader {
      handle: handle,
      components: components,
      uniforms: HashMap::new(),
      lifetime: ContravariantLifetime,
    }
  }

  pub fn use_shader(&self, _gl: &mut GLContext) {
    unsafe {
      gl::UseProgram(self.handle.gl_id)
    }
  }

  pub fn get_uniform_location(
    &mut self,
    name: &'static str,
  ) -> GLint {
    let s_name = String::from_str(name);
    // TODO: This shouldn't require a clone.
    match self.uniforms.entry(s_name.clone()) {
      Entry::Occupied(entry) => *entry.get(),
      Entry::Vacant(entry) => {
        let c_name = name.to_c_str();
        let p_name = c_name.as_ptr();
        let loc = unsafe {
          gl::GetUniformLocation(self.handle.gl_id, p_name)
        };
        assert!(loc != -1, "couldn't find shader uniform: {}", s_name);

        *entry.set(loc)
      },
    }
  }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::fmt;
use std::i32;
use std::ops::{Add, Deref, Sub};

/// Game version.
#[derive(Debug, PartialEq, Eq, Clone, Ord, PartialOrd)]
pub enum Version {
    /// Action SuperCross, older version of Elma.
    Across,
    /// Elasto Mania, current active version.
    Elma,
}

impl Default for Version {
    fn default() -> Version {
        Version::Elma
    }
}

/// Picture clipping.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum Clip {
    /// No clipping.
    Unclipped = 0,
    /// Ground clipping.
    Ground = 1,
    /// Sky clipping.
    Sky = 2,
}

impl Default for Clip {
    fn default() -> Clip {
        Clip::Sky
    }
}

/// Best times struct.
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct BestTimes {
    /// Single-player times.
    pub single: Vec<TimeEntry>,
    /// Multi-player times.
    pub multi: Vec<TimeEntry>,
}

impl BestTimes {
    /// Create a new best times struct.
    pub fn new() -> Self {
        Self::default()
    }
}

/// Wrapper for time in hundredths.
/// Supports add/sub ops.
///
/// # Examples
///
/// ```rust
/// # use elma::Time;
/// let time_x = Time(100); // 1 second
/// let time_y = Time::from("00:00,01"); // 1 hundredth
///
/// assert_eq!(Time::from("0..,0:099"), time_x - time_y); // from string impl allows somewhat malformed input
/// assert_eq!("01:20,00", Time(8000).to_string()); // .to_string() pretty prints in 00:00,00 format
/// ```
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Time(pub i32);

impl Time {
    /// Returns a tuple with `negative?`, `hours`, `mins`, `secs`, `hundredths`.
    pub fn to_parts(self) -> (bool, i32, i32, i32, i32) {
        let h = self.0 % 100;
        let s = (self.0 / 100) % 60;
        let m = (self.0 / (100 * 60)) % 60;
        let hr = self.0 / (100 * 60 * 60);
        let neg = self.0 < 0;
        (neg, hr.abs(), m.abs(), s.abs(), h.abs())
    }

    /// Creates a `Time` struct from a string
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use elma::Time;
    /// let time = Time::from("00:00,01");
    /// ```
    pub fn from(s: &str) -> Self {
        let parts: Vec<_> = s.split(|c: char| !c.is_numeric())
            .filter(|s| !s.is_empty())
            .map(|s| s.parse::<i32>().unwrap())
            .collect();
        let mut time = 0;
        for (n, val) in parts.iter().rev().enumerate() {
            match n {
                n if n == 0 => time += val,
                n if n == 1 => time += val * 100,
                n if n == 2 => time += val * 6000,
                n if n == 3 => time += val * 360_000,
                n if n == 4 => time += val * 8_640_000,
                _ => time = time.saturating_add(i32::MAX),
            }
        }
        if s.starts_with('-') {
            time *= -1
        }
        Time(time)
    }
}

impl From<i32> for Time {
    fn from(i: i32) -> Self {
        Time(i)
    }
}

impl Add for Time {
    type Output = Time;

    fn add(self, other: Self) -> Self {
        Time(self.0 + other.0)
    }
}

impl Sub for Time {
    type Output = Time;

    fn sub(self, other: Self) -> Self {
        Time(self.0 - other.0)
    }
}

impl From<Time> for i32 {
    fn from(t: Time) -> Self {
        t.0
    }
}

impl Deref for Time {
    type Target = i32;

    fn deref(&self) -> &i32 {
        &self.0
    }
}

impl fmt::Display for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let h = self.0 % 100;
        let s = (self.0 / 100) % 60;
        let m = (self.0 / (100 * 60)) % 60;
        let hr = self.0 / (100 * 60 * 60);

        write!(
            f,
            "{}{}{:02}:{:02},{:02}",
            if self.0 < 0 { "-" } else { "" },
            if hr > 0 {
                format!("{:02}:", hr)
            } else {
                "".into()
            },
            m,
            s,
            h
        )
    }
}

/// Shared position struct used in both sub-modules.
///
/// # Examples
/// ```
/// let vertex = elma::Position { x: 23.1928_f64, y: -199.200019_f64 };
/// ```
#[derive(Debug, Default, PartialEq)]
pub struct Position<T> {
    /// X-position.
    pub x: T,
    /// Y-position.
    pub y: T,
}

/// Top10 list entry struct.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TimeEntry {
    /// Player names.
    pub names: (String, String),
    /// Time.
    pub time: Time,
}

impl Ord for TimeEntry {
    fn cmp(&self, other: &Self) -> Ordering {
        self.time.cmp(&other.time)
    }
}

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

impl TimeEntry {
    /// Creates a new TimeEntry.
    pub fn new<T: Into<Time>, S: Into<String>>(names: (S, S), time: T) -> Self {
        TimeEntry {
            names: (names.0.into(), names.1.into()),
            time: time.into(),
        }
    }
}
<commit_msg>Derive Clone for Position<commit_after>use std::cmp::Ordering;
use std::fmt;
use std::i32;
use std::ops::{Add, Deref, Sub};

/// Game version.
#[derive(Debug, PartialEq, Eq, Clone, Ord, PartialOrd)]
pub enum Version {
    /// Action SuperCross, older version of Elma.
    Across,
    /// Elasto Mania, current active version.
    Elma,
}

impl Default for Version {
    fn default() -> Version {
        Version::Elma
    }
}

/// Picture clipping.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub enum Clip {
    /// No clipping.
    Unclipped = 0,
    /// Ground clipping.
    Ground = 1,
    /// Sky clipping.
    Sky = 2,
}

impl Default for Clip {
    fn default() -> Clip {
        Clip::Sky
    }
}

/// Best times struct.
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct BestTimes {
    /// Single-player times.
    pub single: Vec<TimeEntry>,
    /// Multi-player times.
    pub multi: Vec<TimeEntry>,
}

impl BestTimes {
    /// Create a new best times struct.
    pub fn new() -> Self {
        Self::default()
    }
}

/// Wrapper for time in hundredths.
/// Supports add/sub ops.
///
/// # Examples
///
/// ```rust
/// # use elma::Time;
/// let time_x = Time(100); // 1 second
/// let time_y = Time::from("00:00,01"); // 1 hundredth
///
/// assert_eq!(Time::from("0..,0:099"), time_x - time_y); // from string impl allows somewhat malformed input
/// assert_eq!("01:20,00", Time(8000).to_string()); // .to_string() pretty prints in 00:00,00 format
/// ```
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct Time(pub i32);

impl Time {
    /// Returns a tuple with `negative?`, `hours`, `mins`, `secs`, `hundredths`.
    pub fn to_parts(self) -> (bool, i32, i32, i32, i32) {
        let h = self.0 % 100;
        let s = (self.0 / 100) % 60;
        let m = (self.0 / (100 * 60)) % 60;
        let hr = self.0 / (100 * 60 * 60);
        let neg = self.0 < 0;
        (neg, hr.abs(), m.abs(), s.abs(), h.abs())
    }

    /// Creates a `Time` struct from a string
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use elma::Time;
    /// let time = Time::from("00:00,01");
    /// ```
    pub fn from(s: &str) -> Self {
        let parts: Vec<_> = s.split(|c: char| !c.is_numeric())
            .filter(|s| !s.is_empty())
            .map(|s| s.parse::<i32>().unwrap())
            .collect();
        let mut time = 0;
        for (n, val) in parts.iter().rev().enumerate() {
            match n {
                n if n == 0 => time += val,
                n if n == 1 => time += val * 100,
                n if n == 2 => time += val * 6000,
                n if n == 3 => time += val * 360_000,
                n if n == 4 => time += val * 8_640_000,
                _ => time = time.saturating_add(i32::MAX),
            }
        }
        if s.starts_with('-') {
            time *= -1
        }
        Time(time)
    }
}

impl From<i32> for Time {
    fn from(i: i32) -> Self {
        Time(i)
    }
}

impl Add for Time {
    type Output = Time;

    fn add(self, other: Self) -> Self {
        Time(self.0 + other.0)
    }
}

impl Sub for Time {
    type Output = Time;

    fn sub(self, other: Self) -> Self {
        Time(self.0 - other.0)
    }
}

impl From<Time> for i32 {
    fn from(t: Time) -> Self {
        t.0
    }
}

impl Deref for Time {
    type Target = i32;

    fn deref(&self) -> &i32 {
        &self.0
    }
}

impl fmt::Display for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let h = self.0 % 100;
        let s = (self.0 / 100) % 60;
        let m = (self.0 / (100 * 60)) % 60;
        let hr = self.0 / (100 * 60 * 60);

        write!(
            f,
            "{}{}{:02}:{:02},{:02}",
            if self.0 < 0 { "-" } else { "" },
            if hr > 0 {
                format!("{:02}:", hr)
            } else {
                "".into()
            },
            m,
            s,
            h
        )
    }
}

/// Shared position struct used in both sub-modules.
///
/// # Examples
/// ```
/// let vertex = elma::Position { x: 23.1928_f64, y: -199.200019_f64 };
/// ```
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Position<T> {
    /// X-position.
    pub x: T,
    /// Y-position.
    pub y: T,
}

/// Top10 list entry struct.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TimeEntry {
    /// Player names.
    pub names: (String, String),
    /// Time.
    pub time: Time,
}

impl Ord for TimeEntry {
    fn cmp(&self, other: &Self) -> Ordering {
        self.time.cmp(&other.time)
    }
}

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

impl TimeEntry {
    /// Creates a new TimeEntry.
    pub fn new<T: Into<Time>, S: Into<String>>(names: (S, S), time: T) -> Self {
        TimeEntry {
            names: (names.0.into(), names.1.into()),
            time: time.into(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint};

use gobject_ffi::{self, GCallback};
use glib_ffi::GQuark;
use source::CallbackGuard;
use translate::ToGlibPtr;

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> u64 {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty()) as u64;
    assert!(handle > 0);
    handle
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<commit_msg>Add stop_emission_by_name()<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint};

use gobject_ffi::{self, GCallback};
use glib_ffi::GQuark;
use object::{IsA, Object};
use source::CallbackGuard;
use translate::ToGlibPtr;

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> u64 {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty()) as u64;
    assert!(handle > 0);
    handle
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<|endoftext|>