<commit_before>use tab_organizer::styles::*;
use std::sync::{RwLock, Arc};
use futures_signals::signal::{Signal, SignalExt, Mutable};
use dominator::{Dom, DomBuilder, HIGHEST_ZINDEX, html, clone, events, class, text};
use lazy_static::lazy_static;
use web_sys::{Element, EventTarget};

lazy_static! {
    static ref TOP_STYLE: String = class! {
        .style("position", "absolute")
        .style("top", "calc(100% + 4px)")
        .style("right", "0px")
        .style("z-index", HIGHEST_ZINDEX)
    };

    static ref MENU_ARROW_STYLE: String = class! {
        .style("width", "0px")
        .style("height", "0px")
        .style("border-left", "8px solid transparent")
        .style("border-right", "8px solid transparent")
        .style("border-bottom", "8px solid white")
        .style("position", "absolute")
        .style("top", "-7px")
        .style("right", "4px")
    };

    /*static ref MENU_ARROW_STYLE: String = class! {
        .style("width", "12px")
        .style("height", "12px")
        .style("border-top", "1px solid rgb(204, 204, 204)")
        .style("border-left", "1px solid rgb(204, 204, 204)")
        .style("transform", "rotate(45deg)")
        .style("position", "absolute")
        .style("background-color", "white")
        .style("top", "-6px")
        .style("right", "5px")
    };*/

    static ref MENU_MODAL_STYLE: String = class! {
        .style("background-color", "hsla(0, 0%, 0%, 0.15)")
    };

    static ref MENU_STYLE: String = class! {
        //.style("overflow", "hidden")
        .style("border", "1px solid rgb(204, 204, 204)")
        .style("box-shadow", "rgba(0, 0, 0, 0.15) -1px 1px 5px")
    };

    static ref MENU_CHEVRON_STYLE: String = class! {
        .style("margin-left", "6px")

        .style("border-top", "2px solid rgb(117, 117, 118)")
        .style("border-right", "2px solid rgb(117, 117, 118)")
        .style("width", "5.07px")
        .style("height", "5.07px")
        .style("transform", "rotate(45deg)")
    };

    static ref SUBMENU_HEADER_STYLE: String = class! {
        .style("text-align", "center")
        .style("font-size", "13px")
        .style("height", "28px")
    };

    static ref SUBMENU_HEADER_BACK_STYLE: String = class! {
        .style("position", "absolute")
        .style("top", "-2px")
        .style("left", "4px")
        .style("width", "32px")
        .style("height", "32px")
        .style("z-index", "1")
    };

    static ref SUBMENU_HEADER_BACK_HOVER_STYLE: String = class! {
        .style("background-color", "rgb(237, 237, 237)")
    };

    static ref BACK_CHEVRON_STYLE: String = class! {
        .style("border-top", "2px solid rgb(12, 12, 13)")
        .style("border-left", "2px solid rgb(12, 12, 13)")
        .style("width", "6.48px")
        .style("height", "6.48px")
        .style("transform", "rotate(-45deg)")
    };

    static ref SUBMENU_STYLE: String = class! {
        .style("font-size", "12px")
        // TODO is this a good width ?
        .style("min-width", "150px")
        .style("background-color", "white")
        .style("white-space", "pre")
        .style("padding-top", "6px")
        .style("padding-bottom", "6px")
    };

    static ref MENU_ITEM_STYLE: String = class! {
        .style("cursor", "pointer")
        .style("position", "static")
        .style("height", "24px")
        //.style("padding-top", "1px")
        //.style("padding-bottom", "1px")
        .style("padding-left", "11px")
        .style("padding-right", "11px")
        .style("color", "black")
        .style("text-shadow", "none")
    };

    static ref MENU_ITEM_HOVER_STYLE: String = class! {
        .style("background-color", "rgb(237, 237, 237)")
    };

    /*static ref MENU_ITEM_SUBMENU_STYLE: String = class! {
        // TODO a tiny bit hacky
        .style("cursor", "default")
    };*/

    static ref MENU_ITEM_SELECTED_STYLE: String = class! {
        .style("font-weight", "bold")
    };

    // TODO code duplication with main.rs
    static ref MENU_ITEM_SHADOW_STYLE: String = class! {
        .style("box-shadow", "      0px 1px  1px hsla(0, 0%,   0%, 0.25), \
                              inset 0px 0px  3px hsla(0, 0%, 100%, 1   ), \
                              inset 0px 0px 10px hsla(0, 0%, 100%, 0.25)")
    };

    static ref SEPARATOR_STYLE: String = class! {
        .style("background-color", "rgb(222, 222, 222)")
        .style("margin", "6px 0px")
        .style("height", "1px")
    };
}

#[derive(Debug)]
struct Parent {
    visible: Mutable<bool>,
}

#[derive(Debug)]
enum ChildState {
    Item {
        hovered: Mutable<bool>,
    },
    Submenu {
        visible: Mutable<bool>,
    },
}

// TODO verify that there aren't any Arc cycles
#[derive(Debug)]
struct MenuBuilderState {
    state: Arc<MenuState>,
    children: RwLock<Vec<ChildState>>,
}

impl MenuBuilderState {
    fn new(state: Arc<MenuState>) -> Self {
        Self {
            state,
            children: RwLock::new(vec![]),
        }
    }

    fn hide(&self) {
        self.state.visible.set_neq(false);
        self.hide_children();
    }

    fn hide_children(&self) {
        let lock = self.children.read().unwrap();

        for item in lock.iter() {
            match item {
                ChildState::Item { hovered } => {
                    hovered.set_neq(false);
                },
                ChildState::Submenu { visible } => {
                    visible.set_neq(false);
                },
            }
        }
    }

    fn push(&self, child: ChildState) {
        let mut lock = self.children.write().unwrap();

        lock.push(child);
    }
}

// TODO verify that there aren't any Arc cycles
#[derive(Debug)]
pub(crate) struct MenuBuilder {
    state: Arc<MenuBuilderState>,
    parent: Arc<Parent>,
    children: Vec<Dom>,
    submenus: Vec<Dom>,
}

impl MenuBuilder {
    fn new(state: Arc<MenuBuilderState>, parent: Arc<Parent>) -> Self {
        Self {
            state,
            parent,
            children: vec![],
            submenus: vec![],
        }
    }

    fn menu_item<A>(&mut self) -> impl FnOnce(DomBuilder<A>) -> DomBuilder<A> where A: AsRef<Element> + AsRef<EventTarget> + Clone + 'static {
        let hovered = Mutable::new(false);

        self.state.push(ChildState::Item {
            hovered: hovered.clone(),
        });

        // TODO is this inline a good idea ?
        #[inline]
        move |dom| { dom
            .class(&*ROW_STYLE)
            .class(&*MENU_ITEM_STYLE)

            .class_signal(&*MENU_ITEM_HOVER_STYLE, hovered.signal())
            //.class_signal(&*MENU_ITEM_SHADOW_STYLE, hovered.signal())

            .event(clone!(hovered => move |_: events::MouseEnter| {
                hovered.set_neq(true);
            }))

            .event(move |_: events::MouseLeave| {
                hovered.set_neq(false);
            })
        }
    }

    fn push_submenu<F>(&mut self, name: &str, f: F) where F: FnOnce(MenuBuilder) -> MenuBuilder {
        let visible = Mutable::new(false);

        let MenuBuilder { mut children, mut submenus, .. } = f(MenuBuilder::new(self.state.clone(), Arc::new(Parent {
            visible: visible.clone(),
        })));

        let parent = self.parent.clone();
        let state = self.state.clone();
        let mixin = self.menu_item();

        self.children.push(html!("div", {
            .apply(mixin)

            .event(clone!(state, visible => move |_: events::Click| {
                state.hide_children();
                visible.set_neq(true);
            }))

            .children(&mut [
                // TODO figure out a way to avoid this wrapper div ?
                html!("div", {
                    .class(&*STRETCH_STYLE)
                    .text(name)
                }),

                html!("div", {
                    .class(&*MENU_CHEVRON_STYLE)
                }),
            ])
        }));

        let back_hover = Mutable::new(false);

        self.state.push(ChildState::Item {
            hovered: back_hover.clone(),
        });

        children.insert(0, html!("div", {
            .class([
                &*CENTER_STYLE,
                &*SUBMENU_HEADER_STYLE,
            ])

            .children(&mut [
                html!("div", {
                    .class([
                        &*CENTER_STYLE,
                        &*SUBMENU_HEADER_BACK_STYLE,
                    ])

                    .class_signal(&*SUBMENU_HEADER_BACK_HOVER_STYLE, back_hover.signal())

                    .event(clone!(back_hover => move |_: events::MouseEnter| {
                        back_hover.set_neq(true);
                    }))

                    .event(move |_: events::MouseLeave| {
                        back_hover.set_neq(false);
                    })

                    .event(clone!(state, parent => move |_: events::Click| {
                        state.hide_children();
                        parent.visible.set_neq(true);
                    }))

                    .children(&mut [
                        html!("div", {
                            .class(&*BACK_CHEVRON_STYLE)
                        })
                    ])
                }),

                text(name),
            ])
        }));

        // TODO code duplication
        children.insert(1, html!("hr", {
            .class(&*SEPARATOR_STYLE)
        }));

        self.state.push(ChildState::Submenu {
            visible: visible.clone(),
        });

        self.submenus.push(html!("div", {
            .class(&*SUBMENU_STYLE)

            .visible_signal(visible.signal())

            .children(&mut children)
        }));

        self.submenus.append(&mut submenus);
    }

    #[inline]
    pub(crate) fn submenu<F>(mut self, name: &str, f: F) -> Self where F: FnOnce(MenuBuilder) -> MenuBuilder {
        self.push_submenu(name, f);
        self
    }

    fn push_separator(&mut self) {
        self.children.push(html!("hr", {
            .class(&*SEPARATOR_STYLE)
        }));
    }

    #[inline]
    pub(crate) fn separator(mut self) -> Self {
        self.push_separator();
        self
    }

    fn push_option<A, F>(&mut self, name: &str, signal: A, mut on_click: F)
        where A: Signal<Item = bool> + 'static,
              F: FnMut() + 'static {

        let mixin = self.menu_item();

        let state = self.state.clone();

        self.children.push(html!("div", {
            .apply(mixin)

            .class_signal(&*MENU_ITEM_SELECTED_STYLE, signal)

            .event(move |_: events::Click| {
                state.hide();
                on_click();
            })

            .text(name)
        }));
    }

    #[inline]
    pub(crate) fn option<A, F>(mut self, name: &str, signal: A, on_click: F) -> Self
        where A: Signal<Item = bool> + 'static,
              F: FnMut() + 'static {
        self.push_option(name, signal, on_click);
        self
    }
}

