<commit_before>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use std::collections::HashMap;

use quote::Tokens;
use syn::Ident;

use parser::{GtkWidget, RelmWidget, Widget};
use parser::EventValue::{CurrentWidget, ForeignWidget};
use parser::EventValueReturn::{Return, WithoutReturn};
use parser::Widget::{Gtk, Relm};
use super::COMPONENTS;

pub fn gen(name: &Ident, widget: Widget, root_widget: &mut Option<Ident>, root_widget_type: &mut Option<Ident>, idents: Vec<&Ident>) -> (Tokens, HashMap<Ident, Ident>) {
    let mut widget_names = vec![];
    let mut relm_widgets = HashMap::new();
    let mut events = vec![];
    let widget = gen_widget(&widget, None, &mut widget_names, root_widget, root_widget_type, &mut relm_widgets, &mut events);
    let widget_names1: Vec<_> = widget_names.iter()
        .filter(|ident| idents.contains(ident) || relm_widgets.contains_key(ident))
        .collect();
    let widget_names1 = &widget_names1;
    let widget_names2 = widget_names1;
    let root_widget_name = &root_widget.as_ref().unwrap();
    let code = quote! {
        #widget

        #(#events)*

        #name {
            #root_widget_name: #root_widget_name,
            #(#widget_names1: #widget_names2),*
        }
    };
    (code, relm_widgets)
}

fn gen_widget(widget: &Widget, parent: Option<&Ident>, widget_names: &mut Vec<Ident>, root_widget: &mut Option<Ident>, root_widget_type: &mut Option<Ident>, relm_widgets: &mut HashMap<Ident, Ident>, events: &mut Vec<Tokens>) -> Tokens {
    match *widget {
        Gtk(ref gtk_widget) => gen_gtk_widget(gtk_widget, parent, widget_names, root_widget, root_widget_type, relm_widgets, events),
        Relm(ref relm_widget) => gen_relm_widget(relm_widget, parent, widget_names, relm_widgets, events, root_widget, root_widget_type),
    }
}

