<commit_before>use crate::syntax::{
    attrs, error, Api, Atom, Doc, ExternFn, ExternType, Receiver, Ref, Struct, Ty1, Type, Var,
};
use proc_macro2::Ident;
use quote::quote;
use syn::{
    Abi, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType, GenericArgument, Item,
    ItemForeignMod, ItemStruct, Pat, PathArguments, Result, ReturnType, Type as RustType,
};

#[derive(Copy, Clone)]
enum Lang {
    Cxx,
    Rust,
}

pub fn parse_items(items: Vec<Item>) -> Result<Vec<Api>> {
    let mut apis = Vec::new();
    for item in items {
        match item {
            Item::Struct(item) => {
                let strct = parse_struct(item)?;
                apis.push(strct);
            }
            Item::ForeignMod(foreign_mod) => {
                let functions = parse_foreign_mod(foreign_mod)?;
                apis.extend(functions);
            }
            Item::Use(item) => return Err(Error::new_spanned(item, error::USE_NOT_ALLOWED)),
            _ => return Err(Error::new_spanned(item, "unsupported item")),
        }
    }
    Ok(apis)
}

fn parse_struct(item: ItemStruct) -> Result<Api> {
    let generics = &item.generics;
    if !generics.params.is_empty() || generics.where_clause.is_some() {
        let struct_token = item.struct_token;
        let ident = &item.ident;
        let where_clause = &generics.where_clause;
        let span = quote!(#struct_token #ident #generics #where_clause);
        return Err(Error::new_spanned(
            span,
            "struct with generic parameters is not supported yet",
        ));
    }

    let mut doc = Doc::new();
    let mut derives = Vec::new();
    attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
    check_reserved_name(&item.ident)?;
    match item.fields {
        Fields::Named(fields) => Ok(Api::Struct(Struct {
            doc,
            derives,
            struct_token: item.struct_token,
            ident: item.ident,
            fields: fields
                .named
                .into_iter()
                .map(|field| {
                    Ok(Var {
                        ident: field.ident.unwrap(),
                        ty: parse_type(&field.ty)?,
                    })
                })
                .collect::<Result<_>>()?,
        })),
        Fields::Unit => Err(Error::new_spanned(item, "unit structs are not supported")),
        Fields::Unnamed(_) => Err(Error::new_spanned(item, "tuple structs are not supported")),
    }
}

fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result<Vec<Api>> {
    let lang = parse_lang(foreign_mod.abi)?;
    let api_type = match lang {
        Lang::Cxx => Api::CxxType,
        Lang::Rust => Api::RustType,
    };
    let api_function = match lang {
        Lang::Cxx => Api::CxxFunction,
        Lang::Rust => Api::RustFunction,
    };

    let mut items = Vec::new();
    for foreign in &foreign_mod.items {
        match foreign {
            ForeignItem::Type(foreign) => {
                check_reserved_name(&foreign.ident)?;
                let ety = parse_extern_type(foreign)?;
                items.push(api_type(ety));
            }
            ForeignItem::Fn(foreign) => {
                let efn = parse_extern_fn(foreign)?;
                items.push(api_function(efn));
            }
            ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
                let include = foreign.mac.parse_body()?;
                items.push(Api::Include(include));
            }
            _ => return Err(Error::new_spanned(foreign, "unsupported foreign item")),
        }
    }
    Ok(items)
}

fn parse_lang(abi: Abi) -> Result<Lang> {
    let name = match &abi.name {
        Some(name) => name,
        None => {
            return Err(Error::new_spanned(
                abi,
                "ABI name is required, extern \"C\" or extern \"Rust\"",
            ));
        }
    };
    match name.value().as_str() {
        "C" => Ok(Lang::Cxx),
        "Rust" => Ok(Lang::Rust),
        _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
    }
}

fn parse_extern_type(foreign_type: &ForeignItemType) -> Result<ExternType> {
    let doc = attrs::parse_doc(&foreign_type.attrs)?;
    let type_token = foreign_type.type_token;
    let ident = foreign_type.ident.clone();
    Ok(ExternType {
        doc,
        type_token,
        ident,
    })
}

fn parse_extern_fn(foreign_fn: &ForeignItemFn) -> Result<ExternFn> {
    let generics = &foreign_fn.sig.generics;
    if !generics.params.is_empty() || generics.where_clause.is_some() {
        return Err(Error::new_spanned(
            foreign_fn,
            "extern function with generic parameters is not supported yet",
        ));
    }
    if let Some(variadic) = &foreign_fn.sig.variadic {
        return Err(Error::new_spanned(
            variadic,
            "variadic function is not supported yet",
        ));
    }

    let mut receiver = None;
    let mut args = Vec::new();
    for arg in &foreign_fn.sig.inputs {
        match arg {
            FnArg::Receiver(receiver) => {
                return Err(Error::new_spanned(receiver, "unsupported signature"))
            }
            FnArg::Typed(arg) => {
                let ident = match arg.pat.as_ref() {
                    Pat::Ident(pat) => pat.ident.clone(),
                    _ => return Err(Error::new_spanned(arg, "unsupported signature")),
                };
                let ty = parse_type(&arg.ty)?;
                if ident != "self" {
                    args.push(Var { ident, ty });
                    continue;
                }
                if let Type::Ref(reference) = ty {
                    if let Type::Ident(ident) = reference.inner {
                        receiver = Some(Receiver {
                            mutability: reference.mutability,
                            ident,
                        });
                        continue;
                    }
                }
                return Err(Error::new_spanned(arg, "unsupported method receiver"));
            }
        }
    }
    let ret = match &foreign_fn.sig.output {
        ReturnType::Default => None,
        ReturnType::Type(_, ty) => Some(parse_type(ty)?),
    };
    let doc = attrs::parse_doc(&foreign_fn.attrs)?;
    let fn_token = foreign_fn.sig.fn_token;
    let ident = foreign_fn.sig.ident.clone();
    let semi_token = foreign_fn.semi_token;
    Ok(ExternFn {
        doc,
        fn_token,
        ident,
        receiver,
        args,
        ret,
        semi_token,
    })
}

fn parse_type(ty: &RustType) -> Result<Type> {
    match &ty {
        RustType::Reference(ty) => {
            let inner = parse_type(&ty.elem)?;
            let which = match &inner {
                Type::Ident(ident) if ident == "str" => {
                    if ty.mutability.is_some() {
                        return Err(Error::new_spanned(ty, "unsupported type"));
                    } else {
                        Type::Str
                    }
                }
                _ => Type::Ref,
            };
            return Ok(which(Box::new(Ref {
                ampersand: ty.and_token,
                mutability: ty.mutability,
                inner,
            })));
        }
        RustType::Path(ty) => {
            let path = &ty.path;
            if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
                let segment = &path.segments[0];
                let ident = segment.ident.clone();
                match &segment.arguments {
                    PathArguments::None => return Ok(Type::Ident(ident)),
                    PathArguments::AngleBracketed(generic) => {
                        if ident == "UniquePtr" && generic.args.len() == 1 {
                            if let GenericArgument::Type(arg) = &generic.args[0] {
                                let inner = parse_type(arg)?;
                                return Ok(Type::UniquePtr(Box::new(Ty1 {
                                    name: ident,
                                    langle: generic.lt_token,
                                    inner,
                                    rangle: generic.gt_token,
                                })));
                            }
                        } else if ident == "Box" && generic.args.len() == 1 {
                            if let GenericArgument::Type(arg) = &generic.args[0] {
                                let inner = parse_type(arg)?;
                                return Ok(Type::RustBox(Box::new(Ty1 {
                                    name: ident,
                                    langle: generic.lt_token,
                                    inner,
                                    rangle: generic.gt_token,
                                })));
                            }
                        }
                    }
                    PathArguments::Parenthesized(_) => {}
                }
            }
        }
        RustType::Tuple(ty) if ty.elems.is_empty() => {
            return Ok(Type::Void(ty.paren_token.span));
        }
        _ => {}
    }
    Err(Error::new_spanned(ty, "unsupported type"))
}

fn check_reserved_name(ident: &Ident) -> Result<()> {
    if ident == "Box" || ident == "UniquePtr" || Atom::from(ident).is_some() {
        Err(Error::new(ident.span(), "reserved name"))
    } else {
        Ok(())
    }
}
<commit_msg>Ignore Void in return position<commit_after>use crate::syntax::{
    attrs, error, Api, Atom, Doc, ExternFn, ExternType, Receiver, Ref, Struct, Ty1, Type, Var,
};
use proc_macro2::Ident;
use quote::quote;
use syn::{
    Abi, Error, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType, GenericArgument, Item,
    ItemForeignMod, ItemStruct, Pat, PathArguments, Result, ReturnType, Type as RustType,
};

#[derive(Copy, Clone)]
enum Lang {
    Cxx,
    Rust,
}

pub fn parse_items(items: Vec<Item>) -> Result<Vec<Api>> {
    let mut apis = Vec::new();
    for item in items {
        match item {
            Item::Struct(item) => {
                let strct = parse_struct(item)?;
                apis.push(strct);
            }
            Item::ForeignMod(foreign_mod) => {
                let functions = parse_foreign_mod(foreign_mod)?;
                apis.extend(functions);
            }
            Item::Use(item) => return Err(Error::new_spanned(item, error::USE_NOT_ALLOWED)),
            _ => return Err(Error::new_spanned(item, "unsupported item")),
        }
    }
    Ok(apis)
}