#[derive(Debug)]
struct MenuState {
    visible: Mutable<bool>,
}

impl MenuState {
    fn new() -> Self {
        Self {
            visible: Mutable::new(false),
        }
    }
}

// TODO verify that there aren't any Arc cycles
#[derive(Debug)]
pub(crate) struct Menu {
    state: Arc<MenuState>,
}

impl Menu {
    pub(crate) fn new() -> Self {
        Self {
            state: Arc::new(MenuState::new()),
        }
    }

    pub(crate) fn show(&self) {
        self.state.visible.set_neq(true);
    }

    pub(crate) fn is_showing(&self) -> impl Signal<Item = bool> {
        self.state.visible.signal()
    }

    pub(crate) fn render<F>(&self, f: F) -> Dom where F: FnOnce(MenuBuilder) -> MenuBuilder {
        let menus = Arc::new(MenuBuilderState::new(self.state.clone()));
        let visible = Mutable::new(false);

        let MenuBuilder { mut children, mut submenus, .. } = f(MenuBuilder::new(menus.clone(), Arc::new(Parent {
            visible: visible.clone(),
        })));

        {
            menus.push(ChildState::Submenu {
                visible: visible.clone(),
            });

            submenus.insert(0, html!("div", {
                .class(&*SUBMENU_STYLE)

                .visible_signal(visible.signal())

                // TODO is there a better way of doing this ?
                .future(self.state.visible.signal().for_each(clone!(menus => move |show| {
                    if show {
                        visible.set_neq(true);

                    } else {
                        menus.hide_children();
                    }

                    async {}
                })))

                .children(&mut children)
            }));
        }

        html!("div", {
            .class(&*TOP_STYLE)

            .visible_signal(self.state.visible.signal())

            .children(&mut [
                html!("div", {
                    .class([
                        &*MODAL_STYLE,
                        &*MENU_MODAL_STYLE,
                    ])

                    .event(move |_: events::Click| {
                        menus.hide();
                    })
                }),

                html!("div", {
                    .class(&*MENU_STYLE)

                    .children(&mut submenus)
                }),

                html!("div", {
                    .class(&*MENU_ARROW_STYLE)
                }),
            ])
        })
    }
}
<commit_msg>Minor tweak<commit_after>use tab_organizer::styles::*;
use std::sync::{RwLock, Arc};
use futures_signals::signal::{Signal, SignalExt, Mutable};
use dominator::{Dom, DomBuilder, HIGHEST_ZINDEX, html, clone, events, class, text};
use lazy_static::lazy_static;
use web_sys::{Element, EventTarget};

lazy_static! {
    static ref TOP_STYLE: String = class! {
        .style("position", "absolute")
        .style("top", "calc(100% + 4px)")
        .style("right", "0px")
        .style("z-index", HIGHEST_ZINDEX)
    };

    static ref MENU_ARROW_STYLE: String = class! {
        .style("width", "0px")
        .style("height", "0px")
        .style("border-left", "8px solid transparent")
        .style("border-right", "8px solid transparent")
        .style("border-bottom", "8px solid white")
        .style("position", "absolute")
        .style("top", "-7px")
        .style("right", "4px")
    };

    /*static ref MENU_ARROW_STYLE: String = class! {
        .style("width", "12px")
        .style("height", "12px")
        .style("border-top", "1px solid rgb(204, 204, 204)")
        .style("border-left", "1px solid rgb(204, 204, 204)")
        .style("transform", "rotate(45deg)")
        .style("position", "absolute")
        .style("background-color", "white")
        .style("top", "-6px")
        .style("right", "5px")
    };*/

    static ref MENU_MODAL_STYLE: String = class! {
        .style("background-color", "hsla(0, 0%, 0%, 0.15)")
    };

    static ref MENU_STYLE: String = class! {
        //.style("overflow", "hidden")
        .style("border", "1px solid rgb(204, 204, 204)")
        .style("box-shadow", "rgba(0, 0, 0, 0.15) -1px 1px 5px")
    };

    static ref MENU_CHEVRON_STYLE: String = class! {
        .style("margin-left", "6px")

        .style("border-top", "2px solid rgb(117, 117, 118)")
        .style("border-right", "2px solid rgb(117, 117, 118)")
        .style("width", "5.07px")
        .style("height", "5.07px")
        .style("transform", "rotate(45deg)")
    };

    static ref SUBMENU_HEADER_STYLE: String = class! {
        .style("text-align", "center")
        .style("font-size", "13px")
        .style("height", "28px")
    };

    static ref SUBMENU_HEADER_BACK_STYLE: String = class! {
        .style("position", "absolute")
        .style("top", "-2px")
        .style("left", "4px")
        .style("width", "32px")
        .style("height", "32px")
        .style("z-index", "1")
    };

    static ref SUBMENU_HEADER_BACK_HOVER_STYLE: String = class! {
        .style("background-color", "rgb(237, 237, 237)")
    };

    static ref BACK_CHEVRON_STYLE: String = class! {
        .style("border-top", "2px solid rgb(12, 12, 13)")
        .style("border-left", "2px solid rgb(12, 12, 13)")
        .style("width", "6.48px")
        .style("height", "6.48px")
        .style("transform", "rotate(-45deg)")
    };

    static ref SUBMENU_STYLE: String = class! {
        .style("font-size", "12px")
        // TODO is this a good width ?
        .style("min-width", "200px")
        .style("background-color", "white")
        .style("white-space", "pre")
        .style("padding-top", "6px")
        .style("padding-bottom", "6px")
    };

    static ref MENU_ITEM_STYLE: String = class! {
        .style("cursor", "pointer")
        .style("position", "static")
        .style("height", "24px")
        //.style("padding-top", "1px")
        //.style("padding-bottom", "1px")
        .style("padding-left", "11px")
        .style("padding-right", "11px")
        .style("color", "black")
        .style("text-shadow", "none")
    };

    static ref MENU_ITEM_HOVER_STYLE: String = class! {
        .style("background-color", "rgb(237, 237, 237)")
    };

    /*static ref MENU_ITEM_SUBMENU_STYLE: String = class! {
        // TODO a tiny bit hacky
        .style("cursor", "default")
    };*/

    static ref MENU_ITEM_SELECTED_STYLE: String = class! {
        .style("font-weight", "bold")
    };

    // TODO code duplication with main.rs
    static ref MENU_ITEM_SHADOW_STYLE: String = class! {
        .style("box-shadow", "      0px 1px  1px hsla(0, 0%,   0%, 0.25), \
                              inset 0px 0px  3px hsla(0, 0%, 100%, 1   ), \
                              inset 0px 0px 10px hsla(0, 0%, 100%, 0.25)")
    };

    static ref SEPARATOR_STYLE: String = class! {
        .style("background-color", "rgb(222, 222, 222)")
        .style("margin", "6px 0px")
        .style("height", "1px")
    };
}

#[derive(Debug)]
struct Parent {
    visible: Mutable<bool>,
}

#[derive(Debug)]
enum ChildState {
    Item {
        hovered: Mutable<bool>,
    },
    Submenu {
        visible: Mutable<bool>,
    },
}

// TODO verify that there aren't any Arc cycles
#[derive(Debug)]
struct MenuBuilderState {
    state: Arc<MenuState>,
    children: RwLock<Vec<ChildState>>,
}

impl MenuBuilderState {
    fn new(state: Arc<MenuState>) -> Self {
        Self {
            state,
            children: RwLock::new(vec![]),
        }
    }

    fn hide(&self) {
        self.state.visible.set_neq(false);
        self.hide_children();
    }

    fn hide_children(&self) {
        let lock = self.children.read().unwrap();

        for item in lock.iter() {
            match item {
                ChildState::Item { hovered } => {
                    hovered.set_neq(false);
                },
                ChildState::Submenu { visible } => {
                    visible.set_neq(false);
                },
            }
        }
    }