// TODO: refactor to use a struct which will contain the state.
fn gen_gtk_widget(widget: &GtkWidget, parent: Option<&Ident>, widget_names: &mut Vec<Ident>, root_widget: &mut Option<Ident>, root_widget_type: &mut Option<Ident>, relm_widgets: &mut HashMap<Ident, Ident>, events: &mut Vec<Tokens>) -> Tokens {
    let struct_name = &widget.gtk_type;
    let widget_name = &widget.name;
    widget_names.push(widget_name.clone());

    if widget.save {
        relm_widgets.insert(widget_name.clone(), struct_name.clone());
    }

    let mut params = Tokens::new();
    for param in &widget.init_parameters {
        params.append(param);
        params.append(",");
    }

    let construct_widget =
        if widget.init_parameters.is_empty() {
            quote! {
                unsafe {
                    use gtk::StaticType;
                    use relm::{Downcast, FromGlibPtrNone, ToGlib};
                    ::gtk::Widget::from_glib_none(::relm::g_object_new(#struct_name::static_type().to_glib(),
                    #params ::std::ptr::null() as *const i8) as *mut _)
                    .downcast_unchecked()
                }
            }
        }
        else {
            quote! {
                #struct_name::new(#params)
            }
        };

    for (name, event) in &widget.events {
        let event_ident = Ident::new(format!("connect_{}", name));
        let event_params: Vec<_> = event.params.iter().map(|ident| Ident::new(ident.as_ref())).collect();
        let connect =
            match event.value {
                CurrentWidget(WithoutReturn(ref event_value)) => quote! {
                    connect!(relm, #widget_name, #event_ident(#(#event_params),*), #event_value);
                },
                ForeignWidget(ref foreign_widget_name, WithoutReturn(ref event_value)) => quote! {
                    connect!(#widget_name, #event_ident(#(#event_params),*), #foreign_widget_name, #event_value);
                },
                CurrentWidget(Return(ref event_value, ref return_value)) => quote! {
                    connect!(relm, #widget_name, #event_ident(#(#event_params),*) (#event_value, #return_value));
                },
                ForeignWidget(_, Return(_, _)) => unreachable!(),
            };
        events.push(connect);
    }

    let children: Vec<_> = widget.children.iter()
        .map(|child| gen_widget(child, Some(widget_name), widget_names, root_widget, root_widget_type, relm_widgets, events)).collect();

    let add_child_or_show_all =
        if let Some(name) = parent {
            quote! {
                ::gtk::ContainerExt::add(&#name, &#widget_name);
            }
        }
        else {
            *root_widget_type = Some(struct_name.clone());
            *root_widget = Some(widget_name.clone());
            quote! {
                #widget_name.show_all();
            }
        };

    let mut properties = vec![];
    for (key, value) in &widget.properties {
        let property_func = Ident::new(format!("set_{}", key));
        properties.push(quote! {
            #widget_name.#property_func(#value);
        });
    }

    let mut child_properties = vec![];
    for (key, value) in &widget.child_properties {
        let property_func = Ident::new(format!("set_child_{}", key));
        let parent = parent.expect("child properties only allowed for non-root widgets");
        child_properties.push(quote! {
            #parent.#property_func(&#widget_name, #value);
        });
    }

    quote! {
        let #widget_name: #struct_name = #construct_widget;
        #(#properties)*
        #(#children)*
        #add_child_or_show_all
        #(#child_properties)*
    }
}

fn gen_relm_widget(widget: &RelmWidget, parent: Option<&Ident>, widget_names: &mut Vec<Ident>, relm_widgets: &mut HashMap<Ident, Ident>, events: &mut Vec<Tokens>, root_widget: &mut Option<Ident>, root_widget_type: &mut Option<Ident>) -> Tokens {
    widget_names.push(widget.name.clone());
    let widget_name = &widget.name;
    let widget_type = Ident::new(widget.relm_type.as_ref());
    let relm_component_type = gen_relm_component_type(&widget.relm_type);
    relm_widgets.insert(widget.name.clone(), relm_component_type);
    let parent = parent.unwrap();

    for (name, widget_events) in &widget.events {
        let event_ident = Ident::new(name.as_ref());
        for event in widget_events {
            let params =
                if event.params.is_empty() {
                    quote! {}
                }
                else {
                    let event_params: Vec<_> = event.params.iter().map(|ident| Ident::new(ident.as_ref())).collect();
                    quote! {
                        (#(#event_params),*)
                    }
                };
            let connect =
                match event.value {
                    CurrentWidget(WithoutReturn(ref event_value)) => quote! {
                        connect!(#widget_name@#event_ident #params, relm, #event_value);
                    },
                    ForeignWidget(ref foreign_widget_name, WithoutReturn(ref event_value)) => quote! {
                        connect!(#widget_name@#event_ident #params, #foreign_widget_name, #event_value);
                    },
                    CurrentWidget(Return(_, _)) | ForeignWidget(_, Return(_, _)) => unreachable!(),
                };
            events.push(connect);
        }
    }

    let children: Vec<_> = widget.children.iter()
        .map(|child| gen_widget(child, Some(widget_name), widget_names, root_widget, root_widget_type, relm_widgets, events)).collect();

    quote! {
        let #widget_name = {
            ::relm::ContainerWidget::add_widget::<#widget_type, _, _>(&#parent, &relm)
        };
        #(#children)*
    }
}

fn gen_relm_component_type(name: &Ident) -> Ident {
    let components = COMPONENTS.lock().unwrap();
    let model_type = &components.get(name)
        .expect(&format!("Cannot find relm Widget {}", name))
        .model_type;
    let msg_type = &components[name].msg_type;
    let view_type = &components[name].view_type;

    let mut model = Tokens::new();
    model.append_all(&[model_type]);

    let mut msg = Tokens::new();
    msg.append_all(&[msg_type]);

    let mut view = Tokens::new();
    view.append(view_type);

    Ident::new(format!("::relm::Component<{}, {}, {}>", model, msg, view).as_ref())
}
<commit_msg>Refactor the code generator<commit_after>/*
 * Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use std::collections::HashMap;

use quote::Tokens;
use syn::Ident;

use parser::{GtkWidget, RelmWidget, Widget};
use parser::EventValue::{CurrentWidget, ForeignWidget};
use parser::EventValueReturn::{Return, WithoutReturn};
use parser::Widget::{Gtk, Relm};
use super::COMPONENTS;

pub fn gen(name: &Ident, widget: Widget, root_widget: &mut Option<Ident>, root_widget_type: &mut Option<Ident>, idents: Vec<&Ident>) -> (Tokens, HashMap<Ident, Ident>) {
    let mut generator = Generator::new(root_widget, root_widget_type);
    let widget = generator.widget(&widget, None);
    let widget_names1: Vec<_> = generator.widget_names.iter()
        .filter(|ident| idents.contains(ident) || generator.relm_widgets.contains_key(ident))
        .collect();
    let widget_names1 = &widget_names1;
    let widget_names2 = widget_names1;
    let root_widget_name = &generator.root_widget.as_ref().unwrap();
    let events = &generator.events;
    let code = quote! {
        #widget

        #(#events)*

        #name {
            #root_widget_name: #root_widget_name,
            #(#widget_names1: #widget_names2),*
        }
    };
    (code, generator.relm_widgets)
}

struct Generator<'a> {
    events: Vec<Tokens>,
    relm_widgets: HashMap<Ident, Ident>,
    root_widget: &'a mut Option<Ident>,
    root_widget_type: &'a mut Option<Ident>,
    widget_names: Vec<Ident>,
}

impl<'a> Generator<'a> {
    fn new(root_widget: &'a mut Option<Ident>, root_widget_type: &'a mut Option<Ident>) -> Self {
        Generator {
            events: vec![],
            relm_widgets: HashMap::new(),
            root_widget: root_widget,
            root_widget_type: root_widget_type,
            widget_names: vec![],
        }
    }

    fn add_child_or_show_all(&mut self, widget: &GtkWidget, parent: Option<&Ident>) -> Tokens {
        let widget_name = &widget.name;
        if let Some(name) = parent {
            quote! {
                ::gtk::ContainerExt::add(&#name, &#widget_name);
            }
        }
        else {
            let struct_name = &widget.gtk_type;
            *self.root_widget_type = Some(struct_name.clone());
            *self.root_widget = Some(widget_name.clone());
            quote! {
                #widget_name.show_all();
            }
        }
    }

    fn collect_events(&mut self, widget: &GtkWidget) {
        let widget_name = &widget.name;
        for (name, event) in &widget.events {
            let event_ident = Ident::new(format!("connect_{}", name));
            let event_params: Vec<_> = event.params.iter().map(|ident| Ident::new(ident.as_ref())).collect();
            let connect =
                match event.value {
                    CurrentWidget(WithoutReturn(ref event_value)) => quote! {
                        connect!(relm, #widget_name, #event_ident(#(#event_params),*), #event_value);
                    },
                    ForeignWidget(ref foreign_widget_name, WithoutReturn(ref event_value)) => quote! {
                        connect!(#widget_name, #event_ident(#(#event_params),*), #foreign_widget_name, #event_value);
                    },
                    CurrentWidget(Return(ref event_value, ref return_value)) => quote! {
                        connect!(relm, #widget_name, #event_ident(#(#event_params),*) (#event_value, #return_value));
                    },
                    ForeignWidget(_, Return(_, _)) => unreachable!(),
                };
            self.events.push(connect);
        }
    }

    fn collect_relm_events(&mut self, widget: &RelmWidget) {
        let widget_name = &widget.name;
        for (name, widget_events) in &widget.events {
            let event_ident = Ident::new(name.as_ref());
            for event in widget_events {
                let params =
                    if event.params.is_empty() {
                        quote! {}
                    }
                    else {
                        let event_params: Vec<_> = event.params.iter().map(|ident| Ident::new(ident.as_ref())).collect();
                        quote! {
                            (#(#event_params),*)
                        }
                    };
                let connect =
                    match event.value {
                        CurrentWidget(WithoutReturn(ref event_value)) => quote! {
                            connect!(#widget_name@#event_ident #params, relm, #event_value);
                        },
                        ForeignWidget(ref foreign_widget_name, WithoutReturn(ref event_value)) => quote! {
                            connect!(#widget_name@#event_ident #params, #foreign_widget_name, #event_value);
                        },
                        CurrentWidget(Return(_, _)) | ForeignWidget(_, Return(_, _)) => unreachable!(),
                    };
                self.events.push(connect);
            }
        }
    }

    fn gtk_widget(&mut self, widget: &GtkWidget, parent: Option<&Ident>) -> Tokens {
        let struct_name = &widget.gtk_type;
        let widget_name = &widget.name;
        self.widget_names.push(widget_name.clone());

        if widget.save {
            self.relm_widgets.insert(widget_name.clone(), struct_name.clone());
        }

        let construct_widget = gen_construct_widget(&widget);
        self.collect_events(&widget);

        let children: Vec<_> = widget.children.iter()
            .map(|child| self.widget(child, Some(widget_name))).collect();

        let add_child_or_show_all = self.add_child_or_show_all(&widget, parent);
        let properties = gen_set_prop_calls(&widget);
        let child_properties = gen_set_child_prop_calls(&widget, parent);

        quote! {
            let #widget_name: #struct_name = #construct_widget;
            #(#properties)*
            #(#children)*
            #add_child_or_show_all
            #(#child_properties)*
        }
    }

    fn relm_widget(&mut self, widget: &RelmWidget, parent: Option<&Ident>) -> Tokens {
        self.widget_names.push(widget.name.clone());
        let widget_name = &widget.name;
        let widget_type = Ident::new(widget.relm_type.as_ref());
        let relm_component_type = gen_relm_component_type(&widget.relm_type);
        self.relm_widgets.insert(widget.name.clone(), relm_component_type);
        let parent = parent.unwrap();

        self.collect_relm_events(widget);

        let children: Vec<_> = widget.children.iter()
            .map(|child| self.widget(child, Some(widget_name))).collect();

        quote! {
            let #widget_name = {
                ::relm::ContainerWidget::add_widget::<#widget_type, _, _>(&#parent, &relm)
            };
            #(#children)*
        }
    }

    fn widget(&mut self, widget: &Widget, parent: Option<&Ident>) -> Tokens {
        match *widget {
            Gtk(ref gtk_widget) => self.gtk_widget(gtk_widget, parent),
            Relm(ref relm_widget) => self.relm_widget(relm_widget, parent),
        }
    }
}

fn gen_construct_widget(widget: &GtkWidget) -> Tokens {
    let struct_name = &widget.gtk_type;

    let mut params = Tokens::new();
    for param in &widget.init_parameters {
        params.append(param);
        params.append(",");
    }

    if widget.init_parameters.is_empty() {
        quote! {
            unsafe {
                use gtk::StaticType;
                use relm::{Downcast, FromGlibPtrNone, ToGlib};
                ::gtk::Widget::from_glib_none(::relm::g_object_new(#struct_name::static_type().to_glib(),
                #params ::std::ptr::null() as *const i8) as *mut _)
                .downcast_unchecked()
            }
        }
    }
    else {
        quote! {
            #struct_name::new(#params)
        }
    }
}

fn gen_relm_component_type(name: &Ident) -> Ident {
    let components = COMPONENTS.lock().unwrap();
    let model_type = &components.get(name)
        .expect(&format!("Cannot find relm Widget {}", name))
        .model_type;
    let msg_type = &components[name].msg_type;
    let view_type = &components[name].view_type;

    let mut model = Tokens::new();
    model.append_all(&[model_type]);

    let mut msg = Tokens::new();
    msg.append_all(&[msg_type]);

    let mut view = Tokens::new();
    view.append(view_type);

    Ident::new(format!("::relm::Component<{}, {}, {}>", model, msg, view).as_ref())
}

fn gen_set_child_prop_calls(widget: &GtkWidget, parent: Option<&Ident>) -> Vec<Tokens> {
    let widget_name = &widget.name;
    let mut child_properties = vec![];
    for (key, value) in &widget.child_properties {
        let property_func = Ident::new(format!("set_child_{}", key));
        let parent = parent.expect("child properties only allowed for non-root widgets");
        child_properties.push(quote! {
            #parent.#property_func(&#widget_name, #value);
        });
    }
    child_properties
}

fn gen_set_prop_calls(widget: &GtkWidget) -> Vec<Tokens> {
    let widget_name = &widget.name;
    let mut properties = vec![];
    for (key, value) in &widget.properties {
        let property_func = Ident::new(format!("set_{}", key));
        properties.push(quote! {
            #widget_name.#property_func(#value);
        });
    }
    properties
}
<|endoftext|>


<commit_before><commit_msg>flush stream to be sure that everything is sent<commit_after><|endoftext|>


<commit_before>use std::u32::MAX as UMAX;
use rand::Rng;
use super::ShuffledIter as SI;

/// This trait may be used to obtain an instance of `ShuffledIter`. It should
/// always be implemented generically for all types implementing `rand::Rng`,
/// that is for all random number generators (which is the case for this library).
///
/// As such, an instance of `ShuffledIter` may be obtained by calling `iter_shuffled`
/// with a suitable argument on any random number generator, given that `ShuffledIterGen`
/// is in scope.
///
/// An implementation of this trait is provided by this library for the following
/// agument types:
///
/// * all ranges of integer types (ie. `0i8..`, `..10u16`, `10..20`)
/// * slices of any kind
pub trait ShuffledIterGen<T>: Rng {
    type Iter: Iterator;

    fn iter_shuffled(&mut self, T) -> Self::Iter;
}

#[derive(Copy, Clone)]
struct Slice<'a, T: 'a> {
    iter: SI,
    slice: &'a [T],
}

impl<'a, T: 'a, R: Rng> ShuffledIterGen<&'a [T]> for R {
    type Iter = Slice<'a, T>;

    fn iter_shuffled(&mut self, slice: &'a [T]) -> Slice<'a, T> {
        let len = slice.len();

        if len == 0 { panic!("slice must not be empty") }
        if len > UMAX as usize + 1 { panic!("slice may contain at most u32::MAX + 1 elements") }

        Slice {
            iter: SI::new((len - 1) as u32, self),
            slice: slice,
        }
    }
}

impl<'a, T> Iterator for Slice<'a, T> {
    type Item = &'a T;

    #[inline]
    fn next(&mut self) -> Option<&'a T> {
        self.iter.next().map(|i| &self.slice[i as usize])
    }
}

macro_rules! impl_range {($prim:ident) => {
    mod $prim {
        #[derive(Copy, Clone)]
        pub struct Iter {
            iter: ::ShuffledIter,
            offset: $prim,
        }

        pub fn new<R: ::rand::Rng>(rng: &mut R, min: $prim, max: $prim) -> Iter {
            if min > max { panic!("min > max") }

            if (max - min) as u64 > ::std::u32::MAX as u64 { panic!("range must contain at most u32::MAX + 1 elements") }

            Iter {
                iter: ::ShuffledIter::new((max - min) as u32, rng),
                offset: min,
            }
        }

        impl Iterator for Iter {
            type Item = $prim;

            #[inline]
            fn next(&mut self) -> Option<$prim> {
                self.iter.next().map(|u| u as $prim + self.offset)
            }
        }
    }

    impl<R: Rng> ShuffledIterGen<::std::ops::Range<$prim>> for R {
        type Iter = $prim::Iter;

        fn iter_shuffled(&mut self, range: ::std::ops::Range<$prim>) -> $prim::Iter {
            if range.end <= range.start { panic!("range must contain at least one element") }
            $prim::new(self, range.start, range.end - 1)
        }
    }

    impl<R: Rng> ShuffledIterGen<::std::ops::RangeFrom<$prim>> for R {
        type Iter = $prim::Iter;

        fn iter_shuffled(&mut self, range: ::std::ops::RangeFrom<$prim>) -> $prim::Iter {
            $prim::new(self, range.start, ::std::$prim::MAX)
        }
    }

    impl<R: Rng> ShuffledIterGen<::std::ops::RangeTo<$prim>> for R {
        type Iter = $prim::Iter;

        fn iter_shuffled(&mut self, range: ::std::ops::RangeTo<$prim>) -> $prim::Iter {
            if range.end == ::std::$prim::MIN { panic!("range must contain at least one element") }
            $prim::new(self, ::std::$prim::MIN, range.end - 1)
        }
    }
}}

macro_rules! impl_ranges {($($prim:ident),+) => {$(
    impl_range!($prim);
)*}}

impl_ranges!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);

#[cfg(test)]
#[path = "iter_tests.rs"]
mod iter_tests;
<commit_msg>Fix a private-in-public error<commit_after>use std::u32::MAX as UMAX;
use rand::Rng;
use super::ShuffledIter as SI;

/// This trait may be used to obtain an instance of `ShuffledIter`. It should
/// always be implemented generically for all types implementing `rand::Rng`,
/// that is for all random number generators (which is the case for this library).
///
/// As such, an instance of `ShuffledIter` may be obtained by calling `iter_shuffled`
/// with a suitable argument on any random number generator, given that `ShuffledIterGen`
/// is in scope.
///
/// An implementation of this trait is provided by this library for the following
/// agument types:
///
/// * all ranges of integer types (ie. `0i8..`, `..10u16`, `10..20`)
/// * slices of any kind
pub trait ShuffledIterGen<T>: Rng {
    type Iter: Iterator;

    fn iter_shuffled(&mut self, T) -> Self::Iter;
}

#[derive(Copy, Clone)]
pub struct Slice<'a, T: 'a> {
    iter: SI,
    slice: &'a [T],
}

impl<'a, T: 'a, R: Rng> ShuffledIterGen<&'a [T]> for R {
    type Iter = Slice<'a, T>;

    fn iter_shuffled(&mut self, slice: &'a [T]) -> Slice<'a, T> {
        let len = slice.len();

        if len == 0 { panic!("slice must not be empty") }
        if len > UMAX as usize + 1 { panic!("slice may contain at most u32::MAX + 1 elements") }

        Slice {
            iter: SI::new((len - 1) as u32, self),
            slice: slice,
        }
    }
}

impl<'a, T> Iterator for Slice<'a, T> {
    type Item = &'a T;

    #[inline]
    fn next(&mut self) -> Option<&'a T> {
        self.iter.next().map(|i| &self.slice[i as usize])
    }
}

macro_rules! impl_range {($prim:ident) => {
    mod $prim {
        #[derive(Copy, Clone)]
        pub struct Iter {
            iter: ::ShuffledIter,
            offset: $prim,
        }

        pub fn new<R: ::rand::Rng>(rng: &mut R, min: $prim, max: $prim) -> Iter {
            if min > max { panic!("min > max") }

            if (max - min) as u64 > ::std::u32::MAX as u64 { panic!("range must contain at most u32::MAX + 1 elements") }

            Iter {
                iter: ::ShuffledIter::new((max - min) as u32, rng),
                offset: min,
            }
        }

        impl Iterator for Iter {
            type Item = $prim;

            #[inline]
            fn next(&mut self) -> Option<$prim> {
                self.iter.next().map(|u| u as $prim + self.offset)
            }
        }
    }

    impl<R: Rng> ShuffledIterGen<::std::ops::Range<$prim>> for R {
        type Iter = $prim::Iter;

        fn iter_shuffled(&mut self, range: ::std::ops::Range<$prim>) -> $prim::Iter {
            if range.end <= range.start { panic!("range must contain at least one element") }
            $prim::new(self, range.start, range.end - 1)
        }
    }

    impl<R: Rng> ShuffledIterGen<::std::ops::RangeFrom<$prim>> for R {
        type Iter = $prim::Iter;

        fn iter_shuffled(&mut self, range: ::std::ops::RangeFrom<$prim>) -> $prim::Iter {
            $prim::new(self, range.start, ::std::$prim::MAX)
        }
    }

    impl<R: Rng> ShuffledIterGen<::std::ops::RangeTo<$prim>> for R {
        type Iter = $prim::Iter;

        fn iter_shuffled(&mut self, range: ::std::ops::RangeTo<$prim>) -> $prim::Iter {
            if range.end == ::std::$prim::MIN { panic!("range must contain at least one element") }
            $prim::new(self, ::std::$prim::MIN, range.end - 1)
        }
    }
}}

macro_rules! impl_ranges {($($prim:ident),+) => {$(
    impl_range!($prim);
)*}}

impl_ranges!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);

#[cfg(test)]
#[path = "iter_tests.rs"]
mod iter_tests;
<|endoftext|>


<commit_before>use std::env;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::PathBuf;
use serde::de::Deserialize;
use serde_protobuf::descriptor::{Descriptors, MessageDescriptor};
use serde_protobuf::de::Deserializer;
use serde_value::Value;
use protobuf::{CodedInputStream, parse_from_reader};
use protobuf::descriptor::{FileDescriptorSet, FileDescriptorProto};

pub fn process_single(read: &mut Read) {
    let mut descriptors = Descriptors::new();
    let mut message_descriptors = Vec::new();

    for fdset_path in discover_fdsets() {
        let mut fdset_file = File::open(fdset_path.as_path()).unwrap();
        let fdset: FileDescriptorSet = parse_from_reader(&mut fdset_file).unwrap();
        descriptors.add_file_set_proto(&fdset);
        let fdset_protos: &[FileDescriptorProto] = fdset.get_file();
        for file_proto in fdset_protos.iter() {
            for message_proto in file_proto.get_message_type().iter() {
                println!("{:?}", message_proto);
                message_descriptors.push(MessageDescriptor::from_proto(&fdset_path.to_string_lossy().into_owned().as_str(), message_proto));
            }
        }
    }

    descriptors.resolve_refs();

    let byte_is = CodedInputStream::new(read);

    for md in message_descriptors {
        println!("ATTEMPT TO DESERIALIE WITH: {:?}\n\n", md);
        let mut deserializer = Deserializer::new(&descriptors, &md, byte_is);
        let value = Value::deserialize(&mut deserializer).unwrap();
        println!("{:?}", value);
    }
}

pub fn process_stream(read: &mut Read) {
    let mut stream = CodedInputStream::new(read);

    loop {
        match stream.eof() {
            Err(e) => panic!(e),
            Ok(true) => break,
            Ok(false) => break,
            //todo: actually do deserialization here
        }
    }
}

fn discover_fdsets() -> Vec<PathBuf> {
    let mut fdset_files = Vec::new();

    let mut home = env::home_dir().expect("Could not find $HOME");
    home.push(".pq");
    let paths = read_dir(home.as_path()).unwrap();

    for p in paths {
        let path = match p {
            Ok(p) => p.path(),
            Err(_) => continue,
        };
        match path.extension() {
            Some(x) => {
                if x != "fdset" {
                    continue;
                }
            },
            None => continue,
        }
        fdset_files.push(path);
    }
    fdset_files
}
<commit_msg>Read consumes message - somehow retain<commit_after>use std::env;
use std::fs::{File, read_dir};
use std::io::Read;
use std::path::PathBuf;
use serde::de::Deserialize;
use serde_protobuf::descriptor::{Descriptors, MessageDescriptor};
use serde_protobuf::de::Deserializer;
use serde_value::Value;
use protobuf::{CodedInputStream, parse_from_reader};
use protobuf::descriptor::{FileDescriptorSet, FileDescriptorProto};

pub fn process_single(read: &mut Read) {
    let mut descriptors = Descriptors::new();
    let mut message_descriptors = Vec::new();

    for fdset_path in discover_fdsets() {
        let mut fdset_file = File::open(fdset_path.as_path()).unwrap();
        let fdset: FileDescriptorSet = parse_from_reader(&mut fdset_file).unwrap();
        descriptors.add_file_set_proto(&fdset);
        let fdset_protos: &[FileDescriptorProto] = fdset.get_file();
        for file_proto in fdset_protos.iter() {
            for message_proto in file_proto.get_message_type().iter() {
                println!("{:?}", message_proto);
                message_descriptors.push(MessageDescriptor::from_proto(&fdset_path.to_string_lossy().into_owned().as_str(), message_proto));
            }
        }
    }

    descriptors.resolve_refs();

    for md in message_descriptors {
        let stream = CodedInputStream::new(read);
        println!("ATTEMPT TO DESERIALIE WITH\n:\t{:?}\n\n", md);
        let mut deserializer = Deserializer::new(&descriptors, &md, stream);
        let value = Value::deserialize(&mut deserializer).unwrap();
        println!("DESERIALIZED\n:\t{:?}\n\n", value);
    }
}

pub fn process_stream(read: &mut Read) {
    let mut stream = CodedInputStream::new(read);

    loop {
        match stream.eof() {
            Err(e) => panic!(e),
            Ok(true) => break,
            Ok(false) => break,
            //todo: actually do deserialization here
        }
    }
}

fn discover_fdsets() -> Vec<PathBuf> {
    let mut fdset_files = Vec::new();

    let mut home = env::home_dir().expect("Could not find $HOME");
    home.push(".pq");
    let paths = read_dir(home.as_path()).unwrap();

    for p in paths {
        let path = match p {
            Ok(p) => p.path(),
            Err(_) => continue,
        };
        match path.extension() {
            Some(x) => {
                if x != "fdset" {
                    continue;
                }
            },
            None => continue,
        }
        fdset_files.push(path);
    }
    fdset_files
}
<|endoftext|>


<commit_before>extern crate term ;
extern crate event ;
extern crate system ;

use term::Offset2 ;
use term::smt::* ;

use event::Event ;

use system::{ CallSet, Callable, Sys, Prop } ;
use system::smt::Unroller ;

macro_rules! try_error {
  ($e:expr, $event:expr) => (
    match $e {
      Ok(()) => (),
      Err(e) => $event.log( & format!("error: {:?}", e) ),
    }
  )
}

pub fn run(
  sys: Sys, mut props: Vec<Prop>, event: Event
) {
  use std::str::from_utf8 ;
  use term::{ Operator, OpMaker, VarMaker, PrintSmt2 } ;
  event.log(
    & format!("checking {} propertie(s) on system {}", props.len(), sys.sym())
  ) ;

  event.log("creating solver") ;

  let conf = SolverConf::z3().print_success() ;
  let factory = event.factory().clone() ;

  let mut k = Offset2::init() ;

  match Solver::mk(z3_cmd(), conf, factory.clone()) {
    Err(e) => event.log( & format!("error:\n  {:?}", e) ),
    Ok(mut solver) => {

      event.log("declaring functions") ;
      try_error!(
        sys.defclare_funs(& mut solver), event
      ) ;

      event.log("declaring state@0") ;
      try_error!(
        sys.declare_svars(& mut solver, & factory, k.curr()), event
      ) ;

      event.log( "asserting init@0" ) ;
      try_error!(
        solver.assert( & (sys.init_term(), & k) ), event
      ) ;

      let mut cpt = 0 ;

      loop {

        let actlit = factory.var( format!("fresh_{}", cpt) ) ;
        let mut neg_props = Vec::with_capacity(props.len()) ;
        for prop in props.iter() {
          neg_props.push(
            factory.op(
              Operator::Not, vec![prop.body().clone()]
            )
          )
        }
        let prop_term = factory.op(
          Operator::Or, neg_props
        ) ;
        event.log(
          & format!("defining actlit {}\nto be {}", actlit, prop_term)
        ) ;
        break

      }
    },
  }
}<commit_msg>bmc checks if the properties are falsifiable in init<commit_after>extern crate term ;
extern crate event ;
extern crate system ;

use term::Offset2 ;
use term::smt::* ;
use term::smt::sync::* ;

use event::Event ;

use system::{ CallSet, Callable, Sys, Prop } ;
use system::smt::Unroller ;

macro_rules! try_error {
  ($e:expr, $event:expr) => (
    match $e {
      Ok(()) => (),
      Err(e) => $event.log( & format!("error: {:?}", e) ),
    }
  )
}

pub fn run(
  sys: Sys, mut props: Vec<Prop>, event: Event
) {
  use std::str::from_utf8 ;
  use term::{ Operator, SymMaker, OpMaker, VarMaker, PrintSmt2, Type } ;
  event.log(
    & format!("checking {} propertie(s) on system {}", props.len(), sys.sym())
  ) ;

  event.log("creating solver") ;

  let conf = SolverConf::z3().print_success() ;
  let factory = event.factory().clone() ;

  let mut k = Offset2::init() ;

  match Solver::mk(z3_cmd(), conf, factory.clone()) {
    Err(e) => event.log( & format!("error:\n  {:?}", e) ),
    Ok(mut solver) => {

      event.log("declaring functions") ;
      try_error!(
        sys.defclare_funs(& mut solver), event
      ) ;

      event.log("declaring state@0") ;
      try_error!(
        sys.declare_svars(& mut solver, & factory, k.curr()), event
      ) ;

      event.log( "asserting init@0" ) ;
      try_error!(
        solver.assert( & (sys.init_term(), & k) ), event
      ) ;

      let mut cpt = 0 ;

      loop {

        let actlit = factory.sym(format!("fresh_{}", cpt)) ;
        let actlit = factory.var_consign().var( actlit ) ;
        let mut neg_props = Vec::with_capacity(props.len()) ;
        for prop in props.iter() {
          neg_props.push(
            factory.op(
              Operator::Not, vec![prop.body().clone()]
            )
          )
        }
        let prop_term = factory.op(
          Operator::Or, neg_props
        ) ;
        event.log(
          & format!("defining actlit {}\nto be {}", actlit, prop_term)
        ) ;

        try_error!(
          solver.declare_fun(
            & (& actlit, k.curr()),
            & Vec::<Type>::new(),
            & Type::Bool
          ), event
        ) ;

        let e = factory.op(
          Operator::Impl, vec![
            factory.mk_var(actlit.clone()),
            prop_term
          ]
        ) ;

        try_error!(
          solver.assert(& (& e, & k)), event
        ) ;

        event.log("check-sat") ;

        match solver.check_sat_assuming( & vec![(& actlit, k.curr())] ) {
          Ok(true) => event.log("sat"),
          Ok(false) => event.log("unsat"),
          Err(e) => event.log( & format!("{:?}", e) ),
        } ;

        break

      }
    },
  }
}<|endoftext|>


<commit_before>use orbclient::{self, EventIter, Renderer};
use std;

use interpolate::Interpolator;
use model::mesh::Mesh;
use primitive::edge::Edge;
use primitive::matrix::Matrix4f32;
use primitive::vertex::Vertex;
use texture::bitmap::BitmapTexture;

pub struct RenderContext {
    window: orbclient::Window,
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{window: orb_window}
    }

    pub fn get_height(&self) -> u32 {
        self.window.height()
    }

    pub fn get_width(&self) -> u32 {
        self.window.width()
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF220CE8});
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_mesh(&mut self, mesh: &Mesh, transform: &Matrix4f32, texture: &BitmapTexture) {
        for idx in (0..mesh.indices.len()).step_by(3) {
            let v1 = &mesh.vertices[mesh.indices[idx as usize] as usize].transform(&transform);
            let v2 = &mesh.vertices[mesh.indices[(idx + 1) as usize] as usize].transform(&transform);
            let v3 = &mesh.vertices[mesh.indices[(idx + 2) as usize] as usize].transform(&transform);

            self.draw_triangle(v1, v2, v3, &texture);
        }
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex, texture: &BitmapTexture) {

        //TODO(dustin): optimisation do not calculate/init every time
        let screen_space_transform = Matrix4f32::new().init_sreenspace_transform(self.get_width() as f32 / 2f32, self.get_height() as f32 / 2f32);

        let mut min_vert = v1.transform(&screen_space_transform).perspective_divide();
        let mut mid_vert = v2.transform(&screen_space_transform).perspective_divide();
        let mut max_vert = v3.transform(&screen_space_transform).perspective_divide();

        if min_vert.calc_double_area(&max_vert, &mid_vert) >= 0 {
            return;
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut max_vert);
        }

        if mid_vert.pos.y < min_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut min_vert);
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut max_vert, &mut mid_vert);
        }

        self.scan_triangle(&min_vert, &mid_vert, &max_vert, min_vert.calc_double_area(&max_vert, &mid_vert) >= 0, texture);
    }

    fn scan_triangle(&mut self,  min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: bool, texture: &BitmapTexture) {

        let interpolator = Interpolator::new(min_vert, mid_vert, max_vert);
        let mut top_to_bottom = Edge::new(&interpolator, min_vert, max_vert, 0);
        let mut top_to_middle = Edge::new(&interpolator, min_vert, mid_vert, 0);
        let mut middle_to_bottom = Edge::new(&interpolator, mid_vert, max_vert, 1);

        self.scan_edges(&mut top_to_bottom, &mut top_to_middle, side, texture);
        self.scan_edges(&mut top_to_bottom, &mut middle_to_bottom, side, texture);
    }

    fn scan_edges(&mut self, first: &mut Edge, second: &mut Edge, side: bool, texture: &BitmapTexture) {

        let start_y = second.start_y;
        let end_y = second.end_y;

        let mut left = first;
        let mut right = second;

        if side {
            std::mem::swap(&mut left, &mut right);
        }

        for idx_y in start_y..end_y {
            self.draw_scan_line(&left, &right, idx_y, texture);
            left.step();
            right.step();
        }
    }

    fn draw_scan_line(&mut self, left: &Edge, right: &Edge, idx_y: i32, texture: &BitmapTexture) {

        let min_x = left.pos_x.ceil() as i32;
        let max_x = right.pos_x.ceil()as i32;
        let prestep_x = min_x as f32 - left.pos_x;

        let dist_x = right.pos_x - left.pos_x;
        let tex_coords_step_xx = (right.tex_coords_x - left.tex_coords_x) / dist_x;
        let tex_coords_step_yx = (right.tex_coords_y - left.tex_coords_y) / dist_x;
        let one_over_step_zx = (right.one_over_z - left.one_over_z) / dist_x;

        let mut tex_coords_x = left.tex_coords_x + tex_coords_step_xx * prestep_x;
        let mut tex_coords_y = left.tex_coords_y + tex_coords_step_yx * prestep_x;
        let mut one_over_z = left.one_over_z + one_over_step_zx * prestep_x;

        for idx_x in min_x..max_x {
            let z = 1_f32 / one_over_z;
            let src_x = ((tex_coords_x * z) * (texture.width - 1) as f32 + 0.5_f32) as i32;
            let src_y = ((tex_coords_y * z) * (texture.height - 1) as f32 + 0.5_f32) as i32;

            self.window.pixel(idx_x, idx_y, texture.get_orb_pixel(src_x, src_y));

            one_over_z += one_over_step_zx;
            tex_coords_x += tex_coords_step_xx;
            tex_coords_y += tex_coords_step_yx;
        }
    }
}
<commit_msg>faster pixel drawing<commit_after>use orbclient::{self, EventIter, Renderer};
use std;

use interpolate::Interpolator;
use model::mesh::Mesh;
use primitive::edge::Edge;
use primitive::matrix::Matrix4f32;
use primitive::vertex::Vertex;
use texture::bitmap::BitmapTexture;

pub struct RenderContext {
    window: orbclient::Window,
}

impl RenderContext {
    pub fn new(width: u32, height: u32, title: &str) -> RenderContext {
        let orb_window = orbclient::Window::new_flags(100, 100, width, height, title, true).unwrap();
        RenderContext{window: orb_window}
    }

    pub fn get_height(&self) -> u32 {
        self.window.height()
    }

    pub fn get_width(&self) -> u32 {
        self.window.width()
    }

    pub fn events(&mut self) -> EventIter {
        self.window.events()
    }

    pub fn clear(&mut self) {
        self.window.set(orbclient::Color { data: 0xFF220CE8});
    }

    pub fn sync(&mut self) {
        self.window.sync();
    }

    pub fn draw_mesh(&mut self, mesh: &Mesh, transform: &Matrix4f32, texture: &BitmapTexture) {
        for idx in (0..mesh.indices.len()).step_by(3) {
            let v1 = &mesh.vertices[mesh.indices[idx as usize] as usize].transform(&transform);
            let v2 = &mesh.vertices[mesh.indices[(idx + 1) as usize] as usize].transform(&transform);
            let v3 = &mesh.vertices[mesh.indices[(idx + 2) as usize] as usize].transform(&transform);

            self.draw_triangle(v1, v2, v3, &texture);
        }
    }

    pub fn draw_triangle(&mut self, v1: &Vertex, v2: &Vertex, v3: &Vertex, texture: &BitmapTexture) {

        //TODO(dustin): optimisation do not calculate/init every time
        let screen_space_transform = Matrix4f32::new().init_sreenspace_transform(self.get_width() as f32 / 2f32, self.get_height() as f32 / 2f32);

        let mut min_vert = v1.transform(&screen_space_transform).perspective_divide();
        let mut mid_vert = v2.transform(&screen_space_transform).perspective_divide();
        let mut max_vert = v3.transform(&screen_space_transform).perspective_divide();

        if min_vert.calc_double_area(&max_vert, &mid_vert) >= 0 {
            return;
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut max_vert);
        }

        if mid_vert.pos.y < min_vert.pos.y {
            std::mem::swap(&mut mid_vert, &mut min_vert);
        }

        if max_vert.pos.y < mid_vert.pos.y {
            std::mem::swap(&mut max_vert, &mut mid_vert);
        }

        self.scan_triangle(&min_vert, &mid_vert, &max_vert, min_vert.calc_double_area(&max_vert, &mid_vert) >= 0, texture);
    }

    fn scan_triangle(&mut self,  min_vert: &Vertex, mid_vert: &Vertex, max_vert: &Vertex, side: bool, texture: &BitmapTexture) {

        let interpolator = Interpolator::new(min_vert, mid_vert, max_vert);
        let mut top_to_bottom = Edge::new(&interpolator, min_vert, max_vert, 0);
        let mut top_to_middle = Edge::new(&interpolator, min_vert, mid_vert, 0);
        let mut middle_to_bottom = Edge::new(&interpolator, mid_vert, max_vert, 1);

        self.scan_edges(&mut top_to_bottom, &mut top_to_middle, side, texture);
        self.scan_edges(&mut top_to_bottom, &mut middle_to_bottom, side, texture);
    }

    fn scan_edges(&mut self, first: &mut Edge, second: &mut Edge, side: bool, texture: &BitmapTexture) {

        let start_y = second.start_y;
        let end_y = second.end_y;

        let mut left = first;
        let mut right = second;

        if side {
            std::mem::swap(&mut left, &mut right);
        }

        for idx_y in start_y..end_y {
            self.draw_scan_line(&left, &right, idx_y, texture);
            left.step();
            right.step();
        }
    }

    fn draw_scan_line(&mut self, left: &Edge, right: &Edge, idx_y: i32, texture: &BitmapTexture) {

        let min_x = left.pos_x.ceil() as i32;
        let max_x = right.pos_x.ceil()as i32;
        let prestep_x = min_x as f32 - left.pos_x;

        let dist_x = right.pos_x - left.pos_x;
        let tex_coords_step_xx = (right.tex_coords_x - left.tex_coords_x) / dist_x;
        let tex_coords_step_yx = (right.tex_coords_y - left.tex_coords_y) / dist_x;
        let one_over_step_zx = (right.one_over_z - left.one_over_z) / dist_x;

        let mut tex_coords_x = left.tex_coords_x + tex_coords_step_xx * prestep_x;
        let mut tex_coords_y = left.tex_coords_y + tex_coords_step_yx * prestep_x;
        let mut one_over_z = left.one_over_z + one_over_step_zx * prestep_x;

        let ww = self.window.width();
        let wh = self.window.height();
        let data = self.window.data_mut();

        for idx_x in min_x..max_x {

            let data_idx = idx_y * ww as i32 + idx_x;
            if data_idx >= data.len() as i32 || data_idx < 0 {
                break;
            }

            let z = 1_f32 / one_over_z;
            let src_x = ((tex_coords_x * z) * (texture.width - 1) as f32 + 0.5_f32) as i32;
            let src_y = ((tex_coords_y * z) * (texture.height - 1) as f32 + 0.5_f32) as i32;

//            self.window.pixel(idx_x, idx_y, texture.get_orb_pixel(src_x, src_y));
            let new = texture.get_orb_pixel(src_x, src_y).data;
            let old = &mut data[idx_y as usize * ww as usize + idx_x as usize].data;
            *old = new;

            one_over_z += one_over_step_zx;
            tex_coords_x += tex_coords_step_xx;
            tex_coords_y += tex_coords_step_yx;
        }
    }
}
<|endoftext|>


<commit_before>use ammonia::Ammonia;
use comrak;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
pub struct MarkdownRenderer<'a> {
    html_sanitizer: Ammonia<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    pub fn new() -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "target"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align", "width"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let html_sanitizer = Ammonia {
            keep_cleaned_elements: true,
            tags: tags,
            tag_attributes: tag_attributes,
            ..Ammonia::default()
        };
        MarkdownRenderer { html_sanitizer: html_sanitizer }
    }

    /// Renders the given markdown to HTML using the current settings.
    pub fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered))
    }
}

impl<'a> Default for MarkdownRenderer<'a> {
    fn default() -> Self {
        Self::new()
    }
}

/// Renders a markdown text to sanitized HTML.
///
/// The returned text should not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// # Examples
///
/// ```
/// use render::markdown_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = markdown_to_html(text)?;
/// ```
pub fn markdown_to_html(text: &str) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new();
    renderer.to_html(text)
}

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

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered.contains("foo_readme"), true);
        assert_eq!(rendered.contains("script"), false);
        assert_eq!(rendered.contains("alert('Hello World')"), true);
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered.contains("foo_readme"), true);
        assert_eq!(rendered.contains("iframe"), false);
        assert_eq!(rendered.contains("alert('Hello World')"), true);
    }

    #[test]
    fn text_with_unknwon_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered.contains("foo_readme"), true);
        assert_eq!(rendered.contains("unknown"), false);
        assert_eq!(rendered.contains("alert('Hello World')"), true);
    }

    #[test]
    fn text_with_inline_javascript() {
        let text = r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered.contains("foo_readme"), true);
        assert_eq!(rendered.contains("<a"), true);
        assert_eq!(rendered.contains("href="), true);
        assert_eq!(rendered.contains("onclick"), false);
        assert_eq!(rendered.contains("window.alert"), false);
        assert_eq!(rendered.contains("Crate page"), true);
    }
}
<commit_msg>Update tests to match GFM tag filtering<commit_after>use ammonia::Ammonia;
use comrak;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
pub struct MarkdownRenderer<'a> {
    html_sanitizer: Ammonia<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    pub fn new() -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "target"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align", "width"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let html_sanitizer = Ammonia {
            keep_cleaned_elements: true,
            tags: tags,
            tag_attributes: tag_attributes,
            ..Ammonia::default()
        };
        MarkdownRenderer { html_sanitizer: html_sanitizer }
    }

    /// Renders the given markdown to HTML using the current settings.
    pub fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered))
    }
}

impl<'a> Default for MarkdownRenderer<'a> {
    fn default() -> Self {
        Self::new()
    }
}

/// Renders a markdown text to sanitized HTML.
///
/// The returned text should not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// # Examples
///
/// ```
/// use render::markdown_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = markdown_to_html(text)?;
/// ```
pub fn markdown_to_html(text: &str) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new();
    renderer.to_html(text)
}

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

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknwon_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered.contains("foo_readme"), true);
        assert_eq!(rendered.contains("unknown"), false);
        assert_eq!(rendered.contains("alert('Hello World')"), true);
    }

    #[test]
    fn text_with_inline_javascript() {
        let text = r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text);
        assert_eq!(result.is_ok(), true);
        let rendered = result.unwrap();
        assert_eq!(rendered.contains("foo_readme"), true);
        assert_eq!(rendered.contains("<a"), true);
        assert_eq!(rendered.contains("href="), true);
        assert_eq!(rendered.contains("onclick"), false);
        assert_eq!(rendered.contains("window.alert"), false);
        assert_eq!(rendered.contains("Crate page"), true);
    }
}
<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the self-application combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the reverse application combinator T

use term::{Term, abs, app};
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(i().app(Var(1)), NOR, 0, false), Var(1));
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(k(), Var(1), Var(2)), NOR, 0, false), Var(1));
/// # }
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(s(), Var(1), Var(2), Var(3)              ), NOR, 0, false),
///            beta(app!(     Var(1), Var(3), app!(Var(2), Var(3))), NOR, 0, false)
/// );
/// # }
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), app(Var(2), Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(iota(), iota()), NOR, 0, false), i());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), iota()))), NOR, 0, false), k());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), app!(iota(), iota())))), NOR, 0, false), s());
/// # }
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(b(), Var(1),      Var(2), Var(3) ), NOR, 0, false),
///            beta(app!(     Var(1), app!(Var(2), Var(3))), NOR, 0, false)
/// );
/// # }
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        app(Var(3), app(Var(2), Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(c(), Var(1), Var(2), Var(3)), NOR, 0, false),
///            beta(app!(     Var(1), Var(3), Var(2)), NOR, 0, false)
/// );
/// # }
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(   w(), Var(1), Var(2)), NOR, 0, false),
///            beta(app!(Var(1), Var(2), Var(2)), NOR, 0, false)
/// );
/// # }
/// ```
pub fn w() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the self-application combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(  om().app(Var(1)), NOR, 0, false),
///            beta(Var(1).app(Var(1)), NOR, 0, false)
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(omm(), NOR, 3, false), omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator.
///
/// It is suitable for `NOR` (normal), `HNO` (hybrid normal), `CBN` (call-by-name) and `HSP`
/// (head spine) reduction `Order`s.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(beta(              app!(y(), dummy() ), NOR, 0, false),
///            beta(app!(dummy(), app!(y(), dummy())), NOR, 0, false)
/// );
/// # }
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator.
///
/// It will work with all the reduction orders suitable for its lazy counterpart (the `Y`
/// combinator). In addition, it will also work with `CBV` (call-by-value) and `HAP` (hybrid
/// applicative) reduction `Order`s, but with them it's not a drop-in replacement for the `Y`
/// combinator - in order for such expressions to work, they need to be modified so that the
/// evaluation of arguments of conditionals and other terms that need to be lazy is delayed.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(beta(              app!(z(), dummy() ), CBV, 0, false),
///            beta(app!(dummy(), app!(z(), dummy())), CBV, 0, false)
/// );
/// # }
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the reverse application combinator.
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(t(), Var(1), Var(2)), NOR, 0, false),
///                 app!(     Var(2), Var(1))
/// );
/// # }
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<commit_msg>use abs!() in combinators.rs<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the self-application combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the reverse application combinator T

use term::{Term, abs, app};
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(i().app(Var(1)), NOR, 0, false), Var(1));
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(k(), Var(1), Var(2)), NOR, 0, false), Var(1));
/// # }
/// ```
pub fn k() -> Term { abs!(2, Var(2)) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(s(), Var(1), Var(2), Var(3)              ), NOR, 0, false),
///            beta(app!(     Var(1), Var(3), app!(Var(2), Var(3))), NOR, 0, false)
/// );
/// # }
/// ```
pub fn s() -> Term {
    abs!(3, app!(Var(3), Var(1), app(Var(2), Var(1))))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(iota(), iota()), NOR, 0, false), i());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), iota()))), NOR, 0, false), k());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), app!(iota(), iota())))), NOR, 0, false), s());
/// # }
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(b(), Var(1),      Var(2), Var(3) ), NOR, 0, false),
///            beta(app!(     Var(1), app!(Var(2), Var(3))), NOR, 0, false)
/// );
/// # }
/// ```
pub fn b() -> Term {
    abs!(3, app(Var(3), app(Var(2), Var(1))))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(c(), Var(1), Var(2), Var(3)), NOR, 0, false),
///            beta(app!(     Var(1), Var(3), Var(2)), NOR, 0, false)
/// );
/// # }
/// ```
pub fn c() -> Term {
    abs!(3, app!(Var(3), Var(1), Var(2)))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(   w(), Var(1), Var(2)), NOR, 0, false),
///            beta(app!(Var(1), Var(2), Var(2)), NOR, 0, false)
/// );
/// # }
/// ```
pub fn w() -> Term {
    abs!(2, app!(Var(2), Var(1), Var(1)))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs!(2, app(Var(1), app!(Var(2), Var(2), Var(1)))) }
*/
/// ω - the self-application combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(  om().app(Var(1)), NOR, 0, false),
///            beta(Var(1).app(Var(1)), NOR, 0, false)
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(omm(), NOR, 3, false), omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator.
///
/// It is suitable for `NOR` (normal), `HNO` (hybrid normal), `CBN` (call-by-name) and `HSP`
/// (head spine) reduction `Order`s.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(beta(              app!(y(), dummy() ), NOR, 0, false),
///            beta(app!(dummy(), app!(y(), dummy())), NOR, 0, false)
/// );
/// # }
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator.
///
/// It will work with all the reduction orders suitable for its lazy counterpart (the `Y`
/// combinator). In addition, it will also work with `CBV` (call-by-value) and `HAP` (hybrid
/// applicative) reduction `Order`s, but with them it's not a drop-in replacement for the `Y`
/// combinator - in order for such expressions to work, they need to be modified so that the
/// evaluation of arguments of conditionals and other terms that need to be lazy is delayed.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::*;
///
/// fn dummy() -> Term { abs(Var(2)) } // a dummy term that won't easily reduce
///
/// assert_eq!(beta(              app!(z(), dummy() ), CBV, 0, false),
///            beta(app!(dummy(), app!(z(), dummy())), CBV, 0, false)
/// );
/// # }
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the reverse application combinator.
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::*;
///
/// assert_eq!(beta(app!(t(), Var(1), Var(2)), NOR, 0, false),
///                 app!(     Var(2), Var(1))
/// );
/// # }
/// ```
pub fn t() -> Term {
    abs!(2, app(Var(1), Var(2)))
}
<|endoftext|>


<commit_before>use std::error;
use std::default::Default;

use hyper;
use rusoto_core::{default_tls_client, DefaultCredentialsProvider, Region};
use rusoto_ecs;
use rusoto_ecs::{
  Ecs, EcsClient };

use config;
use super::error::CommandError;

pub trait EcsExecuter {

  fn client(&self) -> &EcsClient<DefaultCredentialsProvider, hyper::client::Client>;

  fn describe_latest_task_definition(&self, family: &str) -> Result<Option<rusoto_ecs::TaskDefinition>, Box<error::Error>> {
    debug!("EcsCommand::describe_latest_task_definition");

    let req = rusoto_ecs::DescribeTaskDefinitionRequest {
      task_definition: family.to_owned()
    };

    let res = try!(self.client().describe_task_definition(&req));
    info!("Completed to describe task_definition successfully");

    Ok(res.task_definition)
  }

  fn register_task_definition(&self, task_definition_conf: &config::ecs::TaskDefinition) -> Result<rusoto_ecs::TaskDefinition, Box<error::Error>> {
    debug!("EcsCommand::register_task_definition");
    let req = rusoto_ecs::RegisterTaskDefinitionRequest {
      family: task_definition_conf.family.to_owned(),
      task_role_arn: task_definition_conf.task_role_arn.to_owned(),
      network_mode: task_definition_conf.network_mode.to_owned(),
      container_definitions: task_definition_conf.container_definitions.iter().map(|cd| cd.to_rusoto()).collect(),
      ..Default::default()
    };

    let res = try!(self.client().register_task_definition(&req));
    info!("Completed to register task_definition successfully");

    res.task_definition.ok_or(Box::new(CommandError::Unknown))
  }

  fn create_service(&self, cluster: &str, service_conf: &config::ecs::Service, task_definition: &str) -> Result<rusoto_ecs::Service, Box<error::Error>> {
    debug!("EcsCommand::register_task_definition");

    let req = rusoto_ecs::CreateServiceRequest {
      cluster: Some(cluster.to_owned()),
      service_name: service_conf.name.to_owned(),
      desired_count: service_conf.desired_count,
      //deployment_configuration: service_conf.deployment_configuration.as_ref().map(|d| d.to_rusoto()),
      load_balancers: service_conf.load_balancers.as_ref().map(|lbs| lbs.iter().map(|lb| lb.to_rusoto()).collect()),
      role: service_conf.role.to_owned(),
      task_definition: task_definition.to_owned(),
      ..Default::default()
    };

    let res = try!(self.client().create_service(&req));
    info!("Completed to create service successfully");

    res.service.ok_or(Box::new(CommandError::Unknown))
  }

  fn describe_service(&self, cluster: &str, service_conf: &config::ecs::Service) -> Result<Option<rusoto_ecs::Service>, Box<error::Error>> {
    debug!("EcsCommand::describe_service");

    let req = rusoto_ecs::DescribeServicesRequest {
      cluster: Some(cluster.to_owned()),
      services: vec![service_conf.name.to_owned()]
    };

    let res = try!(self.client().describe_services(&req));
    info!("Completed to describe services successfully");

    match res.services {
      Some(services) => {
        let actives = services.iter().filter(|service| service.status.is_some() && service.status.as_ref().unwrap() == "ACTIVE").collect::<Vec<&rusoto_ecs::Service>>();
        Ok(actives.first().cloned().cloned())
      },
      _ => Err(Box::new(CommandError::Unknown))
    }
  }

  fn update_service(&self, cluster: &str, service_conf: &config::ecs::Service, service: &rusoto_ecs::Service, task_definition: &rusoto_ecs::TaskDefinition) -> Result<rusoto_ecs::Service, Box<error::Error>> {
    debug!("EcsCommand::update_service");

    if task_definition.task_definition_arn.is_none() {
      return Err(Box::new(CommandError::Unknown))
    }

    let req = rusoto_ecs::UpdateServiceRequest {
      service: service_conf.name.to_owned(),
      cluster: Some(cluster.to_owned()),
      desired_count: Some(service_conf.desired_count),
      deployment_configuration: service_conf.deployment_configuration.as_ref().map(|d| d.to_rusoto()),
      task_definition: task_definition.task_definition_arn.to_owned(),
      ..Default::default()
    };

    let res = try!(self.client().update_service(&req));
    info!("Completed to update service successfully");

    let service = res.service.map(|s| { s.to_owned() });
    service.ok_or(Box::new(CommandError::Unknown))
  }

  fn run_task(&self, cluster: &str, task_definition_arn: &str) -> Result<(), Box<error::Error>> {

    let req = rusoto_ecs::RunTaskRequest {
      cluster: Some(cluster.to_owned()),
      task_definition: task_definition_arn.to_owned(),
      ..Default::default()
    };

    let res = try!(self.client().run_task(&req));
    info!("Completed to run task successfully");

    Ok(())
  }

  fn detect_task_definition_changes(&self, task_definition_conf: &config::ecs::TaskDefinition, current_task_definitions: &rusoto_ecs::TaskDefinition) -> bool {
    if current_task_definitions.family.is_none() || current_task_definitions.family.as_ref().unwrap().as_str() != task_definition_conf.family.as_str() {
      return true
    }
    // if current_task_definitions.task_role_arn.is_none() || current_task_definitions.task_role_arn.as_ref().unwrap().as_str() != task_definition_conf.task_role_arn.as_str() {
    //   return true
    // }
    // if current_task_definitions.network_mode.is_none() || current_task_definitions.network_mode.as_ref().unwrap().as_str() != task_definition_conf.network_mode.as_str() {
    //   return true
    // }

    // TODO: detect difference between config of container definition and current one
    true

    //false
  }

}
<commit_msg>catch error if no task-definition exists<commit_after>use std::error;
use std::default::Default;

use hyper;
use rusoto_core::{default_tls_client, DefaultCredentialsProvider, Region};
use rusoto_ecs;
use rusoto_ecs::{
  Ecs, EcsClient };

use config;
use super::error::CommandError;

pub trait EcsExecuter {

  fn client(&self) -> &EcsClient<DefaultCredentialsProvider, hyper::client::Client>;

  fn describe_latest_task_definition(&self, family: &str) -> Result<Option<rusoto_ecs::TaskDefinition>, Box<error::Error>> {
    debug!("EcsCommand::describe_latest_task_definition");

    let req = rusoto_ecs::DescribeTaskDefinitionRequest {
      task_definition: family.to_owned()
    };

    match self.client().describe_task_definition(&req) {
      Ok(res) => {
        info!("Completed to describe task_definition successfully");
        Ok(res.task_definition)
      }
      Err(rusoto_ecs::DescribeTaskDefinitionError::Client(s)) => {
        info!("Not found the task-definition: {}", family);
        Ok(None)
      }
      Err(e) => {
        Err(Box::new(e))
      }
    }
  }

  fn register_task_definition(&self, task_definition_conf: &config::ecs::TaskDefinition) -> Result<rusoto_ecs::TaskDefinition, Box<error::Error>> {
    debug!("EcsCommand::register_task_definition");
    let req = rusoto_ecs::RegisterTaskDefinitionRequest {
      family: task_definition_conf.family.to_owned(),
      task_role_arn: task_definition_conf.task_role_arn.to_owned(),
      network_mode: task_definition_conf.network_mode.to_owned(),
      container_definitions: task_definition_conf.container_definitions.iter().map(|cd| cd.to_rusoto()).collect(),
      ..Default::default()
    };

    let res = try!(self.client().register_task_definition(&req));
    info!("Completed to register task_definition successfully");

    res.task_definition.ok_or(Box::new(CommandError::Unknown))
  }

  fn create_service(&self, cluster: &str, service_conf: &config::ecs::Service, task_definition: &str) -> Result<rusoto_ecs::Service, Box<error::Error>> {
    debug!("EcsCommand::register_task_definition");

    let req = rusoto_ecs::CreateServiceRequest {
      cluster: Some(cluster.to_owned()),
      service_name: service_conf.name.to_owned(),
      desired_count: service_conf.desired_count,
      //deployment_configuration: service_conf.deployment_configuration.as_ref().map(|d| d.to_rusoto()),
      load_balancers: service_conf.load_balancers.as_ref().map(|lbs| lbs.iter().map(|lb| lb.to_rusoto()).collect()),
      role: service_conf.role.to_owned(),
      task_definition: task_definition.to_owned(),
      ..Default::default()
    };

    let res = try!(self.client().create_service(&req));
    info!("Completed to create service successfully");

    res.service.ok_or(Box::new(CommandError::Unknown))
  }

  fn describe_service(&self, cluster: &str, service_conf: &config::ecs::Service) -> Result<Option<rusoto_ecs::Service>, Box<error::Error>> {
    debug!("EcsCommand::describe_service");

    let req = rusoto_ecs::DescribeServicesRequest {
      cluster: Some(cluster.to_owned()),
      services: vec![service_conf.name.to_owned()]
    };

    let res = try!(self.client().describe_services(&req));
    info!("Completed to describe services successfully");

    match res.services {
      Some(services) => {
        let actives = services.iter().filter(|service| service.status.is_some() && service.status.as_ref().unwrap() == "ACTIVE").collect::<Vec<&rusoto_ecs::Service>>();
        Ok(actives.first().cloned().cloned())
      },
      _ => Err(Box::new(CommandError::Unknown))
    }
  }

  fn update_service(&self, cluster: &str, service_conf: &config::ecs::Service, service: &rusoto_ecs::Service, task_definition: &rusoto_ecs::TaskDefinition) -> Result<rusoto_ecs::Service, Box<error::Error>> {
    debug!("EcsCommand::update_service");

    if task_definition.task_definition_arn.is_none() {
      return Err(Box::new(CommandError::Unknown))
    }

    let req = rusoto_ecs::UpdateServiceRequest {
      service: service_conf.name.to_owned(),
      cluster: Some(cluster.to_owned()),
      desired_count: Some(service_conf.desired_count),
      deployment_configuration: service_conf.deployment_configuration.as_ref().map(|d| d.to_rusoto()),
      task_definition: task_definition.task_definition_arn.to_owned(),
      ..Default::default()
    };

    let res = try!(self.client().update_service(&req));
    info!("Completed to update service successfully");

    let service = res.service.map(|s| { s.to_owned() });
    service.ok_or(Box::new(CommandError::Unknown))
  }

  fn run_task(&self, cluster: &str, task_definition_arn: &str) -> Result<(), Box<error::Error>> {

    let req = rusoto_ecs::RunTaskRequest {
      cluster: Some(cluster.to_owned()),
      task_definition: task_definition_arn.to_owned(),
      ..Default::default()
    };

    let res = try!(self.client().run_task(&req));
    info!("Completed to run task successfully");

    Ok(())
  }

  fn detect_task_definition_changes(&self, task_definition_conf: &config::ecs::TaskDefinition, current_task_definitions: &rusoto_ecs::TaskDefinition) -> bool {
    if current_task_definitions.family.is_none() || current_task_definitions.family.as_ref().unwrap().as_str() != task_definition_conf.family.as_str() {
      return true
    }
    // if current_task_definitions.task_role_arn.is_none() || current_task_definitions.task_role_arn.as_ref().unwrap().as_str() != task_definition_conf.task_role_arn.as_str() {
    //   return true
    // }
    // if current_task_definitions.network_mode.is_none() || current_task_definitions.network_mode.as_ref().unwrap().as_str() != task_definition_conf.network_mode.as_str() {
    //   return true
    // }

    // TODO: detect difference between config of container definition and current one
    true

    //false
  }

}
<|endoftext|>