<commit_before>#![deny(warnings)]
#![feature(macro_rules, plugin_registrar, slicing_syntax)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use syntax::ast::{CompilerGenerated, TTTok, TokenTree, UnsafeBlock};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{mod, COMMA};

/// Executes several closures in parallel
///
/// - This macro is an expression, and will return a tuple containing the values returned by the
/// closures.
/// - One task per closure (i.e. there is no "load balancing").
/// - This macro will block until all the spawned tasks have finished. For this reason the closures
/// don't need to fulfill the `Send` trait (i.e. the closures may capture slices and references).
///
/// # Expansion
///
/// Consider the following call:
///
/// ``` ignore
/// let (a, b, c) = execute!{
///     |:| job_1(),
///     |:| job_2(),
///     |:| job_3(),
/// };
/// ```
///
/// This macro uses the "unsafe" [`Task`](../parallel/struct.Task.html) defined in the
/// [`parallel`](../parallel/index.html) crate, and its expansion looks (roughly) like this:
///
/// ``` ignore
/// let (a, b, c) = {
///     let __task_0 = |:| job_1();
///     let __task_1 = unsafe { Task::fork(|:| job_2()) };  // spawns a task
///     let __task_2 = unsafe { Task::fork(|:| job_3()) };  // spawns another task
///
///     // the current task takes care of the first closure
///     (__task_0(), __task_1.join(), __task_2.join())
///     // ^~ then blocks until the other two tasks finish
/// };
/// ```
///
/// # Failure
///
/// This macro will fail if any of the spawned tasks fails.
///
/// # Example
///
/// I'll borrow the binary tree example from Niko's
/// [blog](http://smallcultfollowing.com/babysteps/blog/2013/06/11/data-parallelism-in-rust/).
///
/// ```
/// #![feature(overloaded_calls, phase)]
///
/// extern crate parallel;
/// #[phase(plugin)]
/// extern crate parallel_macros;
///
/// struct Tree {
///     left: Option<Box<Tree>>,
///     right: Option<Box<Tree>>,
///     value: uint,
/// }
///
/// impl Tree {
///     fn sum(&self) -> uint {
///         fn sum(subtree: &Option<Box<Tree>>) -> uint {
///             match *subtree {
///                 None => 0,
///                 Some(box ref tree) => tree.sum(),
///             }
///         }
///
///         let (left_sum, right_sum) = execute!{
///             // NB Each closure captures a reference which doesn't fulfills `Send`
///             |:| sum(&self.left),
///             |:| sum(&self.right),
///         };
///
///         left_sum + self.value + right_sum
///     }
/// }
///
/// fn main() {
///     let tree = Tree {
///         value: 5,
///         left: Some(box Tree {
///             value: 3,
///             left: Some(box Tree {
///                 value: 1,
///                 left: None,
///                 right: Some(box Tree {
///                     value: 4,
///                     left: None,
///                     right: None,
///                 }),
///             }),
///             right: None,
///         }),
///         right: Some(box Tree {
///             value: 7,
///             left: None,
///             right: None,
///         }),
///     };
///
///     assert_eq!(tree.sum(), 20);
/// }
/// ```
#[macro_export]
macro_rules! execute {
    ($($closure:expr),+,) => ({ /* syntax extension */ });
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("execute"), NormalTT(box expand_execute, None));
}

fn expand_execute<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    let parallel_task_fork_fn_path = {
        let segments = vec![
            token::str_to_ident("parallel"),
            token::str_to_ident("Task"),
            token::str_to_ident("fork"),
        ];

        cx.expr_path(cx.path_global(sp, segments))
    };

    let mut stmts = vec![];
    let tasks = tts.split(|tt| match *tt {
        TTTok(_, COMMA) => true,
        _ => false,
    }).filter(|tts| {
        !tts.is_empty()
    }).enumerate().map(|(i, tts)|  {
        let closure = cx.new_parser_from_tts(tts).parse_expr();
        let ident = token::str_to_ident(format!("__task_{}", i)[]);

        let expr = if i == 0 {
            closure
        } else {
            let fn_name = parallel_task_fork_fn_path.clone();
            let args = vec![closure];

            // XXX There has to be a simpler way to wrap an expression in `unsafe`
            let block = cx.block_expr(cx.expr_call(sp, fn_name, args)).map(|mut b| {
                b.rules = UnsafeBlock(CompilerGenerated);
                b
            });
            cx.expr_block(block)
        };

        stmts.push(cx.stmt_let(sp, false, ident, expr));

        ident
    }).collect::<Vec<_>>();

    let mut is_first = true;
    let expr = cx.expr_tuple(sp, tasks.into_iter().map(|task| {
        let args = vec![];
        let task = cx.expr_ident(sp, task);

        if is_first {
            is_first = false;

            cx.expr_call(sp, task, args)
        } else {
            let method = token::str_to_ident("join");

            cx.expr_method_call(sp, task, method, args)
        }
    }).collect());

    MacExpr::new(cx.expr_block(cx.block(sp, stmts, Some(expr))))
}
<commit_msg>fix(macros): TTTok -> TtToken, COMMA -> Comma<commit_after>#![deny(warnings)]
#![feature(macro_rules, plugin_registrar, slicing_syntax)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use syntax::ast::{CompilerGenerated, TtToken, TokenTree, UnsafeBlock};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{mod, Comma};

/// Executes several closures in parallel
///
/// - This macro is an expression, and will return a tuple containing the values returned by the
/// closures.
/// - One task per closure (i.e. there is no "load balancing").
/// - This macro will block until all the spawned tasks have finished. For this reason the closures
/// don't need to fulfill the `Send` trait (i.e. the closures may capture slices and references).
///
/// # Expansion
///
/// Consider the following call:
///
/// ``` ignore
/// let (a, b, c) = execute!{
///     |:| job_1(),
///     |:| job_2(),
///     |:| job_3(),
/// };
/// ```
///
/// This macro uses the "unsafe" [`Task`](../parallel/struct.Task.html) defined in the
/// [`parallel`](../parallel/index.html) crate, and its expansion looks (roughly) like this:
///
/// ``` ignore
/// let (a, b, c) = {
///     let __task_0 = |:| job_1();
///     let __task_1 = unsafe { Task::fork(|:| job_2()) };  // spawns a task
///     let __task_2 = unsafe { Task::fork(|:| job_3()) };  // spawns another task
///
///     // the current task takes care of the first closure
///     (__task_0(), __task_1.join(), __task_2.join())
///     // ^~ then blocks until the other two tasks finish
/// };
/// ```
///
/// # Failure
///
/// This macro will fail if any of the spawned tasks fails.
///
/// # Example
///
/// I'll borrow the binary tree example from Niko's
/// [blog](http://smallcultfollowing.com/babysteps/blog/2013/06/11/data-parallelism-in-rust/).
///
/// ```
/// #![feature(overloaded_calls, phase)]
///
/// extern crate parallel;
/// #[phase(plugin)]
/// extern crate parallel_macros;
///
/// struct Tree {
///     left: Option<Box<Tree>>,
///     right: Option<Box<Tree>>,
///     value: uint,
/// }
///
/// impl Tree {
///     fn sum(&self) -> uint {
///         fn sum(subtree: &Option<Box<Tree>>) -> uint {
///             match *subtree {
///                 None => 0,
///                 Some(box ref tree) => tree.sum(),
///             }
///         }
///
///         let (left_sum, right_sum) = execute!{
///             // NB Each closure captures a reference which doesn't fulfills `Send`
///             |:| sum(&self.left),
///             |:| sum(&self.right),
///         };
///
///         left_sum + self.value + right_sum
///     }
/// }
///
/// fn main() {
///     let tree = Tree {
///         value: 5,
///         left: Some(box Tree {
///             value: 3,
///             left: Some(box Tree {
///                 value: 1,
///                 left: None,
///                 right: Some(box Tree {
///                     value: 4,
///                     left: None,
///                     right: None,
///                 }),
///             }),
///             right: None,
///         }),
///         right: Some(box Tree {
///             value: 7,
///             left: None,
///             right: None,
///         }),
///     };
///
///     assert_eq!(tree.sum(), 20);
/// }
/// ```
#[macro_export]
macro_rules! execute {
    ($($closure:expr),+,) => ({ /* syntax extension */ });
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("execute"), NormalTT(box expand_execute, None));
}

fn expand_execute<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    let parallel_task_fork_fn_path = {
        let segments = vec![
            token::str_to_ident("parallel"),
            token::str_to_ident("Task"),
            token::str_to_ident("fork"),
        ];

        cx.expr_path(cx.path_global(sp, segments))
    };

    let mut stmts = vec![];
    let tasks = tts.split(|tt| match *tt {
        TtToken(_, Comma) => true,
        _ => false,
    }).filter(|tts| {
        !tts.is_empty()
    }).enumerate().map(|(i, tts)|  {
        let closure = cx.new_parser_from_tts(tts).parse_expr();
        let ident = token::str_to_ident(format!("__task_{}", i)[]);

        let expr = if i == 0 {
            closure
        } else {
            let fn_name = parallel_task_fork_fn_path.clone();
            let args = vec![closure];

            // XXX There has to be a simpler way to wrap an expression in `unsafe`
            let block = cx.block_expr(cx.expr_call(sp, fn_name, args)).map(|mut b| {
                b.rules = UnsafeBlock(CompilerGenerated);
                b
            });
            cx.expr_block(block)
        };

        stmts.push(cx.stmt_let(sp, false, ident, expr));

        ident
    }).collect::<Vec<_>>();

    let mut is_first = true;
    let expr = cx.expr_tuple(sp, tasks.into_iter().map(|task| {
        let args = vec![];
        let task = cx.expr_ident(sp, task);

        if is_first {
            is_first = false;

            cx.expr_call(sp, task, args)
        } else {
            let method = token::str_to_ident("join");

            cx.expr_method_call(sp, task, method, args)
        }
    }).collect());

    MacExpr::new(cx.expr_block(cx.block(sp, stmts, Some(expr))))
}
<|endoftext|>


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

use std::rc::Rc;
use std::any::Any;

use ::props::*;
use ::layout::{MiLayout, Layout};
use super::super::{
    TokenPrivate, Token, PresentationPrivate, Presentation, SpecifiedTokenProps, PropertyCalculator,
    SpecifiedPresentationProps, Element, InheritedProps, StyleProps, ElementType, TokenElement};
use ::draw::*;
use ::platform::*;

pub struct Mi {
    token_props: SpecifiedTokenProps,
    presentation_props: SpecifiedPresentationProps,
}

impl Mi {
    pub fn new(text: String) -> Mi {
        Mi {
            token_props: SpecifiedTokenProps {
                text: Rc::new(text),
                math_variant: None,
                math_size: None,
                dir: None,
            },
            presentation_props: SpecifiedPresentationProps {
                math_color: None,
                math_background: None,
            }
        }
    }
}