    fn push(&self, child: ChildState) {
        let mut lock = self.children.write().unwrap();

        lock.push(child);
    }
}

// TODO verify that there aren't any Arc cycles
#[derive(Debug)]
pub(crate) struct MenuBuilder {
    state: Arc<MenuBuilderState>,
    parent: Arc<Parent>,
    children: Vec<Dom>,
    submenus: Vec<Dom>,
}

impl MenuBuilder {
    fn new(state: Arc<MenuBuilderState>, parent: Arc<Parent>) -> Self {
        Self {
            state,
            parent,
            children: vec![],
            submenus: vec![],
        }
    }

    fn menu_item<A>(&mut self) -> impl FnOnce(DomBuilder<A>) -> DomBuilder<A> where A: AsRef<Element> + AsRef<EventTarget> + Clone + 'static {
        let hovered = Mutable::new(false);

        self.state.push(ChildState::Item {
            hovered: hovered.clone(),
        });

        // TODO is this inline a good idea ?
        #[inline]
        move |dom| { dom
            .class(&*ROW_STYLE)
            .class(&*MENU_ITEM_STYLE)

            .class_signal(&*MENU_ITEM_HOVER_STYLE, hovered.signal())
            //.class_signal(&*MENU_ITEM_SHADOW_STYLE, hovered.signal())

            .event(clone!(hovered => move |_: events::MouseEnter| {
                hovered.set_neq(true);
            }))

            .event(move |_: events::MouseLeave| {
                hovered.set_neq(false);
            })
        }
    }

    fn push_submenu<F>(&mut self, name: &str, f: F) where F: FnOnce(MenuBuilder) -> MenuBuilder {
        let visible = Mutable::new(false);

        let MenuBuilder { mut children, mut submenus, .. } = f(MenuBuilder::new(self.state.clone(), Arc::new(Parent {
            visible: visible.clone(),
        })));

        let parent = self.parent.clone();
        let state = self.state.clone();
        let mixin = self.menu_item();

        self.children.push(html!("div", {
            .apply(mixin)

            .event(clone!(state, visible => move |_: events::Click| {
                state.hide_children();
                visible.set_neq(true);
            }))

            .children(&mut [
                // TODO figure out a way to avoid this wrapper div ?
                html!("div", {
                    .class(&*STRETCH_STYLE)
                    .text(name)
                }),

                html!("div", {
                    .class(&*MENU_CHEVRON_STYLE)
                }),
            ])
        }));

        let back_hover = Mutable::new(false);

        self.state.push(ChildState::Item {
            hovered: back_hover.clone(),
        });

        children.insert(0, html!("div", {
            .class([
                &*CENTER_STYLE,
                &*SUBMENU_HEADER_STYLE,
            ])

            .children(&mut [
                html!("div", {
                    .class([
                        &*CENTER_STYLE,
                        &*SUBMENU_HEADER_BACK_STYLE,
                    ])

                    .class_signal(&*SUBMENU_HEADER_BACK_HOVER_STYLE, back_hover.signal())

                    .event(clone!(back_hover => move |_: events::MouseEnter| {
                        back_hover.set_neq(true);
                    }))

                    .event(move |_: events::MouseLeave| {
                        back_hover.set_neq(false);
                    })

                    .event(clone!(state, parent => move |_: events::Click| {
                        state.hide_children();
                        parent.visible.set_neq(true);
                    }))

                    .children(&mut [
                        html!("div", {
                            .class(&*BACK_CHEVRON_STYLE)
                        })
                    ])
                }),

                text(name),
            ])
        }));

        // TODO code duplication
        children.insert(1, html!("hr", {
            .class(&*SEPARATOR_STYLE)
        }));

        self.state.push(ChildState::Submenu {
            visible: visible.clone(),
        });

        self.submenus.push(html!("div", {
            .class(&*SUBMENU_STYLE)

            .visible_signal(visible.signal())

            .children(&mut children)
        }));

        self.submenus.append(&mut submenus);
    }

    #[inline]
    pub(crate) fn submenu<F>(mut self, name: &str, f: F) -> Self where F: FnOnce(MenuBuilder) -> MenuBuilder {
        self.push_submenu(name, f);
        self
    }

    fn push_separator(&mut self) {
        self.children.push(html!("hr", {
            .class(&*SEPARATOR_STYLE)
        }));
    }

    #[inline]
    pub(crate) fn separator(mut self) -> Self {
        self.push_separator();
        self
    }

    fn push_option<A, F>(&mut self, name: &str, signal: A, mut on_click: F)
        where A: Signal<Item = bool> + 'static,
              F: FnMut() + 'static {

        let mixin = self.menu_item();

        let state = self.state.clone();

        self.children.push(html!("div", {
            .apply(mixin)

            .class_signal(&*MENU_ITEM_SELECTED_STYLE, signal)

            .event(move |_: events::Click| {
                state.hide();
                on_click();
            })

            .text(name)
        }));
    }

    #[inline]
    pub(crate) fn option<A, F>(mut self, name: &str, signal: A, on_click: F) -> Self
        where A: Signal<Item = bool> + 'static,
              F: FnMut() + 'static {
        self.push_option(name, signal, on_click);
        self
    }
}

#[derive(Debug)]
struct MenuState {
    visible: Mutable<bool>,
}

impl MenuState {
    fn new() -> Self {
        Self {
            visible: Mutable::new(false),
        }
    }
}

// TODO verify that there aren't any Arc cycles
#[derive(Debug)]
pub(crate) struct Menu {
    state: Arc<MenuState>,
}

impl Menu {
    pub(crate) fn new() -> Self {
        Self {
            state: Arc::new(MenuState::new()),
        }
    }

    pub(crate) fn show(&self) {
        self.state.visible.set_neq(true);
    }

    pub(crate) fn is_showing(&self) -> impl Signal<Item = bool> {
        self.state.visible.signal()
    }

    pub(crate) fn render<F>(&self, f: F) -> Dom where F: FnOnce(MenuBuilder) -> MenuBuilder {
        let menus = Arc::new(MenuBuilderState::new(self.state.clone()));
        let visible = Mutable::new(false);

        let MenuBuilder { mut children, mut submenus, .. } = f(MenuBuilder::new(menus.clone(), Arc::new(Parent {
            visible: visible.clone(),
        })));

        {
            menus.push(ChildState::Submenu {
                visible: visible.clone(),
            });

            submenus.insert(0, html!("div", {
                .class(&*SUBMENU_STYLE)

                .visible_signal(visible.signal())

                // TODO is there a better way of doing this ?
                .future(self.state.visible.signal().for_each(clone!(menus => move |show| {
                    if show {
                        visible.set_neq(true);

                    } else {
                        menus.hide_children();
                    }

                    async {}
                })))

                .children(&mut children)
            }));
        }

        html!("div", {
            .class(&*TOP_STYLE)

            .visible_signal(self.state.visible.signal())

            .children(&mut [
                html!("div", {
                    .class([
                        &*MODAL_STYLE,
                        &*MENU_MODAL_STYLE,
                    ])

                    .event(move |_: events::Click| {
                        menus.hide();
                    })
                }),

                html!("div", {
                    .class(&*MENU_STYLE)

                    .children(&mut submenus)
                }),

                html!("div", {
                    .class(&*MENU_ARROW_STYLE)
                }),
            ])
        })
    }
}
<|endoftext|>


<commit_before>use crate::display_delegate::display;
use proc_macro2::{Group, Span, TokenTree};
use quote::{ToTokens};
use std::fmt::{Error, Formatter};
use syn::{self, ArgCaptured, Block, Expr, ExprVerbatim, FnArg, FnDecl, GenericParam, Ident, Pat, PatIdent, PathSegment,
          Stmt};
use syn::punctuated::Punctuated;
use syn::token::{Colon2, Semi};

const MOCKTOPUS_CRATE_NAME:     &str = "__mocktopus_crate__";
const STD_CRATE_NAME:           &str = "__mocktopus_std__";
const ARGS_TO_CONTINUE_NAME:    &str = "__mocktopus_args_to_continue__";
const UNWIND_DATA_NAME:         &str = "__mocktopus_unwind_data__";

macro_rules! error_msg {
    ($msg:expr) => { concat!("Mocktopus internal error: ", $msg) }
}

pub enum FnHeaderBuilder<'a> {
    StaticFn,
    StructImpl,
    TraitDefault,
    TraitImpl(&'a Punctuated<PathSegment, Colon2>),
}

impl<'a> FnHeaderBuilder<'a> {
    pub fn build(&self, fn_ident: &Ident, fn_decl: &FnDecl, fn_block_span: Span) -> Stmt {
        let fn_args = &fn_decl.inputs;
        let header_str = format!(
r#"{{
    extern crate mocktopus as {mocktopus};
    extern crate std as {std_crate};
    match {std_crate}::panic::catch_unwind({std_crate}::panic::AssertUnwindSafe (
            || {mocktopus}::mocking::Mockable::call_mock(&{full_fn_name}, {extract_args}))) {{
        Ok({mocktopus}::mocking::MockResult::Continue({args_to_continue})) => {restore_args},
        Ok({mocktopus}::mocking::MockResult::Return(result)) => {{
            {forget_args}
            let returned = unsafe {{ {std_crate}::mem::transmute_copy(&result) }};
            {std_crate}::mem::forget(result);
            return returned;
        }},
        Err({unwind}) => {{
            {forget_args}
            {std_crate}::panic::resume_unwind({unwind});
        }},
    }}
}}"#,
        mocktopus           = MOCKTOPUS_CRATE_NAME,
        std_crate           = STD_CRATE_NAME,
        full_fn_name        = display(|f| write_full_fn_name(f, self, fn_ident, fn_decl)),
        extract_args        = display(|f| write_extract_args(f, fn_args)),
        args_to_continue    = ARGS_TO_CONTINUE_NAME,
        restore_args        = display(|f| write_restore_args(f, fn_args)),
        forget_args         = display(|f| write_forget_args(f, fn_args)),
        unwind              = UNWIND_DATA_NAME);
        let header_block = syn::parse_str::<Block>(&header_str)
            .expect(error_msg!("generated header unparsable"));
        create_call_site_spanned_stmt(header_block, fn_block_span)
    }
}

fn create_call_site_spanned_stmt(block: Block, span: Span) -> Stmt {
    let token_stream = block.into_token_stream()
        .into_iter()
        .map(|tt| make_token_tree_span_call_site(tt, span))
        .collect();
    Stmt::Semi(
        Expr::Verbatim(
            ExprVerbatim {
                tts: token_stream,
            }
        ),
        Semi([span])
    )
}

fn make_token_tree_span_call_site(mut token_tree: TokenTree, span: Span) -> TokenTree {
    token_tree.set_span(span);
    if let TokenTree::Group(ref mut group) = token_tree {
        let tokens = group.stream().into_iter()
            .map(|tt| make_token_tree_span_call_site(tt, span))
            .collect();
        *group = Group::new(group.delimiter(), tokens);
    }
    token_tree
}

fn write_full_fn_name(f: &mut Formatter, builder: &FnHeaderBuilder, fn_ident: &Ident, fn_decl: &FnDecl)
        -> Result<(), Error> {
    match *builder {
        FnHeaderBuilder::StaticFn               => (),
        FnHeaderBuilder::StructImpl |
        FnHeaderBuilder::TraitDefault           => write!(f, "Self::")?,
        FnHeaderBuilder::TraitImpl(ref path)    => write!(f, "<Self as {}>::", display(|f| write_trait_path(f, path)))?,
    }
    write!(f, "{}::<{}>", fn_ident, display(|f| write_fn_generics(f, fn_decl)))
}

fn write_trait_path<T: ToTokens + Clone>(f: &mut Formatter, path: &Punctuated<PathSegment, T>) -> Result<(), Error> {
    write!(f, "{}", path.into_token_stream())
}

fn write_fn_generics(f: &mut Formatter, fn_decl: &FnDecl) -> Result<(), Error> {
    fn_decl.generics.params.iter()
        .filter_map(get_generic_param_name)
        .map(|param| write!(f, "{},", param))
        .collect()
}

fn get_generic_param_name(param: &GenericParam) -> Option<String> {
    match *param {
        GenericParam::Type(ref type_param) => Some(type_param.ident.to_string()),
        _ => None,
    }
}

fn write_extract_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return write!(f, "()");
    }
    write!(f, "unsafe {{ (")?;
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        write!(f, "{}::mem::replace(&mut *(&{} as *const _ as *mut _), {}::mem::uninitialized()), ",
               STD_CRATE_NAME, fn_arg_name, STD_CRATE_NAME)?;
    }
    write!(f, ") }}")
}

fn write_restore_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return writeln!(f, "()");
    }
    writeln!(f, "unsafe {{")?;
    for (fn_arg_index, fn_arg_name) in iter_fn_arg_names(fn_args).enumerate() {
        writeln!(f, "{}::mem::forget({}::mem::replace({}::mocking_utils::as_mut(&{}), {}.{}));",
            STD_CRATE_NAME, STD_CRATE_NAME, MOCKTOPUS_CRATE_NAME, fn_arg_name, ARGS_TO_CONTINUE_NAME, fn_arg_index)?;
    }
    writeln!(f, "}}")
}

fn write_forget_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        writeln!(f, "{}::mem::forget({});", STD_CRATE_NAME, fn_arg_name)?;
    }
    Ok(())
}

fn iter_fn_arg_names<'a, T>(input_args: &'a Punctuated<FnArg, T>) -> impl Iterator<Item = String> + 'a {
    input_args.iter()
        .map(|fn_arg| match *fn_arg {
            FnArg::SelfRef(_) | FnArg::SelfValue(_) => "self".to_string(),
            FnArg::Captured(
                ArgCaptured {
                    pat: Pat::Ident(
                        PatIdent {
                            ref ident,
                            subpat: None,
                            ..
                        }
                    ),
                    ..
                }
            ) => ident.to_string(),
            _ => panic!("{}: '{}'", error_msg!("invalid fn arg type"), fn_arg.clone().into_token_stream()),
        })
}
<commit_msg>Replace mem::uninitialized with mem::zeroed<commit_after>use crate::display_delegate::display;
use proc_macro2::{Group, Span, TokenTree};
use quote::{ToTokens};
use std::fmt::{Error, Formatter};
use syn::{self, ArgCaptured, Block, Expr, ExprVerbatim, FnArg, FnDecl, GenericParam, Ident, Pat, PatIdent, PathSegment,
          Stmt};
use syn::punctuated::Punctuated;
use syn::token::{Colon2, Semi};

const MOCKTOPUS_CRATE_NAME:     &str = "__mocktopus_crate__";
const STD_CRATE_NAME:           &str = "__mocktopus_std__";
const ARGS_TO_CONTINUE_NAME:    &str = "__mocktopus_args_to_continue__";
const UNWIND_DATA_NAME:         &str = "__mocktopus_unwind_data__";

macro_rules! error_msg {
    ($msg:expr) => { concat!("Mocktopus internal error: ", $msg) }
}

pub enum FnHeaderBuilder<'a> {
    StaticFn,
    StructImpl,
    TraitDefault,
    TraitImpl(&'a Punctuated<PathSegment, Colon2>),
}

impl<'a> FnHeaderBuilder<'a> {
    pub fn build(&self, fn_ident: &Ident, fn_decl: &FnDecl, fn_block_span: Span) -> Stmt {
        let fn_args = &fn_decl.inputs;
        let header_str = format!(
r#"{{
    extern crate mocktopus as {mocktopus};
    extern crate std as {std_crate};
    match {std_crate}::panic::catch_unwind({std_crate}::panic::AssertUnwindSafe (
            || {mocktopus}::mocking::Mockable::call_mock(&{full_fn_name}, {extract_args}))) {{
        Ok({mocktopus}::mocking::MockResult::Continue({args_to_continue})) => {restore_args},
        Ok({mocktopus}::mocking::MockResult::Return(result)) => {{
            {forget_args}
            let returned = unsafe {{ {std_crate}::mem::transmute_copy(&result) }};
            {std_crate}::mem::forget(result);
            return returned;
        }},
        Err({unwind}) => {{
            {forget_args}
            {std_crate}::panic::resume_unwind({unwind});
        }},
    }}
}}"#,
        mocktopus           = MOCKTOPUS_CRATE_NAME,
        std_crate           = STD_CRATE_NAME,
        full_fn_name        = display(|f| write_full_fn_name(f, self, fn_ident, fn_decl)),
        extract_args        = display(|f| write_extract_args(f, fn_args)),
        args_to_continue    = ARGS_TO_CONTINUE_NAME,
        restore_args        = display(|f| write_restore_args(f, fn_args)),
        forget_args         = display(|f| write_forget_args(f, fn_args)),
        unwind              = UNWIND_DATA_NAME);
        let header_block = syn::parse_str::<Block>(&header_str)
            .expect(error_msg!("generated header unparsable"));
        create_call_site_spanned_stmt(header_block, fn_block_span)
    }
}

fn create_call_site_spanned_stmt(block: Block, span: Span) -> Stmt {
    let token_stream = block.into_token_stream()
        .into_iter()
        .map(|tt| make_token_tree_span_call_site(tt, span))
        .collect();
    Stmt::Semi(
        Expr::Verbatim(
            ExprVerbatim {
                tts: token_stream,
            }
        ),
        Semi([span])
    )
}

fn make_token_tree_span_call_site(mut token_tree: TokenTree, span: Span) -> TokenTree {
    token_tree.set_span(span);
    if let TokenTree::Group(ref mut group) = token_tree {
        let tokens = group.stream().into_iter()
            .map(|tt| make_token_tree_span_call_site(tt, span))
            .collect();
        *group = Group::new(group.delimiter(), tokens);
    }
    token_tree
}

fn write_full_fn_name(f: &mut Formatter, builder: &FnHeaderBuilder, fn_ident: &Ident, fn_decl: &FnDecl)
        -> Result<(), Error> {
    match *builder {
        FnHeaderBuilder::StaticFn               => (),
        FnHeaderBuilder::StructImpl |
        FnHeaderBuilder::TraitDefault           => write!(f, "Self::")?,
        FnHeaderBuilder::TraitImpl(ref path)    => write!(f, "<Self as {}>::", display(|f| write_trait_path(f, path)))?,
    }
    write!(f, "{}::<{}>", fn_ident, display(|f| write_fn_generics(f, fn_decl)))
}