fn parse_struct(item: ItemStruct) -> Result<Api> {
    let generics = &item.generics;
    if !generics.params.is_empty() || generics.where_clause.is_some() {
        let struct_token = item.struct_token;
        let ident = &item.ident;
        let where_clause = &generics.where_clause;
        let span = quote!(#struct_token #ident #generics #where_clause);
        return Err(Error::new_spanned(
            span,
            "struct with generic parameters is not supported yet",
        ));
    }

    let mut doc = Doc::new();
    let mut derives = Vec::new();
    attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
    check_reserved_name(&item.ident)?;
    match item.fields {
        Fields::Named(fields) => Ok(Api::Struct(Struct {
            doc,
            derives,
            struct_token: item.struct_token,
            ident: item.ident,
            fields: fields
                .named
                .into_iter()
                .map(|field| {
                    Ok(Var {
                        ident: field.ident.unwrap(),
                        ty: parse_type(&field.ty)?,
                    })
                })
                .collect::<Result<_>>()?,
        })),
        Fields::Unit => Err(Error::new_spanned(item, "unit structs are not supported")),
        Fields::Unnamed(_) => Err(Error::new_spanned(item, "tuple structs are not supported")),
    }
}

fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result<Vec<Api>> {
    let lang = parse_lang(foreign_mod.abi)?;
    let api_type = match lang {
        Lang::Cxx => Api::CxxType,
        Lang::Rust => Api::RustType,
    };
    let api_function = match lang {
        Lang::Cxx => Api::CxxFunction,
        Lang::Rust => Api::RustFunction,
    };

    let mut items = Vec::new();
    for foreign in &foreign_mod.items {
        match foreign {
            ForeignItem::Type(foreign) => {
                check_reserved_name(&foreign.ident)?;
                let ety = parse_extern_type(foreign)?;
                items.push(api_type(ety));
            }
            ForeignItem::Fn(foreign) => {
                let efn = parse_extern_fn(foreign)?;
                items.push(api_function(efn));
            }
            ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
                let include = foreign.mac.parse_body()?;
                items.push(Api::Include(include));
            }
            _ => return Err(Error::new_spanned(foreign, "unsupported foreign item")),
        }
    }
    Ok(items)
}

fn parse_lang(abi: Abi) -> Result<Lang> {
    let name = match &abi.name {
        Some(name) => name,
        None => {
            return Err(Error::new_spanned(
                abi,
                "ABI name is required, extern \"C\" or extern \"Rust\"",
            ));
        }
    };
    match name.value().as_str() {
        "C" => Ok(Lang::Cxx),
        "Rust" => Ok(Lang::Rust),
        _ => Err(Error::new_spanned(abi, "unrecognized ABI")),
    }
}

fn parse_extern_type(foreign_type: &ForeignItemType) -> Result<ExternType> {
    let doc = attrs::parse_doc(&foreign_type.attrs)?;
    let type_token = foreign_type.type_token;
    let ident = foreign_type.ident.clone();
    Ok(ExternType {
        doc,
        type_token,
        ident,
    })
}

fn parse_extern_fn(foreign_fn: &ForeignItemFn) -> Result<ExternFn> {
    let generics = &foreign_fn.sig.generics;
    if !generics.params.is_empty() || generics.where_clause.is_some() {
        return Err(Error::new_spanned(
            foreign_fn,
            "extern function with generic parameters is not supported yet",
        ));
    }
    if let Some(variadic) = &foreign_fn.sig.variadic {
        return Err(Error::new_spanned(
            variadic,
            "variadic function is not supported yet",
        ));
    }

    let mut receiver = None;
    let mut args = Vec::new();
    for arg in &foreign_fn.sig.inputs {
        match arg {
            FnArg::Receiver(receiver) => {
                return Err(Error::new_spanned(receiver, "unsupported signature"))
            }
            FnArg::Typed(arg) => {
                let ident = match arg.pat.as_ref() {
                    Pat::Ident(pat) => pat.ident.clone(),
                    _ => return Err(Error::new_spanned(arg, "unsupported signature")),
                };
                let ty = parse_type(&arg.ty)?;
                if ident != "self" {
                    args.push(Var { ident, ty });
                    continue;
                }
                if let Type::Ref(reference) = ty {
                    if let Type::Ident(ident) = reference.inner {
                        receiver = Some(Receiver {
                            mutability: reference.mutability,
                            ident,
                        });
                        continue;
                    }
                }
                return Err(Error::new_spanned(arg, "unsupported method receiver"));
            }
        }
    }
    let ret = match &foreign_fn.sig.output {
        ReturnType::Default => None,
        ReturnType::Type(_, ty) => match parse_type(ty)? {
            Type::Void(_) => None,
            ty => Some(ty),
        },
    };
    let doc = attrs::parse_doc(&foreign_fn.attrs)?;
    let fn_token = foreign_fn.sig.fn_token;
    let ident = foreign_fn.sig.ident.clone();
    let semi_token = foreign_fn.semi_token;
    Ok(ExternFn {
        doc,
        fn_token,
        ident,
        receiver,
        args,
        ret,
        semi_token,
    })
}

fn parse_type(ty: &RustType) -> Result<Type> {
    match &ty {
        RustType::Reference(ty) => {
            let inner = parse_type(&ty.elem)?;
            let which = match &inner {
                Type::Ident(ident) if ident == "str" => {
                    if ty.mutability.is_some() {
                        return Err(Error::new_spanned(ty, "unsupported type"));
                    } else {
                        Type::Str
                    }
                }
                _ => Type::Ref,
            };
            return Ok(which(Box::new(Ref {
                ampersand: ty.and_token,
                mutability: ty.mutability,
                inner,
            })));
        }
        RustType::Path(ty) => {
            let path = &ty.path;
            if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
                let segment = &path.segments[0];
                let ident = segment.ident.clone();
                match &segment.arguments {
                    PathArguments::None => return Ok(Type::Ident(ident)),
                    PathArguments::AngleBracketed(generic) => {
                        if ident == "UniquePtr" && generic.args.len() == 1 {
                            if let GenericArgument::Type(arg) = &generic.args[0] {
                                let inner = parse_type(arg)?;
                                return Ok(Type::UniquePtr(Box::new(Ty1 {
                                    name: ident,
                                    langle: generic.lt_token,
                                    inner,
                                    rangle: generic.gt_token,
                                })));
                            }
                        } else if ident == "Box" && generic.args.len() == 1 {
                            if let GenericArgument::Type(arg) = &generic.args[0] {
                                let inner = parse_type(arg)?;
                                return Ok(Type::RustBox(Box::new(Ty1 {
                                    name: ident,
                                    langle: generic.lt_token,
                                    inner,
                                    rangle: generic.gt_token,
                                })));
                            }
                        }
                    }
                    PathArguments::Parenthesized(_) => {}
                }
            }
        }
        RustType::Tuple(ty) if ty.elems.is_empty() => {
            return Ok(Type::Void(ty.paren_token.span));
        }
        _ => {}
    }
    Err(Error::new_spanned(ty, "unsupported type"))
}

fn check_reserved_name(ident: &Ident) -> Result<()> {
    if ident == "Box" || ident == "UniquePtr" || Atom::from(ident).is_some() {
        Err(Error::new(ident.span(), "reserved name"))
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

/*!
Syntax extension to create floating point literals from hexadecimal strings

Once loaded, hexfloat!() is called with a string containing the hexadecimal
floating-point literal, and an optional type (f32 or f64).
If the type is omitted, the literal is treated the same as a normal unsuffixed
literal.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate hexfloat;

fn main() {
    let val = hexfloat!("0x1.ffffb4", f32);
}
```

# References

* [ExploringBinary: hexadecimal floating point constants]
  (http://www.exploringbinary.com/hexadecimal-floating-point-constants/)

*/

#![crate_name = "hexfloat"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use rustc::plugin::Registry;

use std::gc::Gc;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("hexfloat", expand_syntax_ext);
}

//Check if the literal is valid (as LLVM expects),
//and return a descriptive error if not.
fn hex_float_lit_err(s: &str) -> Option<(uint, String)> {
    let mut chars = s.chars().peekable();
    let mut i = 0;
    if chars.peek() == Some(&'-') { chars.next(); i+= 1 }
    if chars.next() != Some('0') {
        return Some((i, "Expected '0'".to_string()));
    } i+=1;
    if chars.next() != Some('x') {
        return Some((i, "Expected 'x'".to_string()));
    } i+=1;
    let mut d_len = 0i;
    for _ in chars.take_while(|c| c.is_digit_radix(16)) { chars.next(); i+=1; d_len += 1;}
    if chars.next() != Some('.') {
        return Some((i, "Expected '.'".to_string()));
    } i+=1;
    let mut f_len = 0i;
    for _ in chars.take_while(|c| c.is_digit_radix(16)) { chars.next(); i+=1; f_len += 1;}
    if d_len == 0 && f_len == 0 {
        return Some((i, "Expected digits before or after decimal \
                         point".to_string()));
    }
    if chars.next() != Some('p') {
        return Some((i, "Expected 'p'".to_string()));
    } i+=1;
    if chars.peek() == Some(&'-') { chars.next(); i+= 1 }
    let mut e_len = 0i;
    for _ in chars.take_while(|c| c.is_digit()) { chars.next(); i+=1; e_len += 1}
    if e_len == 0 {
        return Some((i, "Expected exponent digits".to_string()));
    }
    match chars.next() {
        None => None,
        Some(_) => Some((i, "Expected end of string".to_string()))
    }
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, ty_lit) = parse_tts(cx, tts);

    let ty = match ty_lit {
        None => None,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "f32" => Some(ast::TyF32),
            "f64" => Some(ast::TyF64),
            _ => {
                cx.span_err(span, "invalid floating point type in hexfloat!");
                None
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                s.clone()
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in hexfloat!");
                return base::DummyResult::expr(sp);
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in hexfloat!");
            return base::DummyResult::expr(sp);
        }
    };

    {
        let err = hex_float_lit_err(s.get());
        match err {
            Some((err_pos, err_str)) => {
                let pos = expr.span.lo + syntax::codemap::Pos::from_uint(err_pos + 1);
                let span = syntax::codemap::mk_sp(pos,pos);
                cx.span_err(span,
                            format!("invalid hex float literal in hexfloat!: \
                                     {}",
                                    err_str).as_slice());
                return base::DummyResult::expr(sp);
            }
            _ => ()
        }
    }

    let lit = match ty {
        None => ast::LitFloatUnsuffixed(s),
        Some (ty) => ast::LitFloat(s, ty)
    };
    MacExpr::new(cx.expr_lit(sp, lit))
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>hexfloat: Deprecate to move out of the repo<commit_after>// Copyright 2014 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.

/*!
Syntax extension to create floating point literals from hexadecimal strings

Once loaded, hexfloat!() is called with a string containing the hexadecimal
floating-point literal, and an optional type (f32 or f64).
If the type is omitted, the literal is treated the same as a normal unsuffixed
literal.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate hexfloat;

fn main() {
    let val = hexfloat!("0x1.ffffb4", f32);
}
```

# References

* [ExploringBinary: hexadecimal floating point constants]
  (http://www.exploringbinary.com/hexadecimal-floating-point-constants/)

*/

#![crate_name = "hexfloat"]
#![deprecated = "This is now a cargo package located at: \
                 https://github.com/rust-lang/hexfloat"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use rustc::plugin::Registry;

use std::gc::Gc;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("hexfloat", expand_syntax_ext);
}

//Check if the literal is valid (as LLVM expects),
//and return a descriptive error if not.
fn hex_float_lit_err(s: &str) -> Option<(uint, String)> {
    let mut chars = s.chars().peekable();
    let mut i = 0;
    if chars.peek() == Some(&'-') { chars.next(); i+= 1 }
    if chars.next() != Some('0') {
        return Some((i, "Expected '0'".to_string()));
    } i+=1;
    if chars.next() != Some('x') {
        return Some((i, "Expected 'x'".to_string()));
    } i+=1;
    let mut d_len = 0i;
    for _ in chars.take_while(|c| c.is_digit_radix(16)) { chars.next(); i+=1; d_len += 1;}
    if chars.next() != Some('.') {
        return Some((i, "Expected '.'".to_string()));
    } i+=1;
    let mut f_len = 0i;
    for _ in chars.take_while(|c| c.is_digit_radix(16)) { chars.next(); i+=1; f_len += 1;}
    if d_len == 0 && f_len == 0 {
        return Some((i, "Expected digits before or after decimal \
                         point".to_string()));
    }
    if chars.next() != Some('p') {
        return Some((i, "Expected 'p'".to_string()));
    } i+=1;
    if chars.peek() == Some(&'-') { chars.next(); i+= 1 }
    let mut e_len = 0i;
    for _ in chars.take_while(|c| c.is_digit()) { chars.next(); i+=1; e_len += 1}
    if e_len == 0 {
        return Some((i, "Expected exponent digits".to_string()));
    }
    match chars.next() {
        None => None,
        Some(_) => Some((i, "Expected end of string".to_string()))
    }
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, ty_lit) = parse_tts(cx, tts);

    let ty = match ty_lit {
        None => None,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "f32" => Some(ast::TyF32),
            "f64" => Some(ast::TyF64),
            _ => {
                cx.span_err(span, "invalid floating point type in hexfloat!");
                None
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                s.clone()
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in hexfloat!");
                return base::DummyResult::expr(sp);
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in hexfloat!");
            return base::DummyResult::expr(sp);
        }
    };

    {
        let err = hex_float_lit_err(s.get());
        match err {
            Some((err_pos, err_str)) => {
                let pos = expr.span.lo + syntax::codemap::Pos::from_uint(err_pos + 1);
                let span = syntax::codemap::mk_sp(pos,pos);
                cx.span_err(span,
                            format!("invalid hex float literal in hexfloat!: \
                                     {}",
                                    err_str).as_slice());
                return base::DummyResult::expr(sp);
            }
            _ => ()
        }
    }

    let lit = match ty {
        None => ast::LitFloatUnsuffixed(s),
        Some (ty) => ast::LitFloat(s, ty)
    };
    MacExpr::new(cx.expr_lit(sp, lit))
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
    let p = &mut cx.new_parser_from_tts(tts);
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let target = env::var("TARGET").expect("TARGET was not set");

    if cfg!(feature = "llvm-libunwind") &&
        ((target.contains("linux") && !target.contains("musl")) ||
         target.contains("fuchsia")) {
        // Build the unwinding from libunwind C/C++ source code.
        llvm_libunwind::compile();
    } else if target.contains("linux") {
        if target.contains("musl") {
            // linking for musl is handled in lib.rs
            llvm_libunwind::compile();
        } else if !target.contains("android") {
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("rumprun") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("netbsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("openbsd") {
        if target.contains("sparc64") {
            println!("cargo:rustc-link-lib=gcc");
        } else {
            println!("cargo:rustc-link-lib=c++abi");
        }
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") {
        println!("cargo:rustc-link-lib=gcc_pic");
    } else if target.contains("pc-windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    } else if target.contains("uwp-windows-gnu") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("haiku") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("redox") {
        // redox is handled in lib.rs
    } else if target.contains("hermit") {
        //println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("cloudabi") {
        println!("cargo:rustc-link-lib=unwind");
    }
}

mod llvm_libunwind {
    use std::env;
    use std::path::Path;

    /// Compile the libunwind C/C++ source code.
    pub fn compile() {
        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
        let cfg = &mut cc::Build::new();

        cfg.cpp(true);
        cfg.cpp_set_stdlib(None);
        cfg.warnings(false);

        if target_env == "msvc" {
            // Don't pull in extra libraries on MSVC
            cfg.flag("/Zl");
            cfg.flag("/EHsc");
            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
        } else {
            cfg.flag("-std=c99");
            cfg.flag("-std=c++11");
            cfg.flag("-nostdinc++");
            cfg.flag("-fno-exceptions");
            cfg.flag("-fno-rtti");
            cfg.flag("-fstrict-aliasing");
            cfg.flag("-funwind-tables");
        }

        let mut unwind_sources = vec![
            "Unwind-EHABI.cpp",
            "Unwind-seh.cpp",
            "Unwind-sjlj.c",
            "UnwindLevel1-gcc-ext.c",
            "UnwindLevel1.c",
            "UnwindRegistersRestore.S",
            "UnwindRegistersSave.S",
            "libunwind.cpp",
        ];

        if target_vendor == "apple" {
            unwind_sources.push("Unwind_AppleExtras.cpp");
        }

        let root = Path::new("../llvm-project/libunwind");
        cfg.include(root.join("include"));
        for src in unwind_sources {
            cfg.file(root.join("src").join(src));
        }

        if target_env == "musl" {
            // use the same C compiler command to compile C++ code so we do not need to setup the
            // C++ compiler env variables on the builders
            cfg.cpp(false);
            // linking for musl is handled in lib.rs
            cfg.cargo_metadata(false);
            println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
        }

        cfg.compile("unwind");
    }
}
<commit_msg>remove obsolete code<commit_after>use std::env;

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    let target = env::var("TARGET").expect("TARGET was not set");

    if cfg!(feature = "llvm-libunwind") &&
        ((target.contains("linux") && !target.contains("musl")) ||
         target.contains("fuchsia")) {
        // Build the unwinding from libunwind C/C++ source code.
        llvm_libunwind::compile();
    } else if target.contains("linux") {
        if target.contains("musl") {
            // linking for musl is handled in lib.rs
            llvm_libunwind::compile();
        } else if !target.contains("android") {
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("rumprun") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("netbsd") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("openbsd") {
        if target.contains("sparc64") {
            println!("cargo:rustc-link-lib=gcc");
        } else {
            println!("cargo:rustc-link-lib=c++abi");
        }
    } else if target.contains("solaris") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") {
        println!("cargo:rustc-link-lib=gcc_pic");
    } else if target.contains("pc-windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    } else if target.contains("uwp-windows-gnu") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("fuchsia") {
        println!("cargo:rustc-link-lib=unwind");
    } else if target.contains("haiku") {
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("redox") {
        // redox is handled in lib.rs
    } else if target.contains("cloudabi") {
        println!("cargo:rustc-link-lib=unwind");
    }
}

mod llvm_libunwind {
    use std::env;
    use std::path::Path;

    /// Compile the libunwind C/C++ source code.
    pub fn compile() {
        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
        let cfg = &mut cc::Build::new();

        cfg.cpp(true);
        cfg.cpp_set_stdlib(None);
        cfg.warnings(false);

        if target_env == "msvc" {
            // Don't pull in extra libraries on MSVC
            cfg.flag("/Zl");
            cfg.flag("/EHsc");
            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
        } else {
            cfg.flag("-std=c99");
            cfg.flag("-std=c++11");
            cfg.flag("-nostdinc++");
            cfg.flag("-fno-exceptions");
            cfg.flag("-fno-rtti");
            cfg.flag("-fstrict-aliasing");
            cfg.flag("-funwind-tables");
        }

        let mut unwind_sources = vec![
            "Unwind-EHABI.cpp",
            "Unwind-seh.cpp",
            "Unwind-sjlj.c",
            "UnwindLevel1-gcc-ext.c",
            "UnwindLevel1.c",
            "UnwindRegistersRestore.S",
            "UnwindRegistersSave.S",
            "libunwind.cpp",
        ];

        if target_vendor == "apple" {
            unwind_sources.push("Unwind_AppleExtras.cpp");
        }

        let root = Path::new("../llvm-project/libunwind");
        cfg.include(root.join("include"));
        for src in unwind_sources {
            cfg.file(root.join("src").join(src));
        }

        if target_env == "musl" {
            // use the same C compiler command to compile C++ code so we do not need to setup the
            // C++ compiler env variables on the builders
            cfg.cpp(false);
            // linking for musl is handled in lib.rs
            cfg.cargo_metadata(false);
            println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
        }

        cfg.compile("unwind");
    }
}
<|endoftext|>


<commit_before>use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::sync::Arc;
use std::fmt::Debug;

fn rc_refcell() {
    let r = Rc::new(RefCell::new(42));
    let r2 = r.clone();
    *r.borrow_mut() += 10;
    let x = *r2.borrow();
    assert_eq!(x, 52);
}

fn rc_cell() {
    let r = Rc::new(Cell::new(42));
    let r2 = r.clone();
    let x = r.get();
    r2.set(x + x);
    assert_eq!(r.get(), 84);
}

fn rc_refcell2() {
    let r = Rc::new(RefCell::new(42));
    let r2 = r.clone();
    *r.borrow_mut() += 10;
    let x = r2.borrow();
    let r3 = r.clone();
    let y = r3.borrow();
    assert_eq!((*x + *y)/2, 52);
}

fn rc_raw() {
    let r = Rc::new(0);
    let r2 = Rc::into_raw(r.clone());
    let r2 = unsafe { Rc::from_raw(r2) };
    assert!(Rc::ptr_eq(&r, &r2));
    drop(r);
    assert!(Rc::try_unwrap(r2).is_ok());
}

fn arc() {
    fn test() -> Arc<i32> {
        let a = Arc::new(42);
        a
    }
    assert_eq!(*test(), 42);
}

// Make sure this Rc doesn't fall apart when touched
fn check_unique_rc<T: ?Sized>(mut r: Rc<T>) {
    let r2 = r.clone();
    assert!(Rc::get_mut(&mut r).is_none());
    drop(r2);
    assert!(Rc::get_mut(&mut r).is_some());
}

fn rc_from() {
    check_unique_rc::<[_]>(Rc::from(&[1,2,3] as &[_]));
    check_unique_rc::<[_]>(Rc::from(vec![1,2,3]));
    check_unique_rc::<[_]>(Rc::from(Box::new([1,2,3]) as Box<[_]>));
    check_unique_rc::<str>(Rc::from("Hello, World!"));
}

fn rc_fat_ptr_eq() {
    let p = Rc::new(1) as Rc<Debug>;
    let a: *const Debug = &*p;
    let r = Rc::into_raw(p);
    let _b = a == r;
    drop(unsafe { Rc::from_raw(r) });
}

fn main() {
    rc_fat_ptr_eq();
    rc_refcell();
    rc_refcell2();
    rc_cell();
    rc_raw();
    rc_from();
    arc();
}
<commit_msg>actually they should be equal<commit_after>use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::sync::Arc;
use std::fmt::Debug;

fn rc_refcell() {
    let r = Rc::new(RefCell::new(42));
    let r2 = r.clone();
    *r.borrow_mut() += 10;
    let x = *r2.borrow();
    assert_eq!(x, 52);
}

fn rc_cell() {
    let r = Rc::new(Cell::new(42));
    let r2 = r.clone();
    let x = r.get();
    r2.set(x + x);
    assert_eq!(r.get(), 84);
}

fn rc_refcell2() {
    let r = Rc::new(RefCell::new(42));
    let r2 = r.clone();
    *r.borrow_mut() += 10;
    let x = r2.borrow();
    let r3 = r.clone();
    let y = r3.borrow();
    assert_eq!((*x + *y)/2, 52);
}

fn rc_raw() {
    let r = Rc::new(0);
    let r2 = Rc::into_raw(r.clone());
    let r2 = unsafe { Rc::from_raw(r2) };
    assert!(Rc::ptr_eq(&r, &r2));
    drop(r);
    assert!(Rc::try_unwrap(r2).is_ok());
}

fn arc() {
    fn test() -> Arc<i32> {
        let a = Arc::new(42);
        a
    }
    assert_eq!(*test(), 42);
}

// Make sure this Rc doesn't fall apart when touched
fn check_unique_rc<T: ?Sized>(mut r: Rc<T>) {
    let r2 = r.clone();
    assert!(Rc::get_mut(&mut r).is_none());
    drop(r2);
    assert!(Rc::get_mut(&mut r).is_some());
}

fn rc_from() {
    check_unique_rc::<[_]>(Rc::from(&[1,2,3] as &[_]));
    check_unique_rc::<[_]>(Rc::from(vec![1,2,3]));
    check_unique_rc::<[_]>(Rc::from(Box::new([1,2,3]) as Box<[_]>));
    check_unique_rc::<str>(Rc::from("Hello, World!"));
}

fn rc_fat_ptr_eq() {
    let p = Rc::new(1) as Rc<Debug>;
    let a: *const Debug = &*p;
    let r = Rc::into_raw(p);
    assert!(a == r);
    drop(unsafe { Rc::from_raw(r) });
}

fn main() {
    rc_fat_ptr_eq();
    rc_refcell();
    rc_refcell2();
    rc_cell();
    rc_raw();
    rc_from();
    arc();
}
<|endoftext|>


<commit_before>use input::{Event, UpdateArgs};
use ai_behavior::{
    Action,
    State,
    Sequence,
    Success,
    Wait,
    WhenAll,
    While,
};

use test_events::TestActions::{ Inc, Dec };

/// Some test actions.
#[derive(Clone)]
#[allow(dead_code)]
pub enum TestActions {
    /// Increment accumulator.
    Inc,
    /// Decrement accumulator.
    Dec,
}

// A test state machine that can increment and decrement.
fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>) -> u32 {
    let e: Event = UpdateArgs { dt: dt }.into();
    state.event(&e, &mut |args| {
        match *args.action {
            Inc => { acc += 1; (Success, args.dt) },
            Dec => { acc -= 1; (Success, args.dt) },
        }
    });
    acc
}

// Each action that terminates immediately
// consumes a time of 0.0 seconds.
// This makes it possible to execute one action
// after another without delay or waiting for next update.
#[test]
fn print_2() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.0, &mut state);
    assert_eq!(a, 2);
}

// If you wait the exact amount before to execute an action,
// it will execute. This behavior makes it easy to predict
// when an action will run.
#[test]
fn wait_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state);
    assert_eq!(a, 1);
}

// When we execute half the time and then the other half,
// then the action should be executed.
#[test]
fn wait_half_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 1);
}

// A sequence of one event is like a bare event.
#[test]
fn sequence_of_one_event() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state);
    assert_eq!(a, 1);
}

// A sequence of wait events is the same as one wait event.
#[test]
fn wait_two_waits() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state);
    assert_eq!(a, 1);
}

// Increase counter ten times.
#[test]
fn loop_ten_times() {
    let a: u32 = 0;
    let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state);
    assert_eq!(a, 10);
}

#[test]
fn when_all_wait() {
    let a: u32 = 0;
    let all = Sequence(vec![
            // Wait in parallel.
            WhenAll(vec![Wait(0.5), Wait(1.0)]),
            Action(Inc)
        ]);
    let mut state = State::new(all);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 1);
}

#[test]
fn while_wait_sequence() {
    let mut a: u32 = 0;
    let w = While(Box::new(Wait(9.999999)), vec![
        Sequence(vec![
            Wait(0.5),
            Action(Inc),
            Wait(0.5),
            Action(Inc)
        ])
    ]);
    let mut state = State::new(w);
    for _ in 0..100 {
        a = exec(a, 0.1, &mut state);
    }
    // The last increment is never executed, because there is not enough time.
    assert_eq!(a, 19);
}
<commit_msg>Added unit test for `Sequence` in a `While`<commit_after>use input::{Event, UpdateArgs};
use ai_behavior::{
    Action,
    State,
    Sequence,
    Success,
    Wait,
    WaitForever,
    WhenAll,
    While,
};

use test_events::TestActions::{ Inc, Dec };

/// Some test actions.
#[derive(Clone)]
#[allow(dead_code)]
pub enum TestActions {
    /// Increment accumulator.
    Inc,
    /// Decrement accumulator.
    Dec,
}

// A test state machine that can increment and decrement.
fn exec(mut acc: u32, dt: f64, state: &mut State<TestActions, ()>) -> u32 {
    let e: Event = UpdateArgs { dt: dt }.into();
    state.event(&e, &mut |args| {
        match *args.action {
            Inc => { acc += 1; (Success, args.dt) },
            Dec => { acc -= 1; (Success, args.dt) },
        }
    });
    acc
}

// Each action that terminates immediately
// consumes a time of 0.0 seconds.
// This makes it possible to execute one action
// after another without delay or waiting for next update.
#[test]
fn print_2() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.0, &mut state);
    assert_eq!(a, 2);
}

// If you wait the exact amount before to execute an action,
// it will execute. This behavior makes it easy to predict
// when an action will run.
#[test]
fn wait_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state);
    assert_eq!(a, 1);
}

// When we execute half the time and then the other half,
// then the action should be executed.
#[test]
fn wait_half_sec() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(1.0), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 1);
}

// A sequence of one event is like a bare event.
#[test]
fn sequence_of_one_event() {
    let a: u32 = 0;
    let seq = Sequence(vec![Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state);
    assert_eq!(a, 1);
}

// A sequence of wait events is the same as one wait event.
#[test]
fn wait_two_waits() {
    let a: u32 = 0;
    let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]);
    let mut state = State::new(seq);
    let a = exec(a, 1.0, &mut state);
    assert_eq!(a, 1);
}

// Increase counter ten times.
#[test]
fn loop_ten_times() {
    let a: u32 = 0;
    let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]);
    let mut state = State::new(rep);
    let a = exec(a, 10.0, &mut state);
    assert_eq!(a, 10);
}

#[test]
fn when_all_wait() {
    let a: u32 = 0;
    let all = Sequence(vec![
            // Wait in parallel.
            WhenAll(vec![Wait(0.5), Wait(1.0)]),
            Action(Inc)
        ]);
    let mut state = State::new(all);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 0);
    let a = exec(a, 0.5, &mut state);
    assert_eq!(a, 1);
}

#[test]
fn while_wait_sequence() {
    let mut a: u32 = 0;
    let w = While(Box::new(Wait(9.999999)), vec![
        Sequence(vec![
            Wait(0.5),
            Action(Inc),
            Wait(0.5),
            Action(Inc)
        ])
    ]);
    let mut state = State::new(w);
    for _ in 0..100 {
        a = exec(a, 0.1, &mut state);
    }
    // The last increment is never executed, because there is not enough time.
    assert_eq!(a, 19);
}

#[test]
fn while_wait_forever_sequence() {
    let mut a: u32 = 0;
    let w = While(Box::new(WaitForever), vec![
        Sequence(vec![
            Action(Inc),
            Wait(1.0),
        ])
    ]);
    let mut state = State::new(w);
    a = exec(a, 1.001, &mut state);
    assert_eq!(a, 2);
}
<|endoftext|>


<commit_before>
// Copyright 2020 John Hanley.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// The software is provided "AS IS", without warranty of any kind, express or
// implied, including but not limited to the warranties of merchantability,
// fitness for a particular purpose and noninfringement. In no event shall
// the authors or copyright holders be liable for any claim, damages or
// other liability, whether in an action of contract, tort or otherwise,
// arising from, out of or in connection with the software or the use or
// other dealings in the software.

use std::env;
use std::time::Instant;

const MAX_ITER: i32 = 255;  // Rust lacks adequate support for default args.

fn mandelbrot_set(xc: f64, yc: f64, sz: f64, px_resolution: i32) {
    let step = (2.0 * sz) / (px_resolution as f64 - 1.0);

    for j in 0 .. px_resolution {
        for i in 0 .. px_resolution {
            let x0 = xc - sz + step * i as f64;
            let y0 = yc - sz + step * j as f64;
            plot(_cycles_to_escape(x0, y0));
        }
    }
}

fn _cycles_to_escape(x0: f64, y0: f64) -> i32 {
    let mut x = 0.0;
    let mut y = 0.0;
    let mut i = 0;
    while x * x + y * y <= 4.0 && i < MAX_ITER {
        let (a, b) = (x * x - y * y + x0, 2.0 * x * y + y0);
        x = a;
        y = b;  // rust 1.47 lacks tuple unpack, aka destructuring assignment
        i += 1;
    }
    return i;
}

fn plot(grey_value: i32) {
    let v = &grey_value.to_string();
    let mut rgb :String = v.to_owned();
    rgb.push_str(" ");
    rgb.push_str(v);
    rgb.push_str(" ");
    rgb.push_str(v);
    rgb.push_str("\n");
    print!("{}", v);
}
pub fn plot_slow(grey_value: i32) {
    // If _cycles_to_escape costs 220 msec, this costs 840 msec,
    // while the verbose plot costs 730 msec. The to_string
    // alone costs 270 msec. Appending a SPACE costs 140 msec.
    let v = &grey_value;
    println!("{} {} {}", &v, &v, &v);
}

fn getenv(key: &str) -> i32 {
    let s: String;
    match env::var(key) {
        Ok(v) => s = v,
        Err(_) => s = "400".to_string()
    }
    return stoi(s);
}

fn stoi(s: String) -> i32 {
    return s.parse::<i32>().unwrap();
}

fn stof(s: String) -> f64 {
    return s.parse::<f64>().unwrap();
}

pub fn main() {
    let px_resolution = getenv("MSET_PX_RESOLUTION");
    let args: Vec<String> = env::args().into_iter().collect();
    let xc = stof(args[1].to_string());
    let yc = stof(args[2].to_string());
    let sz = stof(args[3].to_string());
    println!("P3\n{} {}\n255", px_resolution, px_resolution);
    let t0 = Instant::now();

    mandelbrot_set(xc, yc, sz, px_resolution);

    let elapsed = t0.elapsed().as_millis() as f64;
    eprintln!("{} seconds", elapsed / 1e3);
}
<commit_msg>Pushing a space char is cheaper<commit_after>
// Copyright 2020 John Hanley.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// The software is provided "AS IS", without warranty of any kind, express or
// implied, including but not limited to the warranties of merchantability,
// fitness for a particular purpose and noninfringement. In no event shall
// the authors or copyright holders be liable for any claim, damages or
// other liability, whether in an action of contract, tort or otherwise,
// arising from, out of or in connection with the software or the use or
// other dealings in the software.

use std::env;
use std::time::Instant;

const MAX_ITER: i32 = 255;  // Rust lacks adequate support for default args.

fn mandelbrot_set(xc: f64, yc: f64, sz: f64, px_resolution: i32) {
    let step = (2.0 * sz) / (px_resolution as f64 - 1.0);

    for j in 0 .. px_resolution {
        for i in 0 .. px_resolution {
            let x0 = xc - sz + step * i as f64;
            let y0 = yc - sz + step * j as f64;
            plot(_cycles_to_escape(x0, y0));
        }
    }
    // io::stdout().flush().ok().expect("flush failed");
}

fn _cycles_to_escape(x0: f64, y0: f64) -> i32 {
    let mut x = 0.0;
    let mut y = 0.0;
    let mut i = 0;
    while x * x + y * y <= 4.0 && i < MAX_ITER {
        let (a, b) = (x * x - y * y + x0, 2.0 * x * y + y0);
        x = a;
        y = b;  // rust 1.47 lacks tuple unpack, aka destructuring assignment
        i += 1;
    }
    return i;
}

fn plot(grey_value: i32) {
    // If _cycles_to_escape costs 220 msec, this costs 840 msec.
    let v = &grey_value;
    println!("{} {} {}", &v, &v, &v);
}
pub fn plot_verbose(grey_value: i32) {
    let v :&str = &grey_value.to_string();
    let mut rgb = String::with_capacity(14);
    rgb.push_str(&v);
    rgb.push(' ');
    rgb.push_str(&v);
    rgb.push(' ');
    rgb.push_str(&v);
    println!("{}", &rgb);
}

fn getenv(key: &str) -> i32 {
    let s: String;
    match env::var(key) {
        Ok(v) => s = v,
        Err(_) => s = "400".to_string()
    }
    return stoi(s);
}

fn stoi(s: String) -> i32 {
    return s.parse::<i32>().unwrap();
}

fn stof(s: String) -> f64 {
    return s.parse::<f64>().unwrap();
}

pub fn main() {
    let px_resolution = getenv("MSET_PX_RESOLUTION");
    let args: Vec<String> = env::args().into_iter().collect();
    let xc = stof(args[1].to_string());
    let yc = stof(args[2].to_string());
    let sz = stof(args[3].to_string());
    println!("P3\n{} {}\n255", px_resolution, px_resolution);
    let t0 = Instant::now();

    mandelbrot_set(xc, yc, sz, px_resolution);

    let elapsed = t0.elapsed().as_millis() as f64;
    eprintln!("{} seconds", elapsed / 1e3);
}
<|endoftext|>


<commit_before>use crate::utils::deserialize::deserialize_duration;
use elasticsearch::Elasticsearch;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::time::Duration;
use url::Url;

pub mod configuration;
pub mod explain;
pub(super) mod internal;
pub mod list;
pub mod models;
pub mod query;
pub mod remote;
pub mod status;
pub mod storage;

/// A structure wrapping around the elasticsearch's client.
#[derive(Clone, Debug)]
pub struct ElasticsearchStorage {
    /// Elasticsearch client
    pub(crate) client: Elasticsearch,
    /// Client configuration
    pub config: ElasticsearchStorageConfig,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ElasticsearchStorageConfig {
    pub url: Url,
    #[serde(deserialize_with = "deserialize_duration")]
    pub timeout: Duration,
    pub version_req: String,
    pub scroll_chunk_size: u64,
    pub scroll_pit_alive: String,
    pub insertion_concurrent_requests: usize,
    pub insertion_chunk_size: usize,
    pub wait_for_active_shards: u64,
    pub force_merge: ElasticsearchStorageForceMergeConfig,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ElasticsearchStorageForceMergeConfig {
    pub enabled: bool,
    pub max_number_segments: i64,
}

impl Default for ElasticsearchStorageConfig {
    /// We retrieve the elasticsearch configuration from ./config/elasticsearch/default.
    fn default() -> Self {
        let config = common::config::config_from(
            &PathBuf::from("config"),
            &["elasticsearch"],
            None,
            None,
            None,
        );

        config
            .expect("cannot build the configuration for testing from config")
            .get("elasticsearch")
            .expect("expected elasticsearch section in configuration from config")
    }
}

impl ElasticsearchStorageConfig {
    pub fn default_testing() -> Self {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../config");

        let config = common::config::config_from(
            config_dir.as_path(),
            &["elasticsearch"],
            "testing",
            "MIMIR_TEST",
            None,
        );

        config
            .unwrap_or_else(|_| {
                panic!(
                    "cannot build the configuration for testing from {}",
                    config_dir.display(),
                )
            })
            .get("elasticsearch")
            .unwrap_or_else(|_| {
                panic!(
                    "expected elasticsearch section in configuration from {}",
                    config_dir.display(),
                )
            })
    }
}

#[cfg(test)]
pub mod tests {

    use serde::{Deserialize, Serialize};
    use serial_test::serial;

    use super::*;

    use crate::domain::ports::secondary::storage::Storage;
    use crate::domain::{
        model::configuration::ContainerConfig, model::configuration::ContainerConfigForceMerge,
        ports::secondary::remote::Remote,
    };
    use crate::utils::docker;
    use common::document::{ContainerDocument, Document};

    #[tokio::test]
    #[serial]
    async fn should_connect_to_elasticsearch() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");

        let _client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig::default_testing())
            .await
            .expect("Elasticsearch Connection Established");
    }

    #[tokio::test]
    #[serial]
    async fn should_create_index() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");
        let client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig::default_testing())
            .await
            .expect("Elasticsearch Connection Established");

        let config = ContainerConfig {
            name: "foo".to_string(),
            dataset: "bar".to_string(),
            force_merge: ContainerConfigForceMerge {
                enabled: true,
                max_number_segments: 1,
            },
        };

        let res = client.create_container(&config).await;
        assert!(res.is_ok());
    }

    #[derive(Deserialize, Serialize)]
    struct TestObj {
        value: String,
    }

    impl Document for TestObj {
        fn id(&self) -> String {
            self.value.clone()
        }
    }

    impl ContainerDocument for TestObj {
        fn static_doc_type() -> &'static str {
            "test-obj"
        }
    }

    #[tokio::test]
    #[serial]
    async fn should_correctly_insert_multiple_documents() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");

        let client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig::default_testing())
            .await
            .expect("Elasticsearch Connection Established");

        let config = ContainerConfig {
            name: TestObj::static_doc_type().to_string(),
            dataset: "default".to_string(),
            force_merge: ContainerConfigForceMerge {
                enabled: true,
                max_number_segments: 1,
            },
        };

        client
            .create_container(&config)
            .await
            .expect("container creation");

        let documents = vec![
            TestObj {
                value: String::from("obj1"),
            },
            TestObj {
                value: String::from("obj2"),
            },
            TestObj {
                value: String::from("obj3"),
            },
            TestObj {
                value: String::from("obj4"),
            },
            TestObj {
                value: String::from("obj5"),
            },
            TestObj {
                value: String::from("obj6"),
            },
        ];
        let documents = futures::stream::iter(documents);

        let res = client
            .insert_documents(
                String::from("root_obj_dataset_test-index-bulk-insert"),
                documents,
            )
            .await;

        assert_eq!(res.expect("insertion stats").created, 6);
    }

    #[tokio::test]
    #[serial]
    async fn should_detect_invalid_elasticsearch_version() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");

        let client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig {
                version_req: ">=9.99.99".to_string(),
                ..ElasticsearchStorageConfig::default_testing()
            })
            .await;

        assert!(client
            .unwrap_err()
            .to_string()
            .contains("Elasticsearch Invalid version"));
    }
}
<commit_msg>set index visibility in elasticsearch tests<commit_after>use crate::utils::deserialize::deserialize_duration;
use elasticsearch::Elasticsearch;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::time::Duration;
use url::Url;

pub mod configuration;
pub mod explain;
pub(super) mod internal;
pub mod list;
pub mod models;
pub mod query;
pub mod remote;
pub mod status;
pub mod storage;

/// A structure wrapping around the elasticsearch's client.
#[derive(Clone, Debug)]
pub struct ElasticsearchStorage {
    /// Elasticsearch client
    pub(crate) client: Elasticsearch,
    /// Client configuration
    pub config: ElasticsearchStorageConfig,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ElasticsearchStorageConfig {
    pub url: Url,
    #[serde(deserialize_with = "deserialize_duration")]
    pub timeout: Duration,
    pub version_req: String,
    pub scroll_chunk_size: u64,
    pub scroll_pit_alive: String,
    pub insertion_concurrent_requests: usize,
    pub insertion_chunk_size: usize,
    pub wait_for_active_shards: u64,
    pub force_merge: ElasticsearchStorageForceMergeConfig,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ElasticsearchStorageForceMergeConfig {
    pub enabled: bool,
    pub max_number_segments: i64,
}

impl Default for ElasticsearchStorageConfig {
    /// We retrieve the elasticsearch configuration from ./config/elasticsearch/default.
    fn default() -> Self {
        let config = common::config::config_from(
            &PathBuf::from("config"),
            &["elasticsearch"],
            None,
            None,
            None,
        );

        config
            .expect("cannot build the configuration for testing from config")
            .get("elasticsearch")
            .expect("expected elasticsearch section in configuration from config")
    }
}

impl ElasticsearchStorageConfig {
    pub fn default_testing() -> Self {
        let config_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../config");

        let config = common::config::config_from(
            config_dir.as_path(),
            &["elasticsearch"],
            "testing",
            "MIMIR_TEST",
            None,
        );

        config
            .unwrap_or_else(|_| {
                panic!(
                    "cannot build the configuration for testing from {}",
                    config_dir.display(),
                )
            })
            .get("elasticsearch")
            .unwrap_or_else(|_| {
                panic!(
                    "expected elasticsearch section in configuration from {}",
                    config_dir.display(),
                )
            })
    }
}

#[cfg(test)]
pub mod tests {

    use serde::{Deserialize, Serialize};
    use serial_test::serial;

    use super::*;

    use crate::domain::model::configuration::ContainerVisibility;
    use crate::domain::ports::secondary::storage::Storage;
    use crate::domain::{model::configuration::ContainerConfig, ports::secondary::remote::Remote};
    use crate::utils::docker;
    use common::document::{ContainerDocument, Document};

    #[tokio::test]
    #[serial]
    async fn should_connect_to_elasticsearch() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");

        let _client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig::default_testing())
            .await
            .expect("Elasticsearch Connection Established");
    }

    #[tokio::test]
    #[serial]
    async fn should_create_index() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");
        let client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig::default_testing())
            .await
            .expect("Elasticsearch Connection Established");

        let config = ContainerConfig {
            name: "foo".to_string(),
            dataset: "bar".to_string(),
            visibility: ContainerVisibility::Public,
        };

        let res = client.create_container(&config).await;
        assert!(res.is_ok());
    }

    #[derive(Deserialize, Serialize)]
    struct TestObj {
        value: String,
    }

    impl Document for TestObj {
        fn id(&self) -> String {
            self.value.clone()
        }
    }

    impl ContainerDocument for TestObj {
        fn static_doc_type() -> &'static str {
            "test-obj"
        }
    }

    #[tokio::test]
    #[serial]
    async fn should_correctly_insert_multiple_documents() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");

        let client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig::default_testing())
            .await
            .expect("Elasticsearch Connection Established");

        let config = ContainerConfig {
            name: TestObj::static_doc_type().to_string(),
            dataset: "default".to_string(),
            visibility: ContainerVisibility::Public,
        };

        client
            .create_container(&config)
            .await
            .expect("container creation");

        let documents = vec![
            TestObj {
                value: String::from("obj1"),
            },
            TestObj {
                value: String::from("obj2"),
            },
            TestObj {
                value: String::from("obj3"),
            },
            TestObj {
                value: String::from("obj4"),
            },
            TestObj {
                value: String::from("obj5"),
            },
            TestObj {
                value: String::from("obj6"),
            },
        ];
        let documents = futures::stream::iter(documents);

        let res = client
            .insert_documents(
                String::from("root_obj_dataset_test-index-bulk-insert"),
                documents,
            )
            .await;

        assert_eq!(res.expect("insertion stats").created, 6);
    }

    #[tokio::test]
    #[serial]
    async fn should_detect_invalid_elasticsearch_version() {
        docker::initialize()
            .await
            .expect("elasticsearch docker initialization");

        let client = remote::connection_test_pool()
            .conn(ElasticsearchStorageConfig {
                version_req: ">=9.99.99".to_string(),
                ..ElasticsearchStorageConfig::default_testing()
            })
            .await;

        assert!(client
            .unwrap_err()
            .to_string()
            .contains("Elasticsearch Invalid version"));
    }
}
<|endoftext|>


<commit_before>use super::Mode;
use super::KeyMap;
use super::Key;
use super::KeyMapState;
use super::Direction;
use buffer::Mark;
use command::{BuilderEvent, Operation, Instruction, Command, Action};
use textobject::{Anchor, Kind, TextObject, Offset};

// TODO: move this somewhere else - probably command module
fn movement(offset: Offset, kind: Kind) -> Command {
    Command {
        number: 0,
        action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
        object: TextObject {
            kind: kind,
            offset: offset
        }
    }

}

/// Standard mode is Iota's default mode.
///
/// Standard mode uses non-vi-like keybindings.
/// Unlike Normal, Command and Visual modes which are all used together, Standard
/// mode is used on its own.
///
/// Standard mode allows Iota to be used in a non-modal way, similar to mainstream
/// editors like emacs or sublime.
pub struct StandardMode {
    keymap: KeyMap<Command>,
}

impl StandardMode {

    /// Create a new instance of StandardMode
    pub fn new() -> StandardMode {
        StandardMode {
            keymap: StandardMode::key_defaults(),
        }
    }

    /// Creates a KeyMap with default StandardMode key bindings
    fn key_defaults() -> KeyMap<Command> {
        let mut keymap = KeyMap::new();

        // Editor Commands
        keymap.bind_key(Key::Ctrl('q'), Command::exit_editor());
        keymap.bind_key(Key::Ctrl('s'), Command::save_buffer());
        keymap.bind_keys(vec![Key::Ctrl('x'), Key::Ctrl('c')].as_slice(), Command::exit_editor());
        keymap.bind_keys(vec![Key::Ctrl('x'), Key::Ctrl('s')].as_slice(), Command::save_buffer());

        // Cursor movement
        keymap.bind_key(Key::Up, movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Down, movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Left, movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Right, movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Ctrl('p'), movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Ctrl('n'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Ctrl('b'), movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Ctrl('f'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Ctrl('e'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::End)));
        keymap.bind_key(Key::Ctrl('a'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::Start)));

        // // Editing
        keymap.bind_key(Key::Tab, Command::insert_tab());
        keymap.bind_key(Key::Enter, Command::insert_char('\n'));
        // keymap.bind_key(Key::Backspace, Command::Delete(Direction::Left, 1));
        // keymap.bind_key(Key::Ctrl('h'), Command::Delete(Direction::Left, 1));
        // keymap.bind_key(Key::Delete, Command::Delete(Direction::Right, 1));
        // keymap.bind_key(Key::Ctrl('d'), Command::Delete(Direction::Right, 1));

        // // History
        // keymap.bind_key(Key::Ctrl('y'), Command::Redo);
        // keymap.bind_key(Key::Ctrl('z'), Command::Undo);

        keymap
    }

}

impl Mode for StandardMode {
    /// Given a key, pass it through the StandardMode KeyMap and return the associated Command, if any.
    /// If no match is found, treat it as an InsertChar command.
    fn handle_key_event(&mut self, key: Key) -> BuilderEvent {

        if let Key::Char(c) = key {
            BuilderEvent::Complete(Command::insert_char(c))
        } else {
            if let KeyMapState::Match(c) = self.keymap.check_key(key) {
                BuilderEvent::Complete(c)
            } else {
                BuilderEvent::Incomplete
            }
        }
    }
}
<commit_msg>Standard mode undo/redo<commit_after>use super::Mode;
use super::KeyMap;
use super::Key;
use super::KeyMapState;
use super::Direction;
use buffer::Mark;
use command::{BuilderEvent, Operation, Instruction, Command, Action};
use textobject::{Anchor, Kind, TextObject, Offset};

// TODO: move this somewhere else - probably command module
fn movement(offset: Offset, kind: Kind) -> Command {
    Command {
        number: 0,
        action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
        object: TextObject {
            kind: kind,
            offset: offset
        }
    }

}

/// Standard mode is Iota's default mode.
///
/// Standard mode uses non-vi-like keybindings.
/// Unlike Normal, Command and Visual modes which are all used together, Standard
/// mode is used on its own.
///
/// Standard mode allows Iota to be used in a non-modal way, similar to mainstream
/// editors like emacs or sublime.
pub struct StandardMode {
    keymap: KeyMap<Command>,
}

impl StandardMode {

    /// Create a new instance of StandardMode
    pub fn new() -> StandardMode {
        StandardMode {
            keymap: StandardMode::key_defaults(),
        }
    }

    /// Creates a KeyMap with default StandardMode key bindings
    fn key_defaults() -> KeyMap<Command> {
        let mut keymap = KeyMap::new();

        // Editor Commands
        keymap.bind_key(Key::Ctrl('q'), Command::exit_editor());
        keymap.bind_key(Key::Ctrl('s'), Command::save_buffer());
        keymap.bind_keys(vec![Key::Ctrl('x'), Key::Ctrl('c')].as_slice(), Command::exit_editor());
        keymap.bind_keys(vec![Key::Ctrl('x'), Key::Ctrl('s')].as_slice(), Command::save_buffer());

        // Cursor movement
        keymap.bind_key(Key::Up, movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Down, movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Left, movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Right, movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Ctrl('p'), movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Ctrl('n'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::Same)));
        keymap.bind_key(Key::Ctrl('b'), movement(Offset::Backward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Ctrl('f'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Char));
        keymap.bind_key(Key::Ctrl('e'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::End)));
        keymap.bind_key(Key::Ctrl('a'), movement(Offset::Forward(1, Mark::Cursor(0)), Kind::Line(Anchor::Start)));

        // // Editing
        keymap.bind_key(Key::Tab, Command::insert_tab());
        keymap.bind_key(Key::Enter, Command::insert_char('\n'));
        // keymap.bind_key(Key::Backspace, Command::Delete(Direction::Left, 1));
        // keymap.bind_key(Key::Ctrl('h'), Command::Delete(Direction::Left, 1));
        // keymap.bind_key(Key::Delete, Command::Delete(Direction::Right, 1));
        // keymap.bind_key(Key::Ctrl('d'), Command::Delete(Direction::Right, 1));

        // History
        keymap.bind_key(Key::Ctrl('z'), Command {
            number: 1,
            action: Action::Operation(Operation::Undo),
            object: TextObject {
                kind: Kind::Char,
                offset: Offset::Absolute(0)
            }
        });
        keymap.bind_key(Key::Ctrl('y'), Command {
            number: 1,
            action: Action::Operation(Operation::Redo),
            object: TextObject {
                kind: Kind::Char,
                offset: Offset::Absolute(0)
            }
        });

        keymap
    }

}

impl Mode for StandardMode {
    /// Given a key, pass it through the StandardMode KeyMap and return the associated Command, if any.
    /// If no match is found, treat it as an InsertChar command.
    fn handle_key_event(&mut self, key: Key) -> BuilderEvent {

        if let Key::Char(c) = key {
            BuilderEvent::Complete(Command::insert_char(c))
        } else {
            if let KeyMapState::Match(c) = self.keymap.check_key(key) {
                BuilderEvent::Complete(c)
            } else {
                BuilderEvent::Incomplete
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;

use libimagerror::into::IntoError;
use libimagstore::storeid::StoreId;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::result::Result;

use vcs::git::action::StoreAction;

use git2::Repository;

/// Check the configuration whether we should commit interactively
pub fn commit_interactive(config: &Value, action: &StoreAction) -> bool {
    match config.lookup("commit.interactive") {
        Some(&Value::Boolean(b)) => b,
        Some(_) => {
            warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.interactive' must be a Boolean.",
                  action);
            warn!("Defaulting to commit.interactive = false");
            false
        }
        None => {
            warn!("Unavailable configuration for");
            warn!("\t'store.hooks.stdhook_git_{}.commit.interactive'", action);
            warn!("Defaulting to false");
            false
        }
    }
}

/// Check the configuration whether we should commit with the editor
fn commit_with_editor(config: &Value, action: &StoreAction) -> bool {
    match config.lookup("commit.interactive_editor") {
        Some(&Value::Boolean(b)) => b,
        Some(_) => {
            warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.interactive_editor' must be a Boolean.",
                  action);
            warn!("Defaulting to commit.interactive_editor = false");
            false
        }
        None => {
            warn!("Unavailable configuration for");
            warn!("\t'store.hooks.stdhook_git_{}.commit.interactive_editor'", action);
            warn!("Defaulting to false");
            false
        }
    }
}

/// Get the commit default message
fn commit_default_msg<'a>(config: &'a Value, action: &'a StoreAction) -> &'a str {
    match config.lookup("commit.message") {
        Some(&Value::String(ref b)) => b,
        Some(_) => {
            warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.message' must be a String.",
                  action);
            warn!("Defaulting to commit.message = '{}'", action.as_commit_message());
            action.as_commit_message()
        }
        None => {
            warn!("Unavailable configuration for");
            warn!("\t'store.hooks.stdhook_git_{}.commit.message'", action);
            warn!("Defaulting to commit.message = '{}'", action.as_commit_message());
            action.as_commit_message()
        }
    }
}

/// Get the commit template
///
/// TODO: Implement good template string
fn commit_template(action: &StoreAction, id: &StoreId) -> String {
    format!(r#"
# Please commit your changes and remove these lines.
#
# You're about to commit changes via the {action} Hook
#
#   Altered file: {id}
#
    "#,
    action = action,
    id = id.local().display())
}

/// Generate a commit message
///
/// Uses the functions `commit_interactive()` and `commit_with_editor()`
/// or reads one from the commandline or uses the `commit_default_msg()` string to create a commit
/// message.
pub fn commit_message(repo: &Repository, config: &Value, action: StoreAction, id: &StoreId) -> Result<String> {
    use libimaginteraction::ask::ask_string;
    use libimagutil::edit::edit_in_tmpfile_with_command;
    use std::process::Command;

    if commit_interactive(config, &action) {
        if commit_with_editor(config, &action) {
            repo.config()
                .map_err_into(GHEK::GitConfigFetchError)
                .and_then(|c| c.get_string("core.editor").map_err_into(GHEK::GitConfigEditorFetchError))
                .map_err_into(GHEK::ConfigError)
                .map(Command::new)
                .and_then(|cmd| {
                    let mut s = commit_template(&action, id);
                    edit_in_tmpfile_with_command(cmd, &mut s).map(|_| s)
                        .map_err_into(GHEK::EditorError)
                })
        } else {
            Ok(ask_string("Commit Message", None, false, false, None, "> "))
        }
    } else {
        Ok(String::from(commit_default_msg(config, &action)))
    }
}

/// Check whether the hook should abort if the repository cannot be initialized
pub fn abort_on_repo_init_err(cfg: &Value) -> bool {
    get_bool_cfg(Some(cfg), "abort_on_repo_init_failure", true, true)
}

/// Get the branch which must be checked out before running the hook (if any).
///
/// If there is no configuration for this, this is `Ok(None)`, otherwise we try to find the
/// configuration `String`.
pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
    match cfg {
        Some(cfg) => {
            match cfg.lookup("ensure_branch") {
                Some(&Value::String(ref s)) => Ok(Some(s.clone())),
                Some(_) => {
                    warn!("Configuration error, 'ensure_branch' must be a String.");
                    Err(GHEK::ConfigTypeError.into_error())
                        .map_err_into(GHEK::ConfigTypeError)
                },
                None => {
                    debug!("No key `ensure_branch'");
                    Ok(None)
                },
            }
        },
        None => Ok(None),
    }
}

/// Check whether we should check out a branch before committing.
pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "try_checkout_ensure_branch", true, true)
}

/// Helper to get a boolean value from the configuration.
fn get_bool_cfg(cfg: Option<&Value>, name: &str, on_fail: bool, on_unavail: bool) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup(name) {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, '{}' must be a Boolean (true|false).", name);
                warn!("Assuming '{}' now.", on_fail);
                on_fail
            },
            None => {
                warn!("No key '{}' - Assuming '{}'", name, on_unavail);
                on_unavail
            },
        }
    })
    .unwrap_or_else(|| {
        warn!("No configuration to fetch {} from, assuming {}", name, on_unavail);
        on_unavail
    })
}

/// Check whether the hook is enabled or not. If the config is not there, the hook is _enabled_ by
/// default.
pub fn is_enabled(cfg: &Value) -> bool {
    get_bool_cfg(Some(cfg), "enabled", true, true)
}

<commit_msg>Add helper to check whether committing is enabled<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use toml::Value;

use libimagerror::into::IntoError;
use libimagstore::storeid::StoreId;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::result::Result;

use vcs::git::action::StoreAction;

use git2::Repository;

/// Check the configuration whether we should commit interactively
pub fn commit_interactive(config: &Value, action: &StoreAction) -> bool {
    match config.lookup("commit.interactive") {
        Some(&Value::Boolean(b)) => b,
        Some(_) => {
            warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.interactive' must be a Boolean.",
                  action);
            warn!("Defaulting to commit.interactive = false");
            false
        }
        None => {
            warn!("Unavailable configuration for");
            warn!("\t'store.hooks.stdhook_git_{}.commit.interactive'", action);
            warn!("Defaulting to false");
            false
        }
    }
}

/// Check the configuration whether we should commit with the editor
fn commit_with_editor(config: &Value, action: &StoreAction) -> bool {
    match config.lookup("commit.interactive_editor") {
        Some(&Value::Boolean(b)) => b,
        Some(_) => {
            warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.interactive_editor' must be a Boolean.",
                  action);
            warn!("Defaulting to commit.interactive_editor = false");
            false
        }
        None => {
            warn!("Unavailable configuration for");
            warn!("\t'store.hooks.stdhook_git_{}.commit.interactive_editor'", action);
            warn!("Defaulting to false");
            false
        }
    }
}

/// Get the commit default message
fn commit_default_msg<'a>(config: &'a Value, action: &'a StoreAction) -> &'a str {
    match config.lookup("commit.message") {
        Some(&Value::String(ref b)) => b,
        Some(_) => {
            warn!("Configuration error, 'store.hooks.stdhook_git_{}.commit.message' must be a String.",
                  action);
            warn!("Defaulting to commit.message = '{}'", action.as_commit_message());
            action.as_commit_message()
        }
        None => {
            warn!("Unavailable configuration for");
            warn!("\t'store.hooks.stdhook_git_{}.commit.message'", action);
            warn!("Defaulting to commit.message = '{}'", action.as_commit_message());
            action.as_commit_message()
        }
    }
}

/// Get the commit template
///
/// TODO: Implement good template string
fn commit_template(action: &StoreAction, id: &StoreId) -> String {
    format!(r#"
# Please commit your changes and remove these lines.
#
# You're about to commit changes via the {action} Hook
#
#   Altered file: {id}
#
    "#,
    action = action,
    id = id.local().display())
}

/// Generate a commit message
///
/// Uses the functions `commit_interactive()` and `commit_with_editor()`
/// or reads one from the commandline or uses the `commit_default_msg()` string to create a commit
/// message.
pub fn commit_message(repo: &Repository, config: &Value, action: StoreAction, id: &StoreId) -> Result<String> {
    use libimaginteraction::ask::ask_string;
    use libimagutil::edit::edit_in_tmpfile_with_command;
    use std::process::Command;

    if commit_interactive(config, &action) {
        if commit_with_editor(config, &action) {
            repo.config()
                .map_err_into(GHEK::GitConfigFetchError)
                .and_then(|c| c.get_string("core.editor").map_err_into(GHEK::GitConfigEditorFetchError))
                .map_err_into(GHEK::ConfigError)
                .map(Command::new)
                .and_then(|cmd| {
                    let mut s = commit_template(&action, id);
                    edit_in_tmpfile_with_command(cmd, &mut s).map(|_| s)
                        .map_err_into(GHEK::EditorError)
                })
        } else {
            Ok(ask_string("Commit Message", None, false, false, None, "> "))
        }
    } else {
        Ok(String::from(commit_default_msg(config, &action)))
    }
}

/// Check whether the hook should abort if the repository cannot be initialized
pub fn abort_on_repo_init_err(cfg: &Value) -> bool {
    get_bool_cfg(Some(cfg), "abort_on_repo_init_failure", true, true)
}

/// Get the branch which must be checked out before running the hook (if any).
///
/// If there is no configuration for this, this is `Ok(None)`, otherwise we try to find the
/// configuration `String`.
pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
    match cfg {
        Some(cfg) => {
            match cfg.lookup("ensure_branch") {
                Some(&Value::String(ref s)) => Ok(Some(s.clone())),
                Some(_) => {
                    warn!("Configuration error, 'ensure_branch' must be a String.");
                    Err(GHEK::ConfigTypeError.into_error())
                        .map_err_into(GHEK::ConfigTypeError)
                },
                None => {
                    debug!("No key `ensure_branch'");
                    Ok(None)
                },
            }
        },
        None => Ok(None),
    }
}

/// Check whether we should check out a branch before committing.
pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "try_checkout_ensure_branch", true, true)
}

/// Helper to get a boolean value from the configuration.
fn get_bool_cfg(cfg: Option<&Value>, name: &str, on_fail: bool, on_unavail: bool) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup(name) {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, '{}' must be a Boolean (true|false).", name);
                warn!("Assuming '{}' now.", on_fail);
                on_fail
            },
            None => {
                warn!("No key '{}' - Assuming '{}'", name, on_unavail);
                on_unavail
            },
        }
    })
    .unwrap_or_else(|| {
        warn!("No configuration to fetch {} from, assuming {}", name, on_unavail);
        on_unavail
    })
}

/// Check whether the hook is enabled or not. If the config is not there, the hook is _enabled_ by
/// default.
pub fn is_enabled(cfg: &Value) -> bool {
    get_bool_cfg(Some(cfg), "enabled", true, true)
}

/// Check whether committing is enabled for a hook.
pub fn committing_is_enabled(cfg: &Value) -> Result<bool> {
    match cfg.lookup("commit.enabled") {
        Some(&Value::Boolean(b)) => Ok(b),
        Some(_) => {
            warn!("Config setting whether committing is enabled or not has wrong type.");
            warn!("Expected Boolean");
            Err(GHEK::ConfigTypeError.into_error())
        },
        None => {
            warn!("No config setting whether committing is enabled or not.");
            Err(GHEK::NoConfigError.into_error())
        },
    }
    .map_err_into(GHEK::ConfigError)
}

<|endoftext|>