impl Element for Mi {
    fn layout(&self, context: &Context, parent: Option<&Element>, inherited: &InheritedProps,
              style: &Option<&StyleProps>) -> Box<Layout> {
        let mut calculator = PropertyCalculator::new(
            context, self, parent, inherited, style.clone());

        Box::new(MiLayout {
            token_element: self.layout_token_element(context, &mut calculator)
        })
    }

    fn type_info(&self) -> ElementType {
        ElementType::TokenElement(TokenElement::Mi)
    }

    fn as_any(&self) -> &Any {
        self
    }
}

impl PresentationPrivate<Mi> for Mi {
    fn get_specified_presentation_props(&self) -> &SpecifiedPresentationProps {
        &self.presentation_props
    }

    fn get_specified_presentation_props_mut(&mut self) -> &mut SpecifiedPresentationProps {
        &mut self.presentation_props
    }
}

impl TokenPrivate<Mi> for Mi {
    fn get_specified_token_props(&self) -> &SpecifiedTokenProps {
        &self.token_props
    }

    fn get_specified_token_props_mut(&mut self) -> &mut SpecifiedTokenProps {
        &mut self.token_props
    }
}

impl Token<Mi> for Mi {}

impl Presentation<Mi> for Mi {}

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

    #[test]
    fn it_works() {
        let snap = Snapshot::default();
        snap.snap_element(&Mi::new(String::from("i")), "mi_normal");

        snap.snap_element(
            Mi::new(String::from("i")).with_math_variant(Some(MathVariant::Italic)),
            "mi_italic"
        );

        snap.snap_element(
            Mi::new(String::from("i")).with_math_size(Some(MathSize::BIG)),
            "mi_big"
        );

        snap.snap_element(
            Mi::new(String::from("i")).with_math_color(Some(Color::RGB(255, 0, 0))),
            "mi_red"
        );

        snap.snap_element(
            Mi::new(String::from("i")).with_math_background(Some(Color::RGB(255, 0, 0))),
            "mi_red_bg"
        );
    }
}<commit_msg>If length of text in Mi is 1, make default math variant italic<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::rc::Rc;
use std::any::Any;

use ::props::*;
use ::layout::{MiLayout, Layout};
use super::super::{
    TokenPrivate, Token, PresentationPrivate, Presentation, SpecifiedTokenProps, PropertyCalculator,
    SpecifiedPresentationProps, Element, InheritedProps, StyleProps, ElementType, TokenElement, Property};
use ::draw::*;
use ::platform::*;

pub struct Mi {
    token_props: SpecifiedTokenProps,
    presentation_props: SpecifiedPresentationProps,
}

impl Mi {
    pub fn new(text: String) -> Mi {
        Mi {
            token_props: SpecifiedTokenProps {
                text: Rc::new(text),
                math_variant: None,
                math_size: None,
                dir: None,
            },
            presentation_props: SpecifiedPresentationProps {
                math_color: None,
                math_background: None,
            }
        }
    }
}

impl Element for Mi {
    fn layout(&self, context: &Context, parent: Option<&Element>, inherited: &InheritedProps,
              style: &Option<&StyleProps>) -> Box<Layout> {
        let mut calculator = PropertyCalculator::new(
            context, self, parent, inherited, style.clone());

        Box::new(MiLayout {
            token_element: self.layout_token_element(context, &mut calculator)
        })
    }

    fn type_info(&self) -> ElementType {
        ElementType::TokenElement(TokenElement::Mi)
    }

    fn as_any(&self) -> &Any {
        self
    }
}

impl PresentationPrivate<Mi> for Mi {
    fn get_specified_presentation_props(&self) -> &SpecifiedPresentationProps {
        &self.presentation_props
    }

    fn get_specified_presentation_props_mut(&mut self) -> &mut SpecifiedPresentationProps {
        &mut self.presentation_props
    }
}

impl TokenPrivate<Mi> for Mi {
    const PROP_MATH_VARIANT: Property<MathVariant, Mi> = Property::Computed {
        default:    || MathVariant::Normal,
        computer:   |ctx, elm, parent| {
            let text = elm.get_text();
            if text.len() == 1 {
                return Some(MathVariant::Italic);
            }
            return None;
        },
        reader:     |s| s.math_variant(),
    };

    fn get_specified_token_props(&self) -> &SpecifiedTokenProps {
        &self.token_props
    }

    fn get_specified_token_props_mut(&mut self) -> &mut SpecifiedTokenProps {
        &mut self.token_props
    }
}

impl Token<Mi> for Mi {}

impl Presentation<Mi> for Mi {}

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

    #[test]
    fn it_works() {
        let snap = Snapshot::default();
        snap.snap_element(&Mi::new(String::from("i")), "mi_normal");

        snap.snap_element(
            &Mi::new(String::from("i")),
            "mi_normal_identifier"
        );

        snap.snap_element(
            &Mi::new(String::from("ix")),
            "mi_text"
        );

        snap.snap_element(
            Mi::new(String::from("i")).with_math_size(Some(MathSize::BIG)),
            "mi_big"
        );

        snap.snap_element(
            Mi::new(String::from("i")).with_math_color(Some(Color::RGB(255, 0, 0))),
            "mi_red"
        );

        snap.snap_element(
            Mi::new(String::from("i")).with_math_background(Some(Color::RGB(255, 0, 0))),
            "mi_red_bg"
        );
    }
}<|endoftext|>


<commit_before>use wlroots_sys::{wlr_event_keyboard_key, xkb_keysym_t, xkb_state, xkb_state_key_get_syms};

pub type Key = xkb_keysym_t;

#[derive(Debug)]
pub struct KeyEvent {
    key: *mut wlr_event_keyboard_key,
    xkb_state: *mut xkb_state
}

impl KeyEvent {
    pub(crate) unsafe fn new(key: *mut wlr_event_keyboard_key, xkb_state: *mut xkb_state) -> Self {
        KeyEvent { key, xkb_state }
    }

    pub fn keycode(&self) -> u32 {
        unsafe { (*self.key).keycode + 8 }
    }

    pub fn input_keys(&self) -> Vec<Key> {
        unsafe {
            let mut syms = 0 as *const xkb_keysym_t;
            let key_length = xkb_state_key_get_syms(self.xkb_state, self.keycode(), &mut syms);
            (0..key_length).map(|index| *syms.offset(index as isize))
                           .collect()
        }
    }
}
<commit_msg>Document KeyEvent<commit_after>use wlroots_sys::{wlr_event_keyboard_key, xkb_keysym_t, xkb_state, xkb_state_key_get_syms};

pub type Key = xkb_keysym_t;

#[derive(Debug)]
pub struct KeyEvent {
    key: *mut wlr_event_keyboard_key,
    xkb_state: *mut xkb_state
}

impl KeyEvent {
    /// Constructs a KeyEvent from the raw key event pointer information.
    pub(crate) unsafe fn new(key: *mut wlr_event_keyboard_key, xkb_state: *mut xkb_state) -> Self {
        KeyEvent { key, xkb_state }
    }

    /// Gets the raw keycode from the device.
    ///
    /// Usually you want to use `KeyEvent::input_keys` since you care about what
    /// value XKB says this is.
    pub fn keycode(&self) -> u32 {
        unsafe { (*self.key).keycode + 8 }
    }

    /// Gets the keys that are pressed using XKB to convert them to a more
    /// programmer friendly form.
    pub fn input_keys(&self) -> Vec<Key> {
        unsafe {
            let mut syms = 0 as *const xkb_keysym_t;
            let key_length = xkb_state_key_get_syms(self.xkb_state, self.keycode(), &mut syms);
            (0..key_length).map(|index| *syms.offset(index as isize))
                           .collect()
        }
    }
}
<|endoftext|>


<commit_before>use glutin::Window;

use event::{Event, React};
use render::{AspectRatio, GlutinRenderer, MetaRenderer, Renderer};

pub trait ContextView {
    type Data: React;
    type Window: AspectRatio;

    fn data(&self) -> &Self::Data;
    fn window(&self) -> &Self::Window;
}

pub trait UpdateContextView: ContextView {
}

pub trait RenderContextView<R>: ContextView
    where R: MetaRenderer
{
    fn renderer(&self) -> &Renderer<R>;
    fn renderer_mut(&mut self) -> &mut Renderer<R>;
}

pub struct Context<T, R>
    where T: React,
          R: MetaRenderer
{
    pub data: T,
    pub renderer: Renderer<R>,
}

impl<T, R> Context<T, R>
    where T: React,
          R: MetaRenderer
{
    pub fn new(data: T, renderer: Renderer<R>) -> Self {
        Context {
            data: data,
            renderer: renderer,
        }
    }
}

impl<T> Context<T, GlutinRenderer>
    where T: React
{
    pub fn from_glutin_window(data: T, window: Window) -> Self {
        Context::new(data, Renderer::from_glutin_window(window))
    }
}

impl<T, R> ContextView for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    type Data = T;
    type Window = R::Window;

    fn data(&self) -> &Self::Data {
        &self.data
    }

    fn window(&self) -> &Self::Window {
        &self.renderer.window
    }
}

impl<T, R> UpdateContextView for Context<T, R>
    where T: React,
          R: MetaRenderer
{
}

impl<T, R> RenderContextView<R> for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    fn renderer(&self) -> &Renderer<R> {
        &self.renderer
    }

    fn renderer_mut(&mut self) -> &mut Renderer<R> {
        &mut self.renderer
    }
}

impl<T, R> React for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    fn react(&mut self, event: &Event) {
        self.data.react(event);
        self.renderer.react(event);
    }
}
<commit_msg>Provide mutable access to user data from `UpdateContextView`.<commit_after>use glutin::Window;

use event::{Event, React};
use render::{AspectRatio, GlutinRenderer, MetaRenderer, Renderer};

pub trait ContextView {
    type Data: React;
    type Window: AspectRatio;

    fn data(&self) -> &Self::Data;
    fn window(&self) -> &Self::Window;
}

pub trait UpdateContextView: ContextView {
    fn data_mut(&mut self) -> &mut Self::Data;
}

pub trait RenderContextView<R>: ContextView
    where R: MetaRenderer
{
    fn renderer(&self) -> &Renderer<R>;
    fn renderer_mut(&mut self) -> &mut Renderer<R>;
}

pub struct Context<T, R>
    where T: React,
          R: MetaRenderer
{
    pub data: T,
    pub renderer: Renderer<R>,
}

impl<T, R> Context<T, R>
    where T: React,
          R: MetaRenderer
{
    pub fn new(data: T, renderer: Renderer<R>) -> Self {
        Context {
            data: data,
            renderer: renderer,
        }
    }
}

impl<T> Context<T, GlutinRenderer>
    where T: React
{
    pub fn from_glutin_window(data: T, window: Window) -> Self {
        Context::new(data, Renderer::from_glutin_window(window))
    }
}

impl<T, R> ContextView for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    type Data = T;
    type Window = R::Window;

    fn data(&self) -> &Self::Data {
        &self.data
    }

    fn window(&self) -> &Self::Window {
        &self.renderer.window
    }
}

impl<T, R> UpdateContextView for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    fn data_mut(&mut self) -> &mut Self::Data {
        &mut self.data
    }
}

impl<T, R> RenderContextView<R> for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    fn renderer(&self) -> &Renderer<R> {
        &self.renderer
    }

    fn renderer_mut(&mut self) -> &mut Renderer<R> {
        &mut self.renderer
    }
}

impl<T, R> React for Context<T, R>
    where T: React,
          R: MetaRenderer
{
    fn react(&mut self, event: &Event) {
        self.data.react(event);
        self.renderer.react(event);
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate hyper;
extern crate treexml;
use getopts::Options;
use std::thread;
use std::sync::mpsc;
use std::env;
use std::io::Read;
use hyper::Client;
use hyper::header::Connection;
use treexml::Document;
use std::cmp::Ordering;

enum ApiResult {
    Error{city: String, error: String},
    WeatherReport{city: String, temp: f32, max:f32, min:f32, conditions: String}
}

fn api_call(city:&String, api_key:&String) -> ApiResult {
    let url = format!("http://api.openweathermap.org/data/2.5/weather?q={}&mode=xml&units=metric&appid={}&lang=sp", city, api_key);
    let client = Client::new();

    for _ in 1..10 {
        match client.get(&url).header(Connection::close()).send() {
            Err(_) => {
                std::thread::sleep(std::time::Duration::from_millis(100))
            },
            Ok(mut req) => {
                let mut body = String::new();
                req.read_to_string(&mut body).unwrap();
                match Document::parse(body.as_bytes()) {
                    Err(_) => {
                        std::thread::sleep(std::time::Duration::from_millis(100))
                    },
                    Ok(doc) => {
                        let root = doc.root.unwrap();
                        let temp = root.find_child(|tag| tag.name == "temperature").unwrap().clone();
                        let weather = root.find_child(|tag| tag.name == "weather").unwrap().clone();

                        let min_temp: f32= temp.attributes["min"].parse().unwrap();
                        let max_temp: f32= temp.attributes["max"].parse().unwrap();
                        let cur_temp: f32= temp.attributes["value"].parse().unwrap();

                        return ApiResult::WeatherReport{city: city.clone(),
                            temp: cur_temp, max: max_temp, min:min_temp,
                            conditions: weather.attributes["value"].clone() }
                    }
                }
            }
        }
    }
    ApiResult::Error{city: city.clone(), error: "error invocando api".to_string()}
}

fn par_fetch(cities:&Vec<String>, api_key:String) -> Vec<ApiResult> {
    let (tx, rx) = mpsc::channel();

    for city in cities {
        let tx = tx.clone();
        let city = city.clone();
        let api_key = api_key.clone();
        thread::spawn(move || {
            let report = api_call(&city, &api_key);
            tx.send(report).unwrap();
        });
    }
    let mut reports : Vec<ApiResult> = Vec::with_capacity(cities.len());
    for _ in cities {
        let rep = rx.recv().unwrap();
        reports.push(rep);
    }
   reports
}

fn seq_fetch(cities:&Vec<String>, api_key:String) -> Vec<ApiResult> {
    let mut reports : Vec<ApiResult> = Vec::with_capacity(cities.len());
    for city in cities {
        reports.push(api_call(city, &api_key));
    }
    reports
}

fn comp_api_result(a:&ApiResult, b:&ApiResult) -> Ordering {
    match a {
        &ApiResult::Error{city:_, error:_} => Ordering::Less,
        &ApiResult::WeatherReport{city:_, temp:ta, max:_, min:_, conditions:_} =>
            match b {
                &ApiResult::Error{city:_, error:_} => Ordering::Less,
                &ApiResult::WeatherReport{city:_, temp:tb, max:_, min:_, conditions:_} =>
                    if ta > tb { Ordering::Less } else { Ordering::Greater }
            }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("p", "par", "ejecuta la busqueda en paralelo");
    let matches = match opts.parse(&args[1..]) {
    	Ok(m) => { m }
    	Err(f) => { panic!(f.to_string()) }
    };
    let par = matches.opt_present("p");
    let cities = matches.free;
    if cities.is_empty() {
    	println!("debe ingresar una lista de ciudades");
    	return;
    }
    let api_key = match env::var("WEATHER_API_KEY") {
        Ok(val) => val,
        Err(_) => "".to_string()
    };

    let t0 = std::time::Instant::now();
    let mut result = if par { par_fetch(&cities, api_key) } else { seq_fetch(&cities, api_key) };

    result.sort_by(|a,b| comp_api_result(&a,&b));
    for report in result {
        match report {
            ApiResult::Error{city:c, error:e} => { println!("{:?} Error: {:?}", e, c) }
            ApiResult::WeatherReport{city, temp, max, min, conditions} =>  { println!("{:<30} max:{:5.1}  min:{:5.1}   actual: {:5.1} {}", city, temp, max, min, conditions) }
        }
    }
    let dur = t0.elapsed();
    let secs = dur.as_secs();
    let nanos = dur.subsec_nanos();
    let hours = secs / 3600;
    let mins  = (secs % 3600) / 60;
    let sec  = (secs % 3600) % 60;
    let frac  = nanos/1000000;
    println!("tiempo ocupado para generar el reporte: {} = {}:{}:{}.{}", secs, hours, mins, sec, frac);

}
<commit_msg>Re escribe la obtención de la API_KEY.<commit_after>extern crate getopts;
extern crate hyper;
extern crate treexml;
use getopts::Options;
use std::thread;
use std::sync::mpsc;
use std::env;
use std::io::Read;
use hyper::Client;
use hyper::header::Connection;
use treexml::Document;
use std::cmp::Ordering;

enum ApiResult {
    Error{city: String, error: String},
    WeatherReport{city: String, temp: f32, max:f32, min:f32, conditions: String}
}

fn api_call(city:&String, api_key:&String) -> ApiResult {
    let url = format!("http://api.openweathermap.org/data/2.5/weather?q={}&mode=xml&units=metric&appid={}&lang=sp", city, api_key);
    let client = Client::new();

    for _ in 1..10 {
        match client.get(&url).header(Connection::close()).send() {
            Err(_) => {
                std::thread::sleep(std::time::Duration::from_millis(100))
            },
            Ok(mut req) => {
                let mut body = String::new();
                req.read_to_string(&mut body).unwrap();
                match Document::parse(body.as_bytes()) {
                    Err(_) => {
                        std::thread::sleep(std::time::Duration::from_millis(100))
                    },
                    Ok(doc) => {
                        let root = doc.root.unwrap();
                        let temp = root.find_child(|tag| tag.name == "temperature").unwrap().clone();
                        let weather = root.find_child(|tag| tag.name == "weather").unwrap().clone();

                        let min_temp: f32= temp.attributes["min"].parse().unwrap();
                        let max_temp: f32= temp.attributes["max"].parse().unwrap();
                        let cur_temp: f32= temp.attributes["value"].parse().unwrap();

                        return ApiResult::WeatherReport{city: city.clone(),
                            temp: cur_temp, max: max_temp, min:min_temp,
                            conditions: weather.attributes["value"].clone() }
                    }
                }
            }
        }
    }
    ApiResult::Error{city: city.clone(), error: "error invocando api".to_string()}
}

fn par_fetch(cities:&Vec<String>, api_key:String) -> Vec<ApiResult> {
    let (tx, rx) = mpsc::channel();

    for city in cities {
        let tx = tx.clone();
        let city = city.clone();
        let api_key = api_key.clone();
        thread::spawn(move || {
            let report = api_call(&city, &api_key);
            tx.send(report).unwrap();
        });
    }
    let mut reports : Vec<ApiResult> = Vec::with_capacity(cities.len());
    for _ in cities {
        let rep = rx.recv().unwrap();
        reports.push(rep);
    }
   reports
}

fn seq_fetch(cities:&Vec<String>, api_key:String) -> Vec<ApiResult> {
    let mut reports : Vec<ApiResult> = Vec::with_capacity(cities.len());
    for city in cities {
        reports.push(api_call(city, &api_key));
    }
    reports
}

fn comp_api_result(a:&ApiResult, b:&ApiResult) -> Ordering {
    match a {
        &ApiResult::Error{city:_, error:_} => Ordering::Less,
        &ApiResult::WeatherReport{city:_, temp:ta, max:_, min:_, conditions:_} =>
            match b {
                &ApiResult::Error{city:_, error:_} => Ordering::Less,
                &ApiResult::WeatherReport{city:_, temp:tb, max:_, min:_, conditions:_} =>
                    if ta > tb { Ordering::Less } else { Ordering::Greater }
            }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optflag("p", "par", "ejecuta la busqueda en paralelo");
    let matches = match opts.parse(&args[1..]) {
    	Ok(m) => { m }
    	Err(f) => { panic!(f.to_string()) }
    };
    let par = matches.opt_present("p");
    let cities = matches.free;
    if cities.is_empty() {
    	println!("debe ingresar una lista de ciudades");
    	return;
    }
    let api_key = env::var("WEATHER_API_KEY").expect("debe definir WEATHER_API_KEY");

    let t0 = std::time::Instant::now();
    let mut result = if par { par_fetch(&cities, api_key) } else { seq_fetch(&cities, api_key) };

    result.sort_by(|a,b| comp_api_result(&a,&b));
    for report in result {
        match report {
            ApiResult::Error{city:c, error:e} => { println!("{:?} Error: {:?}", e, c) }
            ApiResult::WeatherReport{city, temp, max, min, conditions} =>  { println!("{:<30} max:{:5.1}  min:{:5.1}   actual: {:5.1} {}", city, temp, max, min, conditions) }
        }
    }
    let dur = t0.elapsed();
    let secs = dur.as_secs();
    let nanos = dur.subsec_nanos();
    let hours = secs / 3600;
    let mins  = (secs % 3600) / 60;
    let sec  = (secs % 3600) % 60;
    let frac  = nanos/1000000;
    println!("tiempo ocupado para generar el reporte: {} = {}:{}:{}.{}", secs, hours, mins, sec, frac);

}
<|endoftext|>


<commit_before>use decoders::RawImage;
use decoders::cfa::CFA;
use imageops::*;
use std::cmp;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OpDemosaic {
  cfa: String,
}

impl OpDemosaic {
  pub fn new(img: &RawImage) -> OpDemosaic {
    OpDemosaic{
      cfa: img.cropped_cfa().to_string(),
    }
  }
}

impl<'a> ImageOp<'a> for OpDemosaic {
  fn name(&self) -> &str {"demosaic"}
  fn run(&self, pipeline: &mut PipelineGlobals, inid: BufHash, outid: BufHash) {
    let buf = pipeline.cache.get(inid).unwrap();

    let (scale, nwidth, nheight) = if pipeline.maxwidth == 0 || pipeline.maxheight == 0 {
      (0.0, buf.width, buf.height)
    } else {
      // Do the calculations manually to avoid off-by-one errors from floating point rounding
      let xscale = (buf.width as f32) / (pipeline.maxwidth as f32);
      let yscale = (buf.height as f32) / (pipeline.maxheight as f32);
      if yscale > xscale {
        (yscale, ((buf.width as f32)/yscale) as usize, pipeline.maxheight)
      } else {
        (xscale, pipeline.maxwidth, ((buf.height as f32)/xscale) as usize)
      }
    };

    let cfa = CFA::new(&self.cfa);
    let minscale = match cfa.width {
      2  => 2.0,  // RGGB/RGBE bayer
      6  => 3.0,  // x-trans is 6 wide but has all colors in every 3x3 block
      8  => 2.0,  // Canon pro 70 has a 8x2 patern that has all four colors every 2x2 block
      12 => 12.0, // some crazy sensor I haven't actually encountered, use full block
      _  => 2.0,  // default
    };

    // If we want full size and the image is already 4 color pass it through
    if (scale < minscale || buf.colors != 1) && buf.colors == 4 {
      pipeline.cache.alias(inid, outid);
    // If we're not scaling enough do full demosaic and then scale down
    } else if scale < minscale  {
      let fullsize = full(cfa, &buf);
      let buf = if scale > 1.0 {
        scale_down(&fullsize, nwidth, nheight)
      } else {
        fullsize
      };
      pipeline.cache.put(outid, buf, 1);
    // Do a demosaic by scaling down
    } else {
      let buf = scaled(cfa, &buf, nwidth, nheight);
      pipeline.cache.put(outid, buf, 1);
    }
  }
}

pub fn full(cfa: CFA, buf: &OpBuffer) -> OpBuffer {
  let mut out = OpBuffer::new(buf.width, buf.height, 4);

  // First we set the colors we already have
  out.mutate_lines(&(|line: &mut [f32], row| {
    for (col, (pixout, pixin)) in line.chunks_mut(4).zip(buf.data[buf.width*row..].chunks(1)).enumerate() {
      let color = cfa.color_at(row, col);
      pixout[color] = pixin[0] as f32;
    }
  }));

  // Now we go around the image setting the unset colors to the average of the
  // surrounding pixels
  out.mutate_lines(&(|line: &mut [f32], row| {
    for col in 0..buf.width {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [u32; 4] = [0; 4];
      let color = cfa.color_at(row, col);

      for y in (cmp::max(0,(row as isize)-1) as usize) .. cmp::min(buf.height, row+2) {
        for x in (cmp::max(0,(col as isize)-1) as usize) .. cmp::min(buf.width, col+2) {
          let c = cfa.color_at(y, x);
          if c != color {
            sums[c] += buf.data[y*buf.width+x] as f32;
            counts[c] += 1;
          }
        }
      }

      for c in 0..4 {
        if c != color && counts[c] > 0 {
          line[col*4+c] = sums[c] / (counts[c] as f32);
        }
      }
    }
  }));

  out
}

fn calc_skips(idx: usize, idxmax: usize, skip: f32) -> (usize, usize, f32, f32) {
  let from = (idx as f32)*skip;
  let fromback = from.floor();
  let fromfactor = 1.0 - (from-fromback).fract();

  let to = ((idx+1) as f32)*skip;
  let toforward = (idxmax as f32).min(to.ceil());
  let tofactor = (toforward-to).fract();

  (fromback as usize, toforward as usize, fromfactor, tofactor)
}

pub fn scaled(cfa: CFA, buf: &OpBuffer, nwidth: usize, nheight: usize) -> OpBuffer {
  let mut out = OpBuffer::new(nwidth, nheight, 4);

  let rowskip = (buf.width as f32) / (nwidth as f32);
  let colskip = (buf.height as f32) / (nheight as f32);

  // Go around the image averaging blocks of pixels
  out.mutate_lines(&(|line: &mut [f32], row| {
    for col in 0..nwidth {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [f32; 4] = [0.0;4];
      let (fromrow, torow, topfactor, bottomfactor) = calc_skips(row, buf.height, rowskip);
      for y in fromrow..torow {
        let (fromcol, tocol, leftfactor, rightfactor) = calc_skips(col, buf.width, colskip);
        for x in fromcol..tocol {
          let factor = {
            (if y == fromrow {topfactor} else if y == torow {bottomfactor} else {1.0}) *
            (if x == fromcol {leftfactor} else if x == tocol {rightfactor} else {1.0})
          };

          let c = cfa.color_at(y, x);
          sums[c] += (buf.data[y*buf.width+x] as f32) * factor;
          counts[c] += factor;
        }
      }

      for c in 0..4 {
        if counts[c] > 0.0 {
          line[col*4+c] = sums[c] / counts[c];
        }
      }
    }
  }));

  out
}

pub fn scale_down(buf: &OpBuffer, nwidth: usize, nheight: usize) -> OpBuffer {
  let mut out = OpBuffer::new(nwidth, nheight, buf.colors);
  let rowskip = (buf.width as f32) / (nwidth as f32);
  let colskip = (buf.height as f32) / (nheight as f32);

  // Go around the image averaging blocks of pixels
  out.mutate_lines(&(|line: &mut [f32], row| {
    for col in 0..nwidth {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [f32; 4] = [0.0;4];
      let (fromrow, torow, topfactor, bottomfactor) = calc_skips(row, buf.height, rowskip);
      for y in fromrow..torow {
        let (fromcol, tocol, leftfactor, rightfactor) = calc_skips(col, buf.width, colskip);
        for x in fromcol..tocol {
          let factor = {
            (if y == fromrow {topfactor} else if y == torow {bottomfactor} else {1.0}) *
            (if x == fromcol {leftfactor} else if x == tocol {rightfactor} else {1.0})
          };

          for c in 0..buf.colors {
            sums[c] += buf.data[(y*buf.width+x)*buf.colors + c] * factor;
            counts[c] += factor;
          }
        }
      }

      for c in 0..buf.colors {
        if counts[c] > 0.0 {
          line[col*buf.colors+c] = sums[c] / counts[c];
        }
      }
    }
  }));

  out
}
<commit_msg>demosaic: fix demosaic method logic choice<commit_after>use decoders::RawImage;
use decoders::cfa::CFA;
use imageops::*;
use std::cmp;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OpDemosaic {
  cfa: String,
}

impl OpDemosaic {
  pub fn new(img: &RawImage) -> OpDemosaic {
    OpDemosaic{
      cfa: img.cropped_cfa().to_string(),
    }
  }
}

impl<'a> ImageOp<'a> for OpDemosaic {
  fn name(&self) -> &str {"demosaic"}
  fn run(&self, pipeline: &mut PipelineGlobals, inid: BufHash, outid: BufHash) {
    let buf = pipeline.cache.get(inid).unwrap();

    let (scale, nwidth, nheight) = if pipeline.maxwidth == 0 || pipeline.maxheight == 0 {
      (1.0, buf.width, buf.height)
    } else {
      // Do the calculations manually to avoid off-by-one errors from floating point rounding
      let xscale = (buf.width as f32) / (pipeline.maxwidth as f32);
      let yscale = (buf.height as f32) / (pipeline.maxheight as f32);
      if yscale > xscale {
        (yscale, ((buf.width as f32)/yscale) as usize, pipeline.maxheight)
      } else {
        (xscale, pipeline.maxwidth, ((buf.height as f32)/xscale) as usize)
      }
    };

    let cfa = CFA::new(&self.cfa);
    let minscale = match cfa.width {
      2  => 2.0,  // RGGB/RGBE bayer
      6  => 3.0,  // x-trans is 6 wide but has all colors in every 3x3 block
      8  => 2.0,  // Canon pro 70 has a 8x2 patern that has all four colors every 2x2 block
      12 => 12.0, // some crazy sensor I haven't actually encountered, use full block
      _  => 2.0,  // default
    };

    if scale <= 1.0 && buf.colors == 4 {
      // We want full size and the image is already 4 color, pass it through
      pipeline.cache.alias(inid, outid);
    } else if buf.colors == 4 {
      // Scale down a 4 colour image
      let buf = scale_down(&buf, nwidth, nheight);
      pipeline.cache.put(outid, buf, 1);
    } else if scale >= minscale {
      // We're scaling down enough that each pixel has all four colors under it so do the
      // demosaic and scale down in one go
      let buf = scaled(cfa, &buf, nwidth, nheight);
      pipeline.cache.put(outid, buf, 1);
    } else {
      // We're in a close to full scale output that needs full demosaic and possibly
      // minimal scale down
      let fullsize = full(cfa, &buf);
      let buf = if scale > 1.0 {
        scale_down(&fullsize, nwidth, nheight)
      } else {
        fullsize
      };
      pipeline.cache.put(outid, buf, 1);
    }
  }
}

pub fn full(cfa: CFA, buf: &OpBuffer) -> OpBuffer {
  let mut out = OpBuffer::new(buf.width, buf.height, 4);

  // First we set the colors we already have
  out.mutate_lines(&(|line: &mut [f32], row| {
    for (col, (pixout, pixin)) in line.chunks_mut(4).zip(buf.data[buf.width*row..].chunks(1)).enumerate() {
      let color = cfa.color_at(row, col);
      pixout[color] = pixin[0] as f32;
    }
  }));

  // Now we go around the image setting the unset colors to the average of the
  // surrounding pixels
  out.mutate_lines(&(|line: &mut [f32], row| {
    for col in 0..buf.width {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [u32; 4] = [0; 4];
      let color = cfa.color_at(row, col);

      for y in (cmp::max(0,(row as isize)-1) as usize) .. cmp::min(buf.height, row+2) {
        for x in (cmp::max(0,(col as isize)-1) as usize) .. cmp::min(buf.width, col+2) {
          let c = cfa.color_at(y, x);
          if c != color {
            sums[c] += buf.data[y*buf.width+x] as f32;
            counts[c] += 1;
          }
        }
      }

      for c in 0..4 {
        if c != color && counts[c] > 0 {
          line[col*4+c] = sums[c] / (counts[c] as f32);
        }
      }
    }
  }));

  out
}

fn calc_skips(idx: usize, idxmax: usize, skip: f32) -> (usize, usize, f32, f32) {
  let from = (idx as f32)*skip;
  let fromback = from.floor();
  let fromfactor = 1.0 - (from-fromback).fract();

  let to = ((idx+1) as f32)*skip;
  let toforward = (idxmax as f32).min(to.ceil());
  let tofactor = (toforward-to).fract();

  (fromback as usize, toforward as usize, fromfactor, tofactor)
}

pub fn scaled(cfa: CFA, buf: &OpBuffer, nwidth: usize, nheight: usize) -> OpBuffer {
  let mut out = OpBuffer::new(nwidth, nheight, 4);

  let rowskip = (buf.width as f32) / (nwidth as f32);
  let colskip = (buf.height as f32) / (nheight as f32);

  // Go around the image averaging blocks of pixels
  out.mutate_lines(&(|line: &mut [f32], row| {
    for col in 0..nwidth {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [f32; 4] = [0.0;4];
      let (fromrow, torow, topfactor, bottomfactor) = calc_skips(row, buf.height, rowskip);
      for y in fromrow..torow {
        let (fromcol, tocol, leftfactor, rightfactor) = calc_skips(col, buf.width, colskip);
        for x in fromcol..tocol {
          let factor = {
            (if y == fromrow {topfactor} else if y == torow {bottomfactor} else {1.0}) *
            (if x == fromcol {leftfactor} else if x == tocol {rightfactor} else {1.0})
          };

          let c = cfa.color_at(y, x);
          sums[c] += (buf.data[y*buf.width+x] as f32) * factor;
          counts[c] += factor;
        }
      }

      for c in 0..4 {
        if counts[c] > 0.0 {
          line[col*4+c] = sums[c] / counts[c];
        }
      }
    }
  }));

  out
}

pub fn scale_down(buf: &OpBuffer, nwidth: usize, nheight: usize) -> OpBuffer {
  let mut out = OpBuffer::new(nwidth, nheight, buf.colors);
  let rowskip = (buf.width as f32) / (nwidth as f32);
  let colskip = (buf.height as f32) / (nheight as f32);

  // Go around the image averaging blocks of pixels
  out.mutate_lines(&(|line: &mut [f32], row| {
    for col in 0..nwidth {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [f32; 4] = [0.0;4];
      let (fromrow, torow, topfactor, bottomfactor) = calc_skips(row, buf.height, rowskip);
      for y in fromrow..torow {
        let (fromcol, tocol, leftfactor, rightfactor) = calc_skips(col, buf.width, colskip);
        for x in fromcol..tocol {
          let factor = {
            (if y == fromrow {topfactor} else if y == torow {bottomfactor} else {1.0}) *
            (if x == fromcol {leftfactor} else if x == tocol {rightfactor} else {1.0})
          };

          for c in 0..buf.colors {
            sums[c] += buf.data[(y*buf.width+x)*buf.colors + c] * factor;
            counts[c] += factor;
          }
        }
      }

      for c in 0..buf.colors {
        if counts[c] > 0.0 {
          line[col*buf.colors+c] = sums[c] / counts[c];
        }
      }
    }
  }));

  out
}
<|endoftext|>


<commit_before>//! Json formatter for `slog-rs`
//!
//! ```
//! #[macro_use]
//! extern crate slog;
//! extern crate slog_json;
//! extern crate slog_stream;
//!
//! use slog::DrainExt;
//!
//! fn main() {
//!     let root = slog::Logger::root(
//!         slog_stream::stream(
//!             std::io::stderr(),
//!             slog_json::new()
//!         ).fuse(),
//!         o!("build-id" => "8dfljdf")
//!     );
//! }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_serde;
extern crate slog_stream;
extern crate serde_json;
extern crate chrono;

use std::io;

use slog_serde::SerdeSerializer;
use slog::Record;
use slog::{Level, OwnedKeyValue, OwnedKeyValueList};
use slog::Level::*;
use slog::ser::{PushLazy, ValueSerializer};

fn level_to_string(level: Level) -> &'static str {
    match level {
        Critical => "CRIT",
        Error => "ERRO",
        Warning => "WARN",
        Info => "INFO",
        Debug => "DEBG",
        Trace => "TRCE",
    }
}

/// Json formatter
///
/// Each record will be printed as a Json map.
pub struct Format {
    newlines: bool,
    values: Vec<OwnedKeyValue>,
}

impl Format {
    /// Create new Json formatter
    ///
    /// It comes with some default fields (`ts`, `level`, `msg`)
    /// and uses newlines.
    ///
    /// Use `Format::build()` to build a custom Json formatter from
    /// scratch.
    pub fn new() -> Self {
        Format {
            newlines: true,
            values: o!(
                "ts" => PushLazy(move |_ : &Record, ser : ValueSerializer| {
                   ser.serialize(chrono::Local::now().to_rfc3339())
                }),
                "level" => move |rinfo : &Record| {
                    level_to_string(rinfo.level())
                },
                "msg" => PushLazy(move |record : &Record, ser : ValueSerializer| {
                   ser.serialize(record.msg())
                })
                ),
        }
    }

    /// Build a Json formatter with custom settings
    pub fn build() -> FormatBuilder {
        FormatBuilder::new()
    }

    /// Create new `Json` format that does not add
    /// newlines after each record.
    pub fn new_nonewline() -> Self {
        let mut json = Format::new();
        json.newlines = false;
        json
    }
}

/// Json formatter builder
///
/// Create with `Format::build`.
pub struct FormatBuilder {
    newlines: bool,
    values: Vec<OwnedKeyValue>,
}

impl FormatBuilder {
    fn new() -> Self {
        FormatBuilder {
            newlines: true,
            values: vec![],
        }
    }

    /// Build `Json` format
    ///
    /// This consumes the builder.
    pub fn build(self) -> Format {
        Format {
            values: self.values,
            newlines: self.newlines,
        }
    }

    /// Set writing a newline after ever log record
    pub fn set_newlines(&mut self, enabled: bool) -> &mut Self {
        self.newlines = enabled;
        self
    }

    /// Add custom values to be printed with this formatter
    pub fn add_key_values(&mut self, mut values: Vec<OwnedKeyValue>) -> &mut Self {
        self.values.extend(values.drain(..));
        self
    }

    /// Add custom values to be printed with this formatter
    pub fn add_key_value(&mut self, value: OwnedKeyValue) -> &mut Self {
        self.values.push(value);
        self
    }
}

// TODO: Get rid of after
// https://github.com/serde-rs/serde/issues/386
// is implemented
struct SkipFirstByte<W> {
    first: bool,
    io: W,
}

impl<W: io::Write> SkipFirstByte<W> {
    fn new(io: W) -> Self {
        SkipFirstByte {
            first: true,
            io: io,
        }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> io::Write for SkipFirstByte<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.first && !buf.is_empty() {
            self.first = false;
            try!(self.io.write_all(&buf[1..]));
        } else {
            try!(self.io.write_all(buf))
        }
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

impl slog_stream::Format for Format {
    fn format(&self,
              io: &mut io::Write,
              rinfo: &Record,
              logger_values: &OwnedKeyValueList)
              -> io::Result<()> {
        let _ = try!(write!(io, "{{"));
        let mut serializer = serde_json::Serializer::new(SkipFirstByte::new(io));
        {
            let mut serializer = &mut SerdeSerializer(&mut serializer);

            for &(ref k, ref v) in self.values.iter() {
                try!(v.serialize(rinfo, k, serializer));
            }
            for &(ref k, ref v) in logger_values.iter() {
                try!(v.serialize(rinfo, k, serializer));
            }

            for &(ref k, ref v) in rinfo.values().iter() {
                try!(v.serialize(rinfo, k, serializer));
            }
        }
        let mut io = serializer.into_inner().into_inner();
        let _ = try!(io.write_all("}".as_bytes()));
        if self.newlines {
            let _ = try!(io.write_all("\n".as_bytes()));
        }
        Ok(())
    }
}

/// Short for `Format::new()`
pub fn new() -> Format {
    Format::new()
}

/// Short for `FormatBuilder::build()`
pub fn build() -> FormatBuilder {
    Format::build()
}
<commit_msg>doc(json): Polishing<commit_after>//! Json formatter for `slog-rs`
//!
//! ```
//! #[macro_use]
//! extern crate slog;
//! extern crate slog_json;
//! extern crate slog_stream;
//!
//! use slog::DrainExt;
//!
//! fn main() {
//!     let root = slog::Logger::root(
//!         slog_stream::stream(
//!             std::io::stderr(),
//!             slog_json::new()
//!         ).fuse(),
//!         o!("build-id" => "8dfljdf")
//!     );
//! }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_serde;
extern crate slog_stream;
extern crate serde_json;
extern crate chrono;

use std::io;

use slog_serde::SerdeSerializer;
use slog::Record;
use slog::{Level, OwnedKeyValue, OwnedKeyValueList};
use slog::Level::*;
use slog::ser::{PushLazy, ValueSerializer};

fn level_to_string(level: Level) -> &'static str {
    match level {
        Critical => "CRIT",
        Error => "ERRO",
        Warning => "WARN",
        Info => "INFO",
        Debug => "DEBG",
        Trace => "TRCE",
    }
}

/// Json formatter
///
/// Each record will be printed as a Json map.
pub struct Format {
    newlines: bool,
    values: Vec<OwnedKeyValue>,
}

impl Format {
    /// Create new Json formatter
    ///
    /// It comes with some default fields (`ts`, `level`, `msg`)
    /// and uses newlines.
    ///
    /// Use `Format::build()` to build a custom Json formatter from
    /// scratch.
    pub fn new() -> Self {
        Format {
            newlines: true,
            values: o!(
                "ts" => PushLazy(move |_ : &Record, ser : ValueSerializer| {
                   ser.serialize(chrono::Local::now().to_rfc3339())
                }),
                "level" => move |rinfo : &Record| {
                    level_to_string(rinfo.level())
                },
                "msg" => PushLazy(move |record : &Record, ser : ValueSerializer| {
                   ser.serialize(record.msg())
                })
                ),
        }
    }

    /// Build a Json formatter with custom settings
    pub fn build() -> FormatBuilder {
        FormatBuilder::new()
    }

    /// Create new `Json` format that does not add
    /// newlines after each record.
    pub fn new_nonewline() -> Self {
        let mut json = Format::new();
        json.newlines = false;
        json
    }
}

/// Json formatter builder
///
/// Create with `Format::build`.
pub struct FormatBuilder {
    newlines: bool,
    values: Vec<OwnedKeyValue>,
}

impl FormatBuilder {
    fn new() -> Self {
        FormatBuilder {
            newlines: true,
            values: vec![],
        }
    }

    /// Build `Json` format
    ///
    /// This consumes the builder.
    pub fn build(self) -> Format {
        Format {
            values: self.values,
            newlines: self.newlines,
        }
    }

    /// Set writing a newline after ever log record
    pub fn set_newlines(&mut self, enabled: bool) -> &mut Self {
        self.newlines = enabled;
        self
    }

    /// Add custom values to be printed with this formatter
    pub fn add_key_values(&mut self, mut values: Vec<OwnedKeyValue>) -> &mut Self {
        self.values.extend(values.drain(..));
        self
    }

    /// Add custom values to be printed with this formatter
    pub fn add_key_value(&mut self, value: OwnedKeyValue) -> &mut Self {
        self.values.push(value);
        self
    }
}

// TODO: Get rid of after
// https://github.com/serde-rs/serde/issues/386
// is implemented
struct SkipFirstByte<W> {
    first: bool,
    io: W,
}

impl<W: io::Write> SkipFirstByte<W> {
    fn new(io: W) -> Self {
        SkipFirstByte {
            first: true,
            io: io,
        }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> io::Write for SkipFirstByte<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.first && !buf.is_empty() {
            self.first = false;
            try!(self.io.write_all(&buf[1..]));
        } else {
            try!(self.io.write_all(buf))
        }
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

impl slog_stream::Format for Format {
    fn format(&self,
              io: &mut io::Write,
              rinfo: &Record,
              logger_values: &OwnedKeyValueList)
              -> io::Result<()> {
        let _ = try!(write!(io, "{{"));
        let mut serializer = serde_json::Serializer::new(SkipFirstByte::new(io));
        {
            let mut serializer = &mut SerdeSerializer(&mut serializer);

            for &(ref k, ref v) in self.values.iter() {
                try!(v.serialize(rinfo, k, serializer));
            }
            for &(ref k, ref v) in logger_values.iter() {
                try!(v.serialize(rinfo, k, serializer));
            }

            for &(ref k, ref v) in rinfo.values().iter() {
                try!(v.serialize(rinfo, k, serializer));
            }
        }
        let mut io = serializer.into_inner().into_inner();
        let _ = try!(io.write_all("}".as_bytes()));
        if self.newlines {
            let _ = try!(io.write_all("\n".as_bytes()));
        }
        Ok(())
    }
}

/// Build a default Json formatter
///
/// See `Format::new()` for details
pub fn new() -> Format {
    Format::new()
}

/// Use builder to create a custom Json formatter
///
/// See `FormatBuilder` for details
pub fn build() -> FormatBuilder {
    Format::build()
}
<|endoftext|>


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

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!(str::all(~"banana", |c| c.is_ascii()));
        assert!(! str::all(~"ประเทศไทย中华Việt Nam", |c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<commit_msg>Fixed typo... And a billion other things.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use to_str::{ToStr,ToStrConsume};
use str;
use cast;

/// Datatype to hold one ascii character. It is 8 bit long.
#[deriving(Clone, Eq)]
pub struct Ascii { priv chr: u8 }

pub impl Ascii {
    /// Converts a ascii character into a `u8`.
    #[inline(always)]
    fn to_byte(self) -> u8 {
        self.chr
    }

    /// Converts a ascii character into a `char`.
    #[inline(always)]
    fn to_char(self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline(always)]
    fn to_lower(self) -> Ascii {
        if self.chr >= 65 && self.chr <= 90 {
            Ascii{chr: self.chr | 0x20 }
        } else {
            self
        }
    }

    /// Convert to uppercase.
    #[inline(always)]
    fn to_upper(self) -> Ascii {
        if self.chr >= 97 && self.chr <= 122 {
            Ascii{chr: self.chr & !0x20 }
        } else {
            self
        }
    }

    // Compares two ascii characters of equality, ignoring case.
    #[inline(always)]
    fn eq_ignore_case(self, other: Ascii) -> bool {
        self.to_lower().chr == other.to_lower().chr
    }
}

impl ToStr for Ascii {
    #[inline(always)]
    fn to_str(&self) -> ~str { str::from_bytes(['\'' as u8, self.chr, '\'' as u8]) }
}

/// Trait for converting into an ascii type.
pub trait AsciiCast<T> {
    /// Convert to an ascii type
    fn to_ascii(&self) -> T;

    /// Check if convertible to ascii
    fn is_ascii(&self) -> bool;
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        unsafe{ cast::transmute(*self) }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
    #[inline(always)]
    fn to_ascii(&self) -> &'self[Ascii] {
        assert!(self.is_ascii());
        let (p,len): (*u8, uint) = unsafe{ cast::transmute(*self) };
        unsafe{ cast::transmute((p, len - 1))}
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        for self.each |b| {
            if !b.is_ascii() { return false; }
        }
        true
    }
}

impl AsciiCast<Ascii> for u8 {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self & 128 == 0u8
    }
}

impl AsciiCast<Ascii> for char {
    #[inline(always)]
    fn to_ascii(&self) -> Ascii {
        assert!(self.is_ascii());
        Ascii{ chr: *self as u8 }
    }

    #[inline(always)]
    fn is_ascii(&self) -> bool {
        *self - ('\x7F' & *self) == '\x00'
    }
}

/// Trait for copyless casting to an ascii vector.
pub trait OwnedAsciiCast {
    /// Take ownership and cast to an ascii vector without trailing zero element.
    fn to_ascii_consume(self) -> ~[Ascii];
}

impl OwnedAsciiCast for ~[u8] {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        unsafe {cast::transmute(self)}
    }
}

impl OwnedAsciiCast for ~str {
    #[inline(always)]
    fn to_ascii_consume(self) -> ~[Ascii] {
        assert!(self.is_ascii());
        let mut s = self;
        unsafe {
            str::raw::pop_byte(&mut s);
            cast::transmute(s)
        }
    }
}

/// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
pub trait AsciiStr {
    /// Convert to a string.
    fn to_str_ascii(&self) -> ~str;

    /// Convert to vector representing a lower cased ascii string.
    fn to_lower(&self) -> ~[Ascii];

    /// Convert to vector representing a upper cased ascii string.
    fn to_upper(&self) -> ~[Ascii];

}

impl<'self> AsciiStr for &'self [Ascii] {
    #[inline(always)]
    fn to_str_ascii(&self) -> ~str {
        let mut cpy = self.to_owned();
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }

    #[inline(always)]
    fn to_lower(&self) -> ~[Ascii] {
        self.map(|a| a.to_lower())
    }

    #[inline(always)]
    fn to_upper(&self) -> ~[Ascii] {
        self.map(|a| a.to_upper())
    }
}

impl ToStrConsume for ~[Ascii] {
    #[inline(always)]
    fn to_str_consume(self) -> ~str {
        let mut cpy = self;
        cpy.push(0u8.to_ascii());
        unsafe {cast::transmute(cpy)}
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
        (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]);
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().to_byte(), 65u8);
        assert_eq!(65u8.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_char(), 'A');
        assert_eq!('A'.to_ascii().to_byte(), 65u8);

        assert_eq!('A'.to_ascii().to_lower().to_char(), 'a');
        assert_eq!('Z'.to_ascii().to_lower().to_char(), 'z');
        assert_eq!('a'.to_ascii().to_upper().to_char(), 'A');
        assert_eq!('z'.to_ascii().to_upper().to_char(), 'Z');

        assert_eq!('@'.to_ascii().to_lower().to_char(), '@');
        assert_eq!('['.to_ascii().to_lower().to_char(), '[');
        assert_eq!('`'.to_ascii().to_upper().to_char(), '`');
        assert_eq!('{'.to_ascii().to_upper().to_char(), '{');

        assert!(str::all(~"banana", |c| c.is_ascii()));
        assert!(! str::all(~"ประเทศไทย中华Việt Nam", |c| c.is_ascii()));
    }

    #[test]
    fn test_ascii_vec() {
        assert_eq!((&[40u8, 32u8, 59u8]).to_ascii(), v2ascii!([40, 32, 59]));
        assert_eq!("( ;".to_ascii(),                 v2ascii!([40, 32, 59]));
        // FIXME: #5475 borrowchk error, owned vectors do not live long enough
        // if chained-from directly
        let v = ~[40u8, 32u8, 59u8]; assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));
        let v = ~"( ;";              assert_eq!(v.to_ascii(), v2ascii!([40, 32, 59]));

        assert_eq!("abCDef&?#".to_ascii().to_lower().to_str_ascii(), ~"abcdef&?#");
        assert_eq!("abCDef&?#".to_ascii().to_upper().to_str_ascii(), ~"ABCDEF&?#");

        assert_eq!("".to_ascii().to_lower().to_str_ascii(), ~"");
        assert_eq!("YMCA".to_ascii().to_lower().to_str_ascii(), ~"ymca");
        assert_eq!("abcDEFxyz:.;".to_ascii().to_upper().to_str_ascii(), ~"ABCDEFXYZ:.;");

        assert!("".is_ascii());
        assert!("a".is_ascii());
        assert!(!"\u2009".is_ascii());

    }

    #[test]
    fn test_owned_ascii_vec() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(~"( ;".to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume(), v2ascii!(~[40, 32, 59]));
        //assert_eq!(~"( ;".to_ascii_consume_with_null(), v2ascii!(~[40, 32, 59, 0]));
        //assert_eq!(~[40u8, 32u8, 59u8].to_ascii_consume_with_null(),
        //           v2ascii!(~[40, 32, 59, 0]));
    }

    #[test]
    fn test_ascii_to_str() { assert_eq!(v2ascii!([40, 32, 59]).to_str_ascii(), ~"( ;"); }

    #[test]
    fn test_ascii_to_str_consume() {
        // FIXME: #4318 Compiler crashes on moving self
        //assert_eq!(v2ascii!(~[40, 32, 59]).to_str_consume(), ~"( ;");
    }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_fail_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
}
<|endoftext|>


<commit_before>
//! Common types for the Cretonne code generator.

use std::fmt::{self, Display, Formatter, Write};

// ====--------------------------------------------------------------------------------------====//
//
// Value types
//
// ====--------------------------------------------------------------------------------------====//

/// The type of an SSA value.
///
/// The `VOID` type is only used for instructions that produce no value. It can't be part of a SIMD
/// vector.
///
/// Basic integer types: `I8`, `I16`, `I32`, and `I64`. These types are sign-agnostic.
///
/// Basic floating point types: `F32` and `F64`. IEEE single and double precision.
///
/// Boolean types: `B1`, `B8`, `B16`, `B32`, and `B64`. These all encode 'true' or 'false'. The
/// larger types use redundant bits.
///
/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float/bool type.
///
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Type(u8);

/// No type. Used for functions without a return value. Can't be loaded or stored. Can't be part of
/// a SIMD vector.
pub const VOID: Type = Type(0);

/// Integer type with 8 bits.
pub const I8: Type = Type(1);

/// Integer type with 16 bits.
pub const I16: Type = Type(2);

/// Integer type with 32 bits.
pub const I32: Type = Type(3);

/// Integer type with 64 bits.
pub const I64: Type = Type(4);

/// IEEE single precision floating point type.
pub const F32: Type = Type(5);

/// IEEE double precision floating point type.
pub const F64: Type = Type(6);

/// Boolean type. Can't be loaded or stored, but can be used to form SIMD vectors.
pub const B1: Type = Type(7);

/// Boolean type using 8 bits to represent true/false.
pub const B8: Type = Type(8);

/// Boolean type using 16 bits to represent true/false.
pub const B16: Type = Type(9);

/// Boolean type using 32 bits to represent true/false.
pub const B32: Type = Type(10);

/// Boolean type using 64 bits to represent true/false.
pub const B64: Type = Type(11);

impl Type {
    /// Get the lane type of this SIMD vector type.
    ///
    /// A scalar type is the same as a SIMD vector type with one lane, so it returns itself.
    pub fn lane_type(self) -> Type {
        Type(self.0 & 0x0f)
    }

    /// Get the number of bits in a lane.
    pub fn lane_bits(self) -> u8 {
        match self.lane_type() {
            B1 => 1,
            B8 | I8 => 8,
            B16 | I16 => 16,
            B32 | I32 | F32 => 32,
            B64 | I64 | F64 => 64,
            _ => 0,
        }
    }

    /// Is this the VOID type?
    pub fn is_void(self) -> bool {
        self == VOID
    }

    /// Is this a scalar boolean type?
    pub fn is_bool(self) -> bool {
        match self {
            B1 | B8 | B16 | B32 | B64 => true,
            _ => false,
        }
    }

    /// Is this a scalar integer type?
    pub fn is_int(self) -> bool {
        match self {
            I8 | I16 | I32 | I64 => true,
            _ => false,
        }
    }

    /// Is this a scalar floating point type?
    pub fn is_float(self) -> bool {
        match self {
            F32 | F64 => true,
            _ => false,
        }
    }

    /// Get log2 of the number of lanes in this SIMD vector type.
    ///
    /// All SIMD types have a lane count that is a power of two and no larger than 256, so this
    /// will be a number in the range 0-8.
    ///
    /// A scalar type is the same as a SIMD vector type with one lane, so it return 0.
    pub fn log2_lane_count(self) -> u8 {
        self.0 >> 4
    }

    /// Is this a scalar type? (That is, not a SIMD vector type).
    ///
    /// A scalar type is the same as a SIMD vector type with one lane.
    pub fn is_scalar(self) -> bool {
        self.log2_lane_count() == 0
    }

    /// Get the number of lanes in this SIMD vector type.
    ///
    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1.
    pub fn lane_count(self) -> u16 {
        1 << self.log2_lane_count()
    }

    /// Get the total number of bits used to represent this type.
    pub fn bits(self) -> u16 {
        self.lane_bits() as u16 * self.lane_count()
    }

    /// Get a SIMD vector type with `n` times more lanes than this one.
    ///
    /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes.
    ///
    /// If this is already a SIMD vector type, this produces a SIMD vector type with `n *
    /// self.lane_count()` lanes.
    pub fn by(self, n: u16) -> Type {
        debug_assert!(self.lane_bits() > 0,
                      "Can't make SIMD vectors with void lanes.");
        debug_assert!(n.is_power_of_two(),
                      "Number of SIMD lanes must be a power of two");
        let log2_lanes: u32 = n.trailing_zeros();
        let new_type = self.0 as u32 + (log2_lanes << 4);
        assert!(new_type < 0x90, "No more than 256 SIMD lanes supported");
        Type(new_type as u8)
    }

    /// Get a SIMD vector with half the number of lanes.
    pub fn half_vector(self) -> Type {
        assert!(!self.is_scalar(), "Expecting a proper SIMD vector type.");
        Type(self.0 - 0x10)
    }
}

impl Display for Type {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if self.is_void() {
            write!(f, "void")
        } else if self.is_bool() {
            write!(f, "b{}", self.lane_bits())
        } else if self.is_int() {
            write!(f, "i{}", self.lane_bits())
        } else if self.is_float() {
            write!(f, "f{}", self.lane_bits())
        } else if !self.is_scalar() {
            write!(f, "{}x{}", self.lane_type(), self.lane_count())
        } else {
            panic!("Invalid Type(0x{:x})", self.0)
        }
    }
}

// ====--------------------------------------------------------------------------------------====//
//
// Function signatures
//
// ====--------------------------------------------------------------------------------------====//

/// Function argument extension options.
///
/// On some architectures, small integer function arguments are extended to the width of a
/// general-purpose register.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ArgumentExtension {
    /// No extension, high bits are indeterminate.
    None,
    /// Unsigned extension: high bits in register are 0.
    Uext,
    /// Signed extension: high bits in register replicate sign bit.
    Sext,
}

/// Function argument or return value type.
///
/// This describes the value type being passed to or from a function along with flags that affect
/// how the argument is passed.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ArgumentType {
    pub value_type: Type,
    pub extension: ArgumentExtension,
    /// Place this argument in a register if possible.
    pub inreg: bool,
}

/// Function signature.
///
/// The function signature describes the types of arguments and return values along with other
/// details that are needed to call a function correctly.
pub struct Signature {
    pub argument_types: Vec<ArgumentType>,
    pub return_types: Vec<ArgumentType>,
}

impl ArgumentType {
    pub fn new(vt: Type) -> ArgumentType {
        ArgumentType {
            value_type: vt,
            extension: ArgumentExtension::None,
            inreg: false,
        }
    }
}

impl Display for ArgumentType {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.value_type));
        match self.extension {
            ArgumentExtension::None => {}
            ArgumentExtension::Uext => try!(write!(f, " uext")),
            ArgumentExtension::Sext => try!(write!(f, " sext")),
        }
        if self.inreg {
            try!(write!(f, " inreg"));
        }
        Ok(())
    }
}

impl Signature {
    pub fn new() -> Signature {
        Signature {
            argument_types: Vec::new(),
            return_types: Vec::new(),
        }
    }
}

fn write_list(f: &mut Formatter, args: &Vec<ArgumentType>) -> fmt::Result {
    match args.split_first() {
        None => {}
        Some((first, rest)) => {
            try!(write!(f, "{}", first));
            for arg in rest {
                try!(write!(f, ", {}", arg));
            }
        }
    }
    Ok(())
}

impl Display for Signature {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "("));
        try!(write_list(f, &self.argument_types));
        try!(write!(f, ")"));
        if !self.return_types.is_empty() {
            try!(write!(f, " -> "));
            try!(write_list(f, &self.return_types));
        }
        Ok(())
    }
}

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

    #[test]
    fn basic_scalars() {
        assert_eq!(VOID, VOID.lane_type());
        assert_eq!(0, VOID.bits());
        assert_eq!(B1, B1.lane_type());
        assert_eq!(B8, B8.lane_type());
        assert_eq!(B16, B16.lane_type());
        assert_eq!(B32, B32.lane_type());
        assert_eq!(B64, B64.lane_type());
        assert_eq!(I8, I8.lane_type());
        assert_eq!(I16, I16.lane_type());
        assert_eq!(I32, I32.lane_type());
        assert_eq!(I64, I64.lane_type());
        assert_eq!(F32, F32.lane_type());
        assert_eq!(F64, F64.lane_type());

        assert_eq!(VOID.lane_bits(), 0);
        assert_eq!(B1.lane_bits(), 1);
        assert_eq!(B8.lane_bits(), 8);
        assert_eq!(B16.lane_bits(), 16);
        assert_eq!(B32.lane_bits(), 32);
        assert_eq!(B64.lane_bits(), 64);
        assert_eq!(I8.lane_bits(), 8);
        assert_eq!(I16.lane_bits(), 16);
        assert_eq!(I32.lane_bits(), 32);
        assert_eq!(I64.lane_bits(), 64);
        assert_eq!(F32.lane_bits(), 32);
        assert_eq!(F64.lane_bits(), 64);
    }

    #[test]
    fn vectors() {
        let big = F64.by(256);
        assert_eq!(big.lane_bits(), 64);
        assert_eq!(big.lane_count(), 256);
        assert_eq!(big.bits(), 64 * 256);

        assert_eq!(format!("{}", big.half_vector()), "f64x128");
        assert_eq!(format!("{}", B1.by(2).half_vector()), "b1");
    }

    #[test]
    fn format_scalars() {
        assert_eq!(format!("{}", VOID), "void");
        assert_eq!(format!("{}", B1), "b1");
        assert_eq!(format!("{}", B8), "b8");
        assert_eq!(format!("{}", B16), "b16");
        assert_eq!(format!("{}", B32), "b32");
        assert_eq!(format!("{}", B64), "b64");
        assert_eq!(format!("{}", I8), "i8");
        assert_eq!(format!("{}", I16), "i16");
        assert_eq!(format!("{}", I32), "i32");
        assert_eq!(format!("{}", I64), "i64");
        assert_eq!(format!("{}", F32), "f32");
        assert_eq!(format!("{}", F64), "f64");
    }

    #[test]
    fn format_vectors() {
        assert_eq!(format!("{}", B1.by(8)), "b1x8");
        assert_eq!(format!("{}", B8.by(1)), "b8");
        assert_eq!(format!("{}", B16.by(256)), "b16x256");
        assert_eq!(format!("{}", B32.by(4).by(2)), "b32x8");
        assert_eq!(format!("{}", B64.by(8)), "b64x8");
        assert_eq!(format!("{}", I8.by(64)), "i8x64");
        assert_eq!(format!("{}", F64.by(2)), "f64x2");
    }

    #[test]
    fn argument_type() {
        let mut t = ArgumentType::new(I32);
        assert_eq!(format!("{}", t), "i32");
        t.extension = ArgumentExtension::Uext;
        assert_eq!(format!("{}", t), "i32 uext");
        t.inreg = true;
        assert_eq!(format!("{}", t), "i32 uext inreg");
    }

    #[test]
    fn signatures() {
        let mut sig = Signature::new();
        assert_eq!(format!("{}", sig), "()");
        sig.argument_types.push(ArgumentType::new(I32));
        assert_eq!(format!("{}", sig), "(i32)");
        sig.return_types.push(ArgumentType::new(F32));
        assert_eq!(format!("{}", sig), "(i32) -> f32");
        sig.argument_types.push(ArgumentType::new(I32.by(4)));
        assert_eq!(format!("{}", sig), "(i32, i32x4) -> f32");
        sig.return_types.push(ArgumentType::new(B8));
        assert_eq!(format!("{}", sig), "(i32, i32x4) -> f32, b8");
    }
}
<commit_msg>Type::by() returns an Optional<Type>.<commit_after>
//! Common types for the Cretonne code generator.

use std::fmt::{self, Display, Formatter, Write};

// ====--------------------------------------------------------------------------------------====//
//
// Value types
//
// ====--------------------------------------------------------------------------------------====//

/// The type of an SSA value.
///
/// The `VOID` type is only used for instructions that produce no value. It can't be part of a SIMD
/// vector.
///
/// Basic integer types: `I8`, `I16`, `I32`, and `I64`. These types are sign-agnostic.
///
/// Basic floating point types: `F32` and `F64`. IEEE single and double precision.
///
/// Boolean types: `B1`, `B8`, `B16`, `B32`, and `B64`. These all encode 'true' or 'false'. The
/// larger types use redundant bits.
///
/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float/bool type.
///
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Type(u8);

/// No type. Used for functions without a return value. Can't be loaded or stored. Can't be part of
/// a SIMD vector.
pub const VOID: Type = Type(0);

/// Integer type with 8 bits.
pub const I8: Type = Type(1);

/// Integer type with 16 bits.
pub const I16: Type = Type(2);

/// Integer type with 32 bits.
pub const I32: Type = Type(3);

/// Integer type with 64 bits.
pub const I64: Type = Type(4);

/// IEEE single precision floating point type.
pub const F32: Type = Type(5);

/// IEEE double precision floating point type.
pub const F64: Type = Type(6);

/// Boolean type. Can't be loaded or stored, but can be used to form SIMD vectors.
pub const B1: Type = Type(7);

/// Boolean type using 8 bits to represent true/false.
pub const B8: Type = Type(8);

/// Boolean type using 16 bits to represent true/false.
pub const B16: Type = Type(9);

/// Boolean type using 32 bits to represent true/false.
pub const B32: Type = Type(10);

/// Boolean type using 64 bits to represent true/false.
pub const B64: Type = Type(11);

impl Type {
    /// Get the lane type of this SIMD vector type.
    ///
    /// A scalar type is the same as a SIMD vector type with one lane, so it returns itself.
    pub fn lane_type(self) -> Type {
        Type(self.0 & 0x0f)
    }

    /// Get the number of bits in a lane.
    pub fn lane_bits(self) -> u8 {
        match self.lane_type() {
            B1 => 1,
            B8 | I8 => 8,
            B16 | I16 => 16,
            B32 | I32 | F32 => 32,
            B64 | I64 | F64 => 64,
            _ => 0,
        }
    }

    /// Is this the VOID type?
    pub fn is_void(self) -> bool {
        self == VOID
    }

    /// Is this a scalar boolean type?
    pub fn is_bool(self) -> bool {
        match self {
            B1 | B8 | B16 | B32 | B64 => true,
            _ => false,
        }
    }

    /// Is this a scalar integer type?
    pub fn is_int(self) -> bool {
        match self {
            I8 | I16 | I32 | I64 => true,
            _ => false,
        }
    }

    /// Is this a scalar floating point type?
    pub fn is_float(self) -> bool {
        match self {
            F32 | F64 => true,
            _ => false,
        }
    }

    /// Get log2 of the number of lanes in this SIMD vector type.
    ///
    /// All SIMD types have a lane count that is a power of two and no larger than 256, so this
    /// will be a number in the range 0-8.
    ///
    /// A scalar type is the same as a SIMD vector type with one lane, so it return 0.
    pub fn log2_lane_count(self) -> u8 {
        self.0 >> 4
    }

    /// Is this a scalar type? (That is, not a SIMD vector type).
    ///
    /// A scalar type is the same as a SIMD vector type with one lane.
    pub fn is_scalar(self) -> bool {
        self.log2_lane_count() == 0
    }

    /// Get the number of lanes in this SIMD vector type.
    ///
    /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1.
    pub fn lane_count(self) -> u16 {
        1 << self.log2_lane_count()
    }

    /// Get the total number of bits used to represent this type.
    pub fn bits(self) -> u16 {
        self.lane_bits() as u16 * self.lane_count()
    }

    /// Get a SIMD vector type with `n` times more lanes than this one.
    ///
    /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes.
    ///
    /// If this is already a SIMD vector type, this produces a SIMD vector type with `n *
    /// self.lane_count()` lanes.
    pub fn by(self, n: u16) -> Option<Type> {
        if self.lane_bits() == 0 || !n.is_power_of_two() {
            return None;
        }
        let log2_lanes: u32 = n.trailing_zeros();
        let new_type = self.0 as u32 + (log2_lanes << 4);
        if new_type < 0x90 {
            Some(Type(new_type as u8))
        } else {
            None
        }
    }

    /// Get a SIMD vector with half the number of lanes.
    pub fn half_vector(self) -> Option<Type> {
        if self.is_scalar() {
            None
        } else {
            Some(Type(self.0 - 0x10))
        }
    }
}

impl Display for Type {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if self.is_void() {
            write!(f, "void")
        } else if self.is_bool() {
            write!(f, "b{}", self.lane_bits())
        } else if self.is_int() {
            write!(f, "i{}", self.lane_bits())
        } else if self.is_float() {
            write!(f, "f{}", self.lane_bits())
        } else if !self.is_scalar() {
            write!(f, "{}x{}", self.lane_type(), self.lane_count())
        } else {
            panic!("Invalid Type(0x{:x})", self.0)
        }
    }
}

// ====--------------------------------------------------------------------------------------====//
//
// Function signatures
//
// ====--------------------------------------------------------------------------------------====//

/// Function argument extension options.
///
/// On some architectures, small integer function arguments are extended to the width of a
/// general-purpose register.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ArgumentExtension {
    /// No extension, high bits are indeterminate.
    None,
    /// Unsigned extension: high bits in register are 0.
    Uext,
    /// Signed extension: high bits in register replicate sign bit.
    Sext,
}

/// Function argument or return value type.
///
/// This describes the value type being passed to or from a function along with flags that affect
/// how the argument is passed.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ArgumentType {
    pub value_type: Type,
    pub extension: ArgumentExtension,
    /// Place this argument in a register if possible.
    pub inreg: bool,
}

/// Function signature.
///
/// The function signature describes the types of arguments and return values along with other
/// details that are needed to call a function correctly.
pub struct Signature {
    pub argument_types: Vec<ArgumentType>,
    pub return_types: Vec<ArgumentType>,
}

impl ArgumentType {
    pub fn new(vt: Type) -> ArgumentType {
        ArgumentType {
            value_type: vt,
            extension: ArgumentExtension::None,
            inreg: false,
        }
    }
}

impl Display for ArgumentType {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.value_type));
        match self.extension {
            ArgumentExtension::None => {}
            ArgumentExtension::Uext => try!(write!(f, " uext")),
            ArgumentExtension::Sext => try!(write!(f, " sext")),
        }
        if self.inreg {
            try!(write!(f, " inreg"));
        }
        Ok(())
    }
}

impl Signature {
    pub fn new() -> Signature {
        Signature {
            argument_types: Vec::new(),
            return_types: Vec::new(),
        }
    }
}

fn write_list(f: &mut Formatter, args: &Vec<ArgumentType>) -> fmt::Result {
    match args.split_first() {
        None => {}
        Some((first, rest)) => {
            try!(write!(f, "{}", first));
            for arg in rest {
                try!(write!(f, ", {}", arg));
            }
        }
    }
    Ok(())
}

impl Display for Signature {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "("));
        try!(write_list(f, &self.argument_types));
        try!(write!(f, ")"));
        if !self.return_types.is_empty() {
            try!(write!(f, " -> "));
            try!(write_list(f, &self.return_types));
        }
        Ok(())
    }
}

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

    #[test]
    fn basic_scalars() {
        assert_eq!(VOID, VOID.lane_type());
        assert_eq!(0, VOID.bits());
        assert_eq!(B1, B1.lane_type());
        assert_eq!(B8, B8.lane_type());
        assert_eq!(B16, B16.lane_type());
        assert_eq!(B32, B32.lane_type());
        assert_eq!(B64, B64.lane_type());
        assert_eq!(I8, I8.lane_type());
        assert_eq!(I16, I16.lane_type());
        assert_eq!(I32, I32.lane_type());
        assert_eq!(I64, I64.lane_type());
        assert_eq!(F32, F32.lane_type());
        assert_eq!(F64, F64.lane_type());

        assert_eq!(VOID.lane_bits(), 0);
        assert_eq!(B1.lane_bits(), 1);
        assert_eq!(B8.lane_bits(), 8);
        assert_eq!(B16.lane_bits(), 16);
        assert_eq!(B32.lane_bits(), 32);
        assert_eq!(B64.lane_bits(), 64);
        assert_eq!(I8.lane_bits(), 8);
        assert_eq!(I16.lane_bits(), 16);
        assert_eq!(I32.lane_bits(), 32);
        assert_eq!(I64.lane_bits(), 64);
        assert_eq!(F32.lane_bits(), 32);
        assert_eq!(F64.lane_bits(), 64);
    }

    #[test]
    fn vectors() {
        let big = F64.by(256).unwrap();
        assert_eq!(big.lane_bits(), 64);
        assert_eq!(big.lane_count(), 256);
        assert_eq!(big.bits(), 64 * 256);

        assert_eq!(format!("{}", big.half_vector().unwrap()), "f64x128");
        assert_eq!(format!("{}", B1.by(2).unwrap().half_vector().unwrap()),
                   "b1");
        assert_eq!(I32.half_vector(), None);
        assert_eq!(VOID.half_vector(), None);
    }

    #[test]
    fn format_scalars() {
        assert_eq!(format!("{}", VOID), "void");
        assert_eq!(format!("{}", B1), "b1");
        assert_eq!(format!("{}", B8), "b8");
        assert_eq!(format!("{}", B16), "b16");
        assert_eq!(format!("{}", B32), "b32");
        assert_eq!(format!("{}", B64), "b64");
        assert_eq!(format!("{}", I8), "i8");
        assert_eq!(format!("{}", I16), "i16");
        assert_eq!(format!("{}", I32), "i32");
        assert_eq!(format!("{}", I64), "i64");
        assert_eq!(format!("{}", F32), "f32");
        assert_eq!(format!("{}", F64), "f64");
    }

    #[test]
    fn format_vectors() {
        assert_eq!(format!("{}", B1.by(8).unwrap()), "b1x8");
        assert_eq!(format!("{}", B8.by(1).unwrap()), "b8");
        assert_eq!(format!("{}", B16.by(256).unwrap()), "b16x256");
        assert_eq!(format!("{}", B32.by(4).unwrap().by(2).unwrap()), "b32x8");
        assert_eq!(format!("{}", B64.by(8).unwrap()), "b64x8");
        assert_eq!(format!("{}", I8.by(64).unwrap()), "i8x64");
        assert_eq!(format!("{}", F64.by(2).unwrap()), "f64x2");
        assert_eq!(I8.by(3), None);
        assert_eq!(I8.by(512), None);
        assert_eq!(VOID.by(4), None);
    }

    #[test]
    fn argument_type() {
        let mut t = ArgumentType::new(I32);
        assert_eq!(format!("{}", t), "i32");
        t.extension = ArgumentExtension::Uext;
        assert_eq!(format!("{}", t), "i32 uext");
        t.inreg = true;
        assert_eq!(format!("{}", t), "i32 uext inreg");
    }

    #[test]
    fn signatures() {
        let mut sig = Signature::new();
        assert_eq!(format!("{}", sig), "()");
        sig.argument_types.push(ArgumentType::new(I32));
        assert_eq!(format!("{}", sig), "(i32)");
        sig.return_types.push(ArgumentType::new(F32));
        assert_eq!(format!("{}", sig), "(i32) -> f32");
        sig.argument_types.push(ArgumentType::new(I32.by(4).unwrap()));
        assert_eq!(format!("{}", sig), "(i32, i32x4) -> f32");
        sig.return_types.push(ArgumentType::new(B8));
        assert_eq!(format!("{}", sig), "(i32, i32x4) -> f32, b8");
    }
}
<|endoftext|>