fn write_trait_path<T: ToTokens + Clone>(f: &mut Formatter, path: &Punctuated<PathSegment, T>) -> Result<(), Error> {
    write!(f, "{}", path.into_token_stream())
}

fn write_fn_generics(f: &mut Formatter, fn_decl: &FnDecl) -> Result<(), Error> {
    fn_decl.generics.params.iter()
        .filter_map(get_generic_param_name)
        .map(|param| write!(f, "{},", param))
        .collect()
}

fn get_generic_param_name(param: &GenericParam) -> Option<String> {
    match *param {
        GenericParam::Type(ref type_param) => Some(type_param.ident.to_string()),
        _ => None,
    }
}

fn write_extract_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return write!(f, "()");
    }
    write!(f, "unsafe {{ (")?;
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        write!(f, "{}::mem::replace(&mut *(&{} as *const _ as *mut _), {}::mem::zeroed()), ",
               STD_CRATE_NAME, fn_arg_name, STD_CRATE_NAME)?;
    }
    write!(f, ") }}")
}

fn write_restore_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return writeln!(f, "()");
    }
    writeln!(f, "unsafe {{")?;
    for (fn_arg_index, fn_arg_name) in iter_fn_arg_names(fn_args).enumerate() {
        writeln!(f, "{}::mem::forget({}::mem::replace({}::mocking_utils::as_mut(&{}), {}.{}));",
            STD_CRATE_NAME, STD_CRATE_NAME, MOCKTOPUS_CRATE_NAME, fn_arg_name, ARGS_TO_CONTINUE_NAME, fn_arg_index)?;
    }
    writeln!(f, "}}")
}

fn write_forget_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        writeln!(f, "{}::mem::forget({});", STD_CRATE_NAME, fn_arg_name)?;
    }
    Ok(())
}

fn iter_fn_arg_names<'a, T>(input_args: &'a Punctuated<FnArg, T>) -> impl Iterator<Item = String> + 'a {
    input_args.iter()
        .map(|fn_arg| match *fn_arg {
            FnArg::SelfRef(_) | FnArg::SelfValue(_) => "self".to_string(),
            FnArg::Captured(
                ArgCaptured {
                    pat: Pat::Ident(
                        PatIdent {
                            ref ident,
                            subpat: None,
                            ..
                        }
                    ),
                    ..
                }
            ) => ident.to_string(),
            _ => panic!("{}: '{}'", error_msg!("invalid fn arg type"), fn_arg.clone().into_token_stream()),
        })
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use nom::IResult;

#[derive(Debug)]
struct ZWord {
    first: u8,
    second: u8,
    third: u8,
    last_bit: u8
}

named!( take_5_bits<u8>, bits!( take_bits!( u8, 5 ) ) );

named!( take_z_word<&[u8],ZWord>,
    bits!(
        do_parse!(
            first: take_bits!( u8, 5 ) >>
            second: take_bits!( u8, 5 ) >>
            third: take_bits!( u8, 5 ) >>
            last_bit: take_bits!( u8, 1 ) >>
            (
                ZWord {
                    first: first,
                    second: second,
                    third: third,
                    last_bit: last_bit
                }
            )
        )
    )
);

fn char_from_5_bits(fiver: u8) -> char {
    let alphabet_table: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ];
    alphabet_table[fiver as usize]
}

/* The other two alphabet tables
[| " "; "?"; "?"; "?"; "?"; "?"; "A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J";
   "K"; "L"; "M"; "N"; "O"; "P"; "Q"; "R"; "S"; "T"; "U"; "V"; "W"; "X"; "Y"; "Z" |];
[| " "; "?"; "?"; "?"; "?"; "?"; "?"; "\n"; "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7";
   "8"; "9"; "."; ","; "!"; "?"; "_"; "#"; "'"; "\""; "/"; "\\"; "-"; ":"; "("; ")" |] |]
*/

fn z_string_fragment(bytes: &[u8]) -> String {
    if let IResult::Done(_, word) = take_z_word(bytes) {
        let ZWord { first: a, second: b, third: c, .. } = word;
        let chars = vec![
            char_from_5_bits(a),
            char_from_5_bits(b),
            char_from_5_bits(c)
        ];
        let s : String = chars.into_iter().collect();
        return s;
    }
    //TODO handle error case
    "NOT IMPLEMENTED".to_string()
}

#[test]
fn it_takes_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(take_5_bits( sl ), IResult::Done(&sl[1..], 21) );
}

#[test]
fn it_can_get_letter() {
    let starts_with_six = vec! [0b00110111, 0b11110000, 0b11110001];
    let sl = &starts_with_six[..];
    let expected = 'a';
    let actual = char_from_5_bits( take_5_bits(sl).to_result().unwrap() );
    assert_eq!(expected, actual);
}

#[test]
fn it_can_parse_the() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "the".to_string();
    let actual = z_string_fragment(sl);
    assert_eq!(expected, actual);
}<commit_msg>add write z string till break method<commit_after>#![allow(dead_code)]

use nom::IResult;
use std::io::{stderr, Write, ErrorKind};
use std::process;

#[derive(Debug)]
struct ZWord {
    first: u8,
    second: u8,
    third: u8,
    last_bit: u8
}

impl ZWord {
    pub fn to_string(&self) -> String {
        let ZWord { first: a, second: b, third: c, .. } = *self;
        let chars = vec![
            char_from_5_bits(a),
            char_from_5_bits(b),
            char_from_5_bits(c)
        ];
        let s : String = chars.into_iter().collect();
        s
    }
}

named!( take_5_bits<u8>, bits!( take_bits!( u8, 5 ) ) );

named!( take_z_word<&[u8],ZWord>,
    bits!(
        do_parse!(
            first: take_bits!( u8, 5 ) >>
            second: take_bits!( u8, 5 ) >>
            third: take_bits!( u8, 5 ) >>
            last_bit: take_bits!( u8, 1 ) >>
            (
                ZWord {
                    first: first,
                    second: second,
                    third: third,
                    last_bit: last_bit
                }
            )
        )
    )
);

fn char_from_5_bits(fiver: u8) -> char {
    let alphabet_table: Vec<char> = vec![
        ' ', '?', '?', '?', '?', '?', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' ];
    alphabet_table[fiver as usize]
}

/* The other two alphabet tables
[| " "; "?"; "?"; "?"; "?"; "?"; "A"; "B"; "C"; "D"; "E"; "F"; "G"; "H"; "I"; "J";
   "K"; "L"; "M"; "N"; "O"; "P"; "Q"; "R"; "S"; "T"; "U"; "V"; "W"; "X"; "Y"; "Z" |];
[| " "; "?"; "?"; "?"; "?"; "?"; "?"; "\n"; "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7";
   "8"; "9"; "."; ","; "!"; "?"; "_"; "#"; "'"; "\""; "/"; "\\"; "-"; ":"; "("; ")" |] |]
*/

fn z_string_fragment(bytes: &[u8]) -> String {
    if let IResult::Done(_, word) = take_z_word(bytes) {
       return word.to_string();
    }
    //TODO handle error case
    "NOT IMPLEMENTED".to_string()
}

fn read_until_break(bytes: &[u8], collection: &mut Vec<ZWord>) {
    let mut slice = bytes;
    loop {
        let result = take_z_word(slice);
        if let IResult::Done(rest, word) = result {
            let should_break = word.last_bit == 1 || rest.len() <= 2;
            collection.push(word);
            slice = rest;
            if should_break { break; }
        }
    }
}

pub fn dump_string_until_break<W: Write>(bytes: &[u8], writer: &mut W) {
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(bytes, &mut collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|z_word| z_word.to_string())
        .collect();

    for s in strings.into_iter() {
        let write_result = writeln!(writer, "{}", s);
        if let Err(e) = write_result {
            match e.kind() {
                ErrorKind::BrokenPipe => break,
                    _ => {
                        writeln!(stderr(), "{}", e).unwrap();
                        process::exit(1);
                    }
            }
        }
    }
}

#[test]
fn it_takes_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];
    assert_eq!(take_5_bits( sl ), IResult::Done(&sl[1..], 21) );
}

#[test]
fn it_can_get_letter() {
    let starts_with_six = vec! [0b00110111, 0b11110000, 0b11110001];
    let sl = &starts_with_six[..];
    let expected = 'a';
    let actual = char_from_5_bits( take_5_bits(sl).to_result().unwrap() );
    assert_eq!(expected, actual);
}

#[test]
fn it_can_parse_the() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "the".to_string();
    let actual = z_string_fragment(sl);
    assert_eq!(expected, actual);
}

#[test]
fn read_until_break_breaks() {
    let bytes_for_the = vec! [0b1100_1011u8, 0b0101_0100u8, 0b1100_1011u8, 0b0101_0101u8, 0b1100_1011u8, 0b0101_0101u8];
    let sl = &bytes_for_the[..];
    let expected = "thethe".to_string();
    let mut collection : Vec<ZWord> = Vec::new();
    read_until_break(sl, &mut collection);
    println!("{:?}", collection);
    let strings : Vec<String> = collection
        .into_iter()
        .map(|zword| zword.to_string())
        .collect();

    let actual = strings.concat();

    assert_eq!(expected, actual);
}<|endoftext|>


<commit_before>use std::slice;
use std::vec;
use std::cmp;

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// The iterator **Zip\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::Zip;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in Zip::new((0i32..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct Zip<T> {
    t: T
}

impl<T> Zip<T> where Zip<T>: Iterator
{
    /// Create a new **Zip** from a tuple of iterators.
    pub fn new(t: T) -> Zip<T>
    {
        Zip{t: t}
    }
}

macro_rules! impl_zip_iter {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for Zip<($($B,)*)>
            where
            $(
                $B: Iterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<
                    ($(<$B as Iterator>::Item,)*)
                >
            {
                let &mut Zip { t : ($(ref mut $B,)*)} = self;
                // WARNING: partial consume possible
                // Zip worked the same.
                $(
                    let $B = match $B.next() {
                        None => return None,
                        Some(elt) => elt
                    };
                )*
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                let low = ::std::usize::MAX;
                let high = None;
                let &Zip { t : ($(ref $B,)*) } = self;
                $(
                    // update estimate
                    let (l, h) = $B.size_hint();
                    let low = cmp::min(low, l);
                    let high = match (high, h) {
                        (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                        _ => high.or(h)
                    };
                )*
                (low, high)
            }
        }
    );
}

impl_zip_iter!(A);
impl_zip_iter!(A, B);
impl_zip_iter!(A, B, C);
impl_zip_iter!(A, B, C, D);
impl_zip_iter!(A, B, C, D, E);
impl_zip_iter!(A, B, C, D, E, F);
impl_zip_iter!(A, B, C, D, E, F, G);
impl_zip_iter!(A, B, C, D, E, F, G, H);
impl_zip_iter!(A, B, C, D, E, F, G, H, I);

/// A **TrustedIterator** has exact size, always.
pub unsafe trait TrustedIterator : ExactSizeIterator
{
    /* no methods */
}

unsafe impl TrustedIterator for ::std::ops::Range<usize> { }
unsafe impl TrustedIterator for ::std::ops::Range<u32> { }
unsafe impl TrustedIterator for ::std::ops::Range<i32> { }
unsafe impl TrustedIterator for ::std::ops::Range<u16> { }
unsafe impl TrustedIterator for ::std::ops::Range<i16> { }
unsafe impl TrustedIterator for ::std::ops::Range<u8> { }
unsafe impl TrustedIterator for ::std::ops::Range<i8> { }
unsafe impl<'a, T> TrustedIterator for slice::Iter<'a, T> { }
unsafe impl<'a, T> TrustedIterator for slice::IterMut<'a, T> { }
unsafe impl<T> TrustedIterator for vec::IntoIter<T> { }

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// **ZipTrusted** is an experimental version of **Zip**, and it can only use iterators that are
/// known to provide their exact size up front. The lockstep iteration can then compile to faster
/// code, ideally not checking more than once per lap for the end of iteration.
///
/// The iterator **ZipTrusted\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::ZipTrusted;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in ZipTrusted::new((0i32..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct ZipTrusted<T> {
    length: usize,
    t: T
}

trait SetLength {
    fn set_length(&mut self);
}

impl<T> ZipTrusted<T> where ZipTrusted<T>: SetLength
{
    /// Create a new **ZipTrusted** from a tuple of iterators.
    #[inline]
    pub fn new(t: T) -> ZipTrusted<T>
    {
        let mut iter = ZipTrusted {
            length: 0,
            t: t,
        };
        iter.set_length();
        iter
    }
}

macro_rules! impl_zip_trusted {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> SetLength for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            #[inline]
            fn set_length(&mut self)
            {
                let len = ::std::usize::MAX;
                let ($(ref $B,)*) = self.t;
                $(
                    let (l, h) = $B.size_hint();
                    let len = cmp::min(len, l);
                    debug_assert!(Some(l) == h);
                )*
                self.length = len;
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<<Self as Iterator>::Item>
            {
                let ($(ref mut $B,)*) = self.t;

                if self.length == 0 {
                    return None
                }
                $(
                    let next_opt = $B.next();
                    let $B;
                    unsafe {
                        ::std::intrinsics::assume(match next_opt {
                            None => false,
                            Some(_) => true,
                        });
                        $B = match next_opt {
                            None => return None,
                            Some(elt) => elt
                        };
                    }
                )*
                self.length -= 1;
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                (self.length, Some(self.length))
            }
        }
    );
}

impl_zip_trusted!(A);
impl_zip_trusted!(A, B);
impl_zip_trusted!(A, B, C);
impl_zip_trusted!(A, B, C, D);
impl_zip_trusted!(A, B, C, D, E);
impl_zip_trusted!(A, B, C, D, E, F);
impl_zip_trusted!(A, B, C, D, E, F, G);
impl_zip_trusted!(A, B, C, D, E, F, G, H);
impl_zip_trusted!(A, B, C, D, E, F, G, H, I);

<commit_msg>ZipTrusted: I trusted the Range iterators and I was wrong.<commit_after>use std::slice;
use std::vec;
use std::cmp;

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// The iterator **Zip\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::Zip;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in Zip::new((0i32..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct Zip<T> {
    t: T
}

impl<T> Zip<T> where Zip<T>: Iterator
{
    /// Create a new **Zip** from a tuple of iterators.
    pub fn new(t: T) -> Zip<T>
    {
        Zip{t: t}
    }
}

macro_rules! impl_zip_iter {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for Zip<($($B,)*)>
            where
            $(
                $B: Iterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<
                    ($(<$B as Iterator>::Item,)*)
                >
            {
                let &mut Zip { t : ($(ref mut $B,)*)} = self;
                // WARNING: partial consume possible
                // Zip worked the same.
                $(
                    let $B = match $B.next() {
                        None => return None,
                        Some(elt) => elt
                    };
                )*
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                let low = ::std::usize::MAX;
                let high = None;
                let &Zip { t : ($(ref $B,)*) } = self;
                $(
                    // update estimate
                    let (l, h) = $B.size_hint();
                    let low = cmp::min(low, l);
                    let high = match (high, h) {
                        (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
                        _ => high.or(h)
                    };
                )*
                (low, high)
            }
        }
    );
}

impl_zip_iter!(A);
impl_zip_iter!(A, B);
impl_zip_iter!(A, B, C);
impl_zip_iter!(A, B, C, D);
impl_zip_iter!(A, B, C, D, E);
impl_zip_iter!(A, B, C, D, E, F);
impl_zip_iter!(A, B, C, D, E, F, G);
impl_zip_iter!(A, B, C, D, E, F, G, H);
impl_zip_iter!(A, B, C, D, E, F, G, H, I);

/// A **TrustedIterator** has exact size, always.
pub unsafe trait TrustedIterator : ExactSizeIterator
{
    /* no methods */
}

/* Not safe yet!
unsafe impl TrustedIterator for ::std::ops::Range<usize> { }
unsafe impl TrustedIterator for ::std::ops::Range<u32> { }
unsafe impl TrustedIterator for ::std::ops::Range<i32> { }
unsafe impl TrustedIterator for ::std::ops::Range<u16> { }
unsafe impl TrustedIterator for ::std::ops::Range<i16> { }
unsafe impl TrustedIterator for ::std::ops::Range<u8> { }
unsafe impl TrustedIterator for ::std::ops::Range<i8> { }
*/
unsafe impl<'a, T> TrustedIterator for slice::Iter<'a, T> { }
unsafe impl<'a, T> TrustedIterator for slice::IterMut<'a, T> { }
unsafe impl<T> TrustedIterator for vec::IntoIter<T> { }

#[derive(Clone)]
/// Create an iterator running multiple iterators in lockstep.
///
/// **ZipTrusted** is an experimental version of **Zip**, and it can only use iterators that are
/// known to provide their exact size up front. The lockstep iteration can then compile to faster
/// code, ideally not checking more than once per lap for the end of iteration.
///
/// The iterator **ZipTrusted\<(I, J, ..., M)\>** is formed from a tuple of iterators and yields elements
/// until any of the subiterators yields **None**.
///
/// Iterator element type is like **(A, B, ..., E)** where **A** to **E** are the respective
/// subiterator types.
///
/// ## Example
///
/// ```
/// use itertools::ZipTrusted;
///
/// // Iterate over three sequences side-by-side
/// let mut xs = [0, 0, 0];
/// let ys = [69, 107, 101];
///
/// for (i, a, b) in ZipTrusted::new((0i32..100, xs.iter_mut(), ys.iter())) {
///    *a = i ^ *b;
/// }
///
/// assert_eq!(xs, [69, 106, 103]);
/// ```
pub struct ZipTrusted<T> {
    length: usize,
    t: T
}

trait SetLength {
    fn set_length(&mut self);
}

impl<T> ZipTrusted<T> where ZipTrusted<T>: SetLength
{
    /// Create a new **ZipTrusted** from a tuple of iterators.
    #[inline]
    pub fn new(t: T) -> ZipTrusted<T>
    {
        let mut iter = ZipTrusted {
            length: 0,
            t: t,
        };
        iter.set_length();
        iter
    }
}

macro_rules! impl_zip_trusted {
    ($($B:ident),*) => (
        #[allow(non_snake_case)]
        impl<$($B),*> SetLength for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            #[inline]
            fn set_length(&mut self)
            {
                let len = ::std::usize::MAX;
                let ($(ref $B,)*) = self.t;
                $(
                    let (l, h) = $B.size_hint();
                    let len = cmp::min(len, l);
                    debug_assert!(Some(l) == h);
                )*
                self.length = len;
            }
        }

        #[allow(non_snake_case)]
        impl<$($B),*> Iterator for ZipTrusted<($($B,)*)>
            where
            $(
                $B: TrustedIterator,
            )*
        {
            type Item = ($(<$B as Iterator>::Item,)*);

            fn next(&mut self) -> Option<<Self as Iterator>::Item>
            {
                let ($(ref mut $B,)*) = self.t;

                if self.length == 0 {
                    return None
                }
                $(
                    let next_opt = $B.next();
                    let $B;
                    unsafe {
                        ::std::intrinsics::assume(match next_opt {
                            None => false,
                            Some(_) => true,
                        });
                        $B = match next_opt {
                            None => return None,
                            Some(elt) => elt
                        };
                    }
                )*
                self.length -= 1;
                Some(($($B,)*))
            }

            fn size_hint(&self) -> (usize, Option<usize>)
            {
                (self.length, Some(self.length))
            }
        }
    );
}

impl_zip_trusted!(A);
impl_zip_trusted!(A, B);
impl_zip_trusted!(A, B, C);
impl_zip_trusted!(A, B, C, D);
impl_zip_trusted!(A, B, C, D, E);
impl_zip_trusted!(A, B, C, D, E, F);
impl_zip_trusted!(A, B, C, D, E, F, G);
impl_zip_trusted!(A, B, C, D, E, F, G, H);
impl_zip_trusted!(A, B, C, D, E, F, G, H, I);

<|endoftext|>


<commit_before>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

const A: uint = 'A' as uint;
const J: uint = 'J' as uint;
const Q: uint = 'Q' as uint;
const K: uint = 'K' as uint;
const D: uint = '♦' as uint;
const H: uint = '♥' as uint;
const S: uint = '♠' as uint;
const C: uint = '♣' as uint;

struct Card {
    rank: uint,
    suit: uint
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<uint, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars: HashMap<uint, uint> = HashMap::new();
        vars.insert(D, 0);
        vars.insert(H, 0);
        vars.insert(S, 0);
        vars.insert(C, 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0u  => self.newline(card),
                K   => self.jump(card),
                Q   => continue,
                J   => self.dump(card, true),
                10u => self.dump(card, false),
                _   => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i + 1 });

            // Parse cards using regural expression.
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as uint },
                   '2'...'9' => Card { rank: rank as uint - 48, suit: suit as uint },
                   _         => Card { rank: rank as uint, suit: suit as uint }
                };
                code.push(card);
            }
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        self.line = card.suit as uint;
        self
    }

    fn jump(&mut self, card: Card) -> &Ante {
        let mut suit = card.suit as uint;
        while self.pc < self.code.len() && self.code[self.pc].rank == K && self.code[self.pc].suit == card.suit {
            suit += card.suit as uint;
            self.pc += 1;
        }

        if self.vars[card.suit] != 0 {
            let label: uint = suit as uint;
            if self.labels.contains_key(&label) {
                self.pc = self.labels[label];
            } else {
                self.exception("can't find the label...");
            }
        }
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        let value = self.vars[card.suit];
        if as_character {
            if value <= 255 {
                print!("{}", std::char::from_u32(value as u32).unwrap());
            } else {
                self.exception(format!("character code {} is out of 0..255 range", value).as_slice());
            }
        } else {
            print!("{}", value);
        }
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial = operands[0].rank;
        let target = operands[0].suit;

        if initial == A {
            initial = self.vars[target];
        }

        for i in range(1, operands.len()) {
            let mut rank = operands[i].rank;
            let suit = operands[i].suit;

            if rank == A {
                rank = self.vars[suit];
            }
            match suit {
                D => initial += rank,
                H => initial *= rank,
                S => initial -= rank,
                C => if rank != 0 {
                        initial /= rank;
                     } else {
                        self.exception("division by zero");
                     },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial;
        self
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("99bottles.ante".as_slice()).run();
}
<commit_msg>Converted to use BigInt<commit_after>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;
use std::num::Zero;
use std::num::from_int;
use std::char::from_u32;
use regex::Regex;
use num::bigint::BigInt;

const A: uint = 'A' as uint;
const J: uint = 'J' as uint;
const Q: uint = 'Q' as uint;
const K: uint = 'K' as uint;
const D: uint = '♦' as uint;
const H: uint = '♥' as uint;
const S: uint = '♠' as uint;
const C: uint = '♣' as uint;

struct Card {
    rank: uint,
    suit: uint
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<uint, BigInt>,  // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars: HashMap<uint, BigInt> = HashMap::new();
        vars.insert(D, Ante::big(0));
        vars.insert(H, Ante::big(0));
        vars.insert(S, Ante::big(0));
        vars.insert(C, Ante::big(0));

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0u  => self.newline(card),
                K   => self.jump(card),
                Q   => continue,
                J   => self.dump(card, true),
                10u => self.dump(card, false),
                _   => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i + 1 });

            // Parse cards using regural expression.
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as uint },
                   '2'...'9' => Card { rank: rank as uint - 48, suit: suit as uint },
                   _         => Card { rank: rank as uint, suit: suit as uint }
                };
                code.push(card);
            }
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        self.line = card.suit as uint;
        self
    }

    fn jump(&mut self, card: Card) -> &Ante {
        let mut suit = card.suit as uint;
        while self.pc < self.code.len() && self.code[self.pc].rank == K && self.code[self.pc].suit == card.suit {
            suit += card.suit as uint;
            self.pc += 1;
        }

        if !self.vars[card.suit].is_zero() {
            let label: uint = suit as uint;
            if self.labels.contains_key(&label) {
                self.pc = self.labels[label];
            } else {
                self.exception("can't find the label...");
            }
        }
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        let value = self.vars[card.suit].clone();
        if as_character {
            if value < Ante::big(0) || value > Ante::big(255) {
                self.exception(format!("character code {} is out of 0..255 range", value).as_slice());
            } else {
                print!("{:1c}", from_u32(value.to_u32().unwrap()).unwrap());
            }
        } else {
            print!("{}", value);
        }
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial: BigInt = Ante::big(operands[0].rank as int);
        let target = operands[0].suit;

        if initial.to_uint().unwrap() == A {
            initial = self.vars[target].clone();
        }

        for i in range(1, operands.len()) {
            let mut rank = Ante::big(operands[i].rank as int);
            let suit = operands[i].suit;

            if rank.to_uint().unwrap() == A {
                rank = self.vars[suit].clone();
            }

            match suit {
                D => { initial = initial.add(&rank) },
                H => { initial = initial.mul(&rank) },
                S => { initial = initial.sub(&rank) },
                C => if !rank.is_zero() {
                        initial = initial.div(&rank);
                     } else {
                        self.exception("division by zero");
                     },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial;
        self
    }

    fn big(n: int) -> BigInt {
        from_int::<BigInt>(n).unwrap()
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("fizzbuzz.ante".as_slice()).run();
}
<|endoftext|>


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

//!
//! # RangeDfa
//!
//! A DFA that matches transitions against symbol ranges.
//!

use super::dfa_builder::*;
use super::pattern_matcher::*;
use super::symbol_range::*;
use super::state_machine::*;

///
/// DFA that decides on transitions based on non-overlapping, sorted lists of input symbols
///
pub struct SymbolRangeDfa<InputSymbol: PartialOrd, OutputSymbol> {
    //
    // Indexes of where each state starts in the transition table (it ends at the start of the next state)
    //
    states: Vec<usize>,

    //
    // The transitions making up this DFA
    //
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,

    //
    // The accepting symbol for each state
    //
    accept: Vec<Option<OutputSymbol>>
}

///
/// DFA builder that creates RangeDfas
///
pub struct SymbolRangeDfaBuilder<InputSymbol: PartialOrd, OutputSymbol> {
    states: Vec<usize>,
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,
    accept: Vec<Option<OutputSymbol>>
}

impl<InputSymbol: PartialOrd, OutputSymbol> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    pub fn new() -> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
        SymbolRangeDfaBuilder { states: vec![], transitions: vec![], accept: vec![] }
    }
}

impl<InputSymbol: PartialOrd, OutputSymbol> DfaBuilder<SymbolRange<InputSymbol>, OutputSymbol, SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    fn start_state(&mut self) {
        // Begin the next state
        self.states.push(self.transitions.len());
        self.accept.push(None);
    }

    fn transition(&mut self, symbol: SymbolRange<InputSymbol>, target_state: StateId) {
        self.transitions.push((symbol, target_state));
    }

    fn accept(&mut self, symbol: OutputSymbol) {
        self.accept.pop();
        self.accept.push(Some(symbol));
    }

    fn build(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        // Turn into a RangeDfa
        let mut result = SymbolRangeDfa { states: self.states, transitions: self.transitions, accept: self.accept };

        // 'Cap' the last state so we don't need to special-case it later
        // ie, we can always find the index of the last symbol by looking at the next state and don't need to handle the final state differently
        result.states.push(result.transitions.len());

        result
    }
}

///
/// A state of a symbol range state machine
///
pub struct SymbolRangeState<'a, InputSymbol: PartialOrd+'a, OutputSymbol: Sized+'a> {
    // The current state of the state machine
    state: StateId,

    // The number of symbols that have been processed so far
    count: usize,

    // If something other than none, the most recent accepting state
    accept: Option<(usize, &'a OutputSymbol)>,

    // The state machine this is running
    state_machine: &'a SymbolRangeDfa<InputSymbol, OutputSymbol>
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: Sized+'a> PatternMatcher<'a, InputSymbol, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    type State = SymbolRangeState<'a, InputSymbol, OutputSymbol>;

    fn start(&'a self) -> Self::State {
        // TODO: if state 0 is accepting, then this will erroneously not move straight to the accepting state
        SymbolRangeState { state: 0, count: 0, accept: None, state_machine: self }
    }
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: Sized+'a> MatchingState<'a, InputSymbol, OutputSymbol> for SymbolRangeState<'a, InputSymbol, OutputSymbol> {
    fn next(self, symbol: InputSymbol) -> MatchAction<'a, OutputSymbol, Self> {
        // The transition range is defined by the current state
        let start_transition    = self.state_machine.states[self.state as usize];
        let end_transition      = self.state_machine.states[self.state as usize+1];

        // See if there is an input symbol matching this transition
        // TODO: consider binary searching for states with large numbers of transitions? (Do these occur regularly in patterns that people use?)
        for transit in start_transition..end_transition {
            // Test this transition
            let (ref range, new_state) = self.state_machine.transitions[transit];

            if range.includes(&symbol) {
                // Found a transition to a new state: result will be `More(new state)`
                let new_count = self.count+1;

                // If the new state is an accepting state, then remember it in case we reach a rejecting state later
                let new_accept = if let Some(ref output) = self.state_machine.accept[new_state as usize] {
                    Some((new_count, output))
                } else {
                    self.accept
                };

                // Action is 'More'
                // TODO: might be an option to return Accept or Reject here if the new state has no transitions
                // (Possible performance advantage, but depends on the regex and input conditions)
                return More(SymbolRangeState { state: new_state, count: new_count, accept: new_accept, state_machine: self.state_machine });
            }
        }

        // No matches: finish the state machine
        self.finish()
    }

    fn finish(self) -> MatchAction<'a, OutputSymbol, Self> {
        if let Some(accept_state) = self.accept {
            // We found an accepting state earlier on, so return that
            let (length, symbol) = accept_state;
            Accept(length, symbol)
        } else {
            // No accepting state was found while this state machine was running
            Reject
        }
    }
}

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

    #[test]
    fn can_accept_single_symbol() {
        let mut builder: SymbolRangeDfaBuilder<i32, i32> = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept(3);

        // Create the state machine
        let state_machine = builder.build();

        // Run the first state
        let start_state = state_machine.start();
        let mut action  = start_state.next(0);

        if let More(next_state) = action {
            action = next_state.next(0);

            // Should have reached an accepting state (read one character)
            if let Accept(count, symbol) = action {
                // One symbol accepted
                assert!(count == 1);

                // Output symbol correct
                assert!(symbol == &3);
            } else {
                // Should have accepted here (the second '0' is rejected)
                assert!(false);
            }
        } else {
            // State machine did not accept the character
            assert!(false);
        }
    }
}
<commit_msg>Output symbol doesn’t need to be sized, we can use a string as the output<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # RangeDfa
//!
//! A DFA that matches transitions against symbol ranges.
//!

use super::dfa_builder::*;
use super::pattern_matcher::*;
use super::symbol_range::*;
use super::state_machine::*;

///
/// DFA that decides on transitions based on non-overlapping, sorted lists of input symbols
///
pub struct SymbolRangeDfa<InputSymbol: PartialOrd, OutputSymbol> {
    //
    // Indexes of where each state starts in the transition table (it ends at the start of the next state)
    //
    states: Vec<usize>,

    //
    // The transitions making up this DFA
    //
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,

    //
    // The accepting symbol for each state
    //
    accept: Vec<Option<OutputSymbol>>
}

///
/// DFA builder that creates RangeDfas
///
pub struct SymbolRangeDfaBuilder<InputSymbol: PartialOrd, OutputSymbol> {
    states: Vec<usize>,
    transitions: Vec<(SymbolRange<InputSymbol>, StateId)>,
    accept: Vec<Option<OutputSymbol>>
}

impl<InputSymbol: PartialOrd, OutputSymbol> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    pub fn new() -> SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
        SymbolRangeDfaBuilder { states: vec![], transitions: vec![], accept: vec![] }
    }
}

impl<InputSymbol: PartialOrd, OutputSymbol> DfaBuilder<SymbolRange<InputSymbol>, OutputSymbol, SymbolRangeDfa<InputSymbol, OutputSymbol>> for SymbolRangeDfaBuilder<InputSymbol, OutputSymbol> {
    fn start_state(&mut self) {
        // Begin the next state
        self.states.push(self.transitions.len());
        self.accept.push(None);
    }

    fn transition(&mut self, symbol: SymbolRange<InputSymbol>, target_state: StateId) {
        self.transitions.push((symbol, target_state));
    }

    fn accept(&mut self, symbol: OutputSymbol) {
        self.accept.pop();
        self.accept.push(Some(symbol));
    }

    fn build(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        // Turn into a RangeDfa
        let mut result = SymbolRangeDfa { states: self.states, transitions: self.transitions, accept: self.accept };

        // 'Cap' the last state so we don't need to special-case it later
        // ie, we can always find the index of the last symbol by looking at the next state and don't need to handle the final state differently
        result.states.push(result.transitions.len());

        result
    }
}

///
/// A state of a symbol range state machine
///
pub struct SymbolRangeState<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> {
    // The current state of the state machine
    state: StateId,

    // The number of symbols that have been processed so far
    count: usize,

    // If something other than none, the most recent accepting state
    accept: Option<(usize, &'a OutputSymbol)>,

    // The state machine this is running
    state_machine: &'a SymbolRangeDfa<InputSymbol, OutputSymbol>
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> PatternMatcher<'a, InputSymbol, OutputSymbol> for SymbolRangeDfa<InputSymbol, OutputSymbol> {
    type State = SymbolRangeState<'a, InputSymbol, OutputSymbol>;

    fn start(&'a self) -> Self::State {
        // TODO: if state 0 is accepting, then this will erroneously not move straight to the accepting state
        SymbolRangeState { state: 0, count: 0, accept: None, state_machine: self }
    }
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a> MatchingState<'a, InputSymbol, OutputSymbol> for SymbolRangeState<'a, InputSymbol, OutputSymbol> {
    fn next(self, symbol: InputSymbol) -> MatchAction<'a, OutputSymbol, Self> {
        // The transition range is defined by the current state
        let start_transition    = self.state_machine.states[self.state as usize];
        let end_transition      = self.state_machine.states[self.state as usize+1];

        // See if there is an input symbol matching this transition
        // TODO: consider binary searching for states with large numbers of transitions? (Do these occur regularly in patterns that people use?)
        for transit in start_transition..end_transition {
            // Test this transition
            let (ref range, new_state) = self.state_machine.transitions[transit];

            if range.includes(&symbol) {
                // Found a transition to a new state: result will be `More(new state)`
                let new_count = self.count+1;

                // If the new state is an accepting state, then remember it in case we reach a rejecting state later
                let new_accept = if let Some(ref output) = self.state_machine.accept[new_state as usize] {
                    Some((new_count, output))
                } else {
                    self.accept
                };

                // Action is 'More'
                // TODO: might be an option to return Accept or Reject here if the new state has no transitions
                // (Possible performance advantage, but depends on the regex and input conditions)
                return More(SymbolRangeState { state: new_state, count: new_count, accept: new_accept, state_machine: self.state_machine });
            }
        }

        // No matches: finish the state machine
        self.finish()
    }

    fn finish(self) -> MatchAction<'a, OutputSymbol, Self> {
        if let Some(accept_state) = self.accept {
            // We found an accepting state earlier on, so return that
            let (length, symbol) = accept_state;
            Accept(length, symbol)
        } else {
            // No accepting state was found while this state machine was running
            Reject
        }
    }
}

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

    #[test]
    fn can_accept_single_symbol() {
        let mut builder = SymbolRangeDfaBuilder::new();

        // State 0: '0', move to state 1
        builder.start_state();
        builder.transition(SymbolRange::new(0, 0), 1);

        // State 1: accept, output symbol "Success"
        builder.start_state();
        builder.accept("Success");

        // Create the state machine
        let state_machine = builder.build();

        // Run the first state
        let start_state = state_machine.start();
        let mut action  = start_state.next(0);

        if let More(next_state) = action {
            action = next_state.next(0);

            // Should have reached an accepting state (read one character)
            if let Accept(count, symbol) = action {
                // One symbol accepted
                assert!(count == 1);

                // Output symbol correct
                assert!(symbol == &"Success");
            } else {
                // Should have accepted here (the second '0' is rejected)
                assert!(false);
            }
        } else {
            // State machine did not accept the character
            assert!(false);
        }
    }
}
<|endoftext|>