<commit_before>/*
 * Copyright (c) 2020 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 gtk::{
    ButtonExt,
    FrameExt,
    GtkMenuItemExt,
    Inhibit,
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::{Horizontal, Vertical};
use relm::Widget;
use relm_derive::{Msg, widget};

use self::Msg::*;
use self::CounterMsg::SetIncrement;

pub struct CounterModel {
    counter: i32,
}

#[derive(Msg)]
pub enum CounterMsg {
    Decrement,
    Increment,
    SetIncrement(i32),
}

#[widget]
impl Widget for Counter {
    fn model() -> CounterModel {
        CounterModel {
            counter: 0,
        }
    }

    fn update(&mut self, event: CounterMsg) {
        match event {
            CounterMsg::Decrement => self.model.counter -= 1,
            CounterMsg::Increment => self.model.counter += 1,
            SetIncrement(value) => self.model.counter = value,
        }
    }

    view! {
        gtk::Box {
            orientation: Vertical,
            gtk::Button {
                label: "+",
                widget_name: "inc_button",
                clicked => CounterMsg::Increment,
            },
            gtk::Label {
                widget_name: "label",
                text: &self.model.counter.to_string(),
            },
            gtk::Button {
                label: "-",
                clicked => CounterMsg::Decrement,
            },
        }
    }
}

#[widget]
impl Widget for HBox {
    fn model() -> () {
        ()
    }

    fn update(&mut self, _event: ()) {
    }

    view! {
        #[container]
        gtk::Box {
            orientation: Horizontal,
        }
    }
}

pub struct Model {
    counter: i32,
}

#[derive(Msg)]
pub enum Msg {
    Click(f64, f64),
    Decrement,
    End,
    Increment,
    Move(f64, f64),
    Quit,
}

#[widget]
impl Widget for Win {
    fn model() -> Model {
        Model {
            counter: 0,
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Click(x, y) => println!("Clicked on {}, {}", x, y),
            Decrement => self.model.counter -= 1,
            End => println!("End"),
            Increment => self.model.counter += 1,
            Move(x, y) => println!("Moved to {}, {}", x, y),
            Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                orientation: Vertical,
                gtk::MenuBar {
                    #[name="file_menu"]
                    gtk::MenuItem {
                        label: "File",
                        submenu: view! {
                            gtk::Menu {
                                #[name="increment_menu"]
                                gtk::MenuItem {
                                    label: "Increment",
                                    // TODO: test nested view with a relm widget.
                                    submenu: view! {
                                        gtk::Menu {
                                            #[name="inc_menu"]
                                            gtk::MenuItem {
                                                label: &("By one ".to_string() + &self.model.counter.to_string()),
                                                activate => Increment,
                                            },
                                            #[name="dec_menu"]
                                            gtk::MenuItem {
                                                label: &("By minus one ".to_string() + &self.model.counter.to_string()),
                                                activate => Decrement,
                                            },
                                        }
                                    },
                                },
                                gtk::MenuItem {
                                    label: "Quit",
                                    activate => Quit,
                                },
                            },
                        },
                    },
                },
                #[name="inc_button"]
                gtk::Button {
                    clicked => Increment,
                    label: "+",
                },
                #[name="label"]
                gtk::Label {
                    text: &self.model.counter.to_string(),
                },
                gtk::Frame {
                    label_widget: view! {
                        HBox {
                            gtk::Frame {
                                label_widget: view! {
                                    #[name="counter"]
                                    Counter {
                                        SetIncrement: self.model.counter,
                                    },
                                }
                            }
                        }
                    },
                    #[name="dec_button"]
                    gtk::Button {
                        clicked => Decrement,
                        label: "-",
                    },
                },
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).expect("Win::run failed");
}

#[cfg(test)]
mod tests {
    use gtk::{Button, ButtonExt, GtkMenuItemExt, Label, LabelExt};

    use gtk_test::{assert_label, assert_text, find_child_by_name};
    use relm_test::{click, mouse_move_to};

    use crate::Win;

    #[test]
    fn label_change() {
        let (_component, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
        let inc_button = &widgets.inc_button;
        let dec_button = &widgets.dec_button;
        let label = &widgets.label;
        let inc_menu = &widgets.inc_menu;
        let dec_menu = &widgets.dec_menu;
        let increment_menu = &widgets.increment_menu;
        let file_menu = &widgets.file_menu;

        let counter = &widgets.counter;
        let counter_inc_button: Button = find_child_by_name(counter.widget(), "inc_button").expect("button");
        let counter_label: Label = find_child_by_name(counter.widget(), "label").expect("label");

        assert_label!(inc_button, "+");
        assert_label!(dec_button, "-");

        let menu_click = || {
            click(file_menu);
            mouse_move_to(increment_menu);
            click(inc_menu);
        };

        assert_text!(label, 0);
        assert_text!(counter_label, 0);
        assert_label!(inc_menu, "By one 0");
        assert_label!(dec_menu, "By minus one 0");
        click(inc_button);
        assert_text!(label, 1);
        assert_text!(counter_label, 1);
        assert_label!(inc_menu, "By one 1");
        assert_label!(dec_menu, "By minus one 1");
        menu_click();
        assert_text!(label, 2);
        assert_text!(counter_label, 2);
        assert_label!(inc_menu, "By one 2");
        assert_label!(dec_menu, "By minus one 2");
        click(inc_button);
        assert_text!(label, 3);
        assert_text!(counter_label, 3);
        assert_label!(inc_menu, "By one 3");
        assert_label!(dec_menu, "By minus one 3");

        click(&counter_inc_button);
        assert_text!(label, 3);
        assert_text!(counter_label, 4);
        assert_label!(inc_menu, "By one 3");
        assert_label!(dec_menu, "By minus one 3");

        menu_click();
        assert_text!(label, 4);
        assert_text!(counter_label, 4);
        assert_label!(inc_menu, "By one 4");
        assert_label!(dec_menu, "By minus one 4");

        let menu_click = || {
            click(file_menu);
            mouse_move_to(increment_menu);
            click(dec_menu);
        };

        menu_click();
        assert_text!(label, 3);
        assert_text!(counter_label, 3);
        assert_label!(inc_menu, "By one 3");
        assert_label!(dec_menu, "By minus one 3");
        menu_click();
        assert_text!(label, 2);
        assert_text!(counter_label, 2);
        assert_label!(inc_menu, "By one 2");
        assert_label!(dec_menu, "By minus one 2");
        menu_click();
        assert_text!(label, 1);
        assert_text!(counter_label, 1);
        assert_label!(inc_menu, "By one 1");
        assert_label!(dec_menu, "By minus one 1");
        menu_click();
        assert_text!(label, 0);
        assert_text!(counter_label, 0);
        assert_label!(inc_menu, "By one 0");
        assert_label!(dec_menu, "By minus one 0");
        menu_click();
        assert_text!(label, -1);
        assert_text!(counter_label, -1);
        assert_label!(inc_menu, "By one -1");
        assert_label!(dec_menu, "By minus one -1");
    }
}
<commit_msg>Remove comment<commit_after>/*
 * Copyright (c) 2020 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 gtk::{
    ButtonExt,
    FrameExt,
    GtkMenuItemExt,
    Inhibit,
    LabelExt,
    OrientableExt,
    WidgetExt,
};
use gtk::Orientation::{Horizontal, Vertical};
use relm::Widget;
use relm_derive::{Msg, widget};

use self::Msg::*;
use self::CounterMsg::SetIncrement;

pub struct CounterModel {
    counter: i32,
}

#[derive(Msg)]
pub enum CounterMsg {
    Decrement,
    Increment,
    SetIncrement(i32),
}

#[widget]
impl Widget for Counter {
    fn model() -> CounterModel {
        CounterModel {
            counter: 0,
        }
    }

    fn update(&mut self, event: CounterMsg) {
        match event {
            CounterMsg::Decrement => self.model.counter -= 1,
            CounterMsg::Increment => self.model.counter += 1,
            SetIncrement(value) => self.model.counter = value,
        }
    }

    view! {
        gtk::Box {
            orientation: Vertical,
            gtk::Button {
                label: "+",
                widget_name: "inc_button",
                clicked => CounterMsg::Increment,
            },
            gtk::Label {
                widget_name: "label",
                text: &self.model.counter.to_string(),
            },
            gtk::Button {
                label: "-",
                clicked => CounterMsg::Decrement,
            },
        }
    }
}

#[widget]
impl Widget for HBox {
    fn model() -> () {
        ()
    }

    fn update(&mut self, _event: ()) {
    }

    view! {
        #[container]
        gtk::Box {
            orientation: Horizontal,
        }
    }
}

pub struct Model {
    counter: i32,
}

#[derive(Msg)]
pub enum Msg {
    Click(f64, f64),
    Decrement,
    End,
    Increment,
    Move(f64, f64),
    Quit,
}

#[widget]
impl Widget for Win {
    fn model() -> Model {
        Model {
            counter: 0,
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            Click(x, y) => println!("Clicked on {}, {}", x, y),
            Decrement => self.model.counter -= 1,
            End => println!("End"),
            Increment => self.model.counter += 1,
            Move(x, y) => println!("Moved to {}, {}", x, y),
            Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                orientation: Vertical,
                gtk::MenuBar {
                    #[name="file_menu"]
                    gtk::MenuItem {
                        label: "File",
                        submenu: view! {
                            gtk::Menu {
                                #[name="increment_menu"]
                                gtk::MenuItem {
                                    label: "Increment",
                                    submenu: view! {
                                        gtk::Menu {
                                            #[name="inc_menu"]
                                            gtk::MenuItem {
                                                label: &("By one ".to_string() + &self.model.counter.to_string()),
                                                activate => Increment,
                                            },
                                            #[name="dec_menu"]
                                            gtk::MenuItem {
                                                label: &("By minus one ".to_string() + &self.model.counter.to_string()),
                                                activate => Decrement,
                                            },
                                        }
                                    },
                                },
                                gtk::MenuItem {
                                    label: "Quit",
                                    activate => Quit,
                                },
                            },
                        },
                    },
                },
                #[name="inc_button"]
                gtk::Button {
                    clicked => Increment,
                    label: "+",
                },
                #[name="label"]
                gtk::Label {
                    text: &self.model.counter.to_string(),
                },
                gtk::Frame {
                    label_widget: view! {
                        HBox {
                            gtk::Frame {
                                label_widget: view! {
                                    #[name="counter"]
                                    Counter {
                                        SetIncrement: self.model.counter,
                                    },
                                }
                            }
                        }
                    },
                    #[name="dec_button"]
                    gtk::Button {
                        clicked => Decrement,
                        label: "-",
                    },
                },
            },
            delete_event(_, _) => (Quit, Inhibit(false)),
        }
    }
}

fn main() {
    Win::run(()).expect("Win::run failed");
}

#[cfg(test)]
mod tests {
    use gtk::{Button, ButtonExt, GtkMenuItemExt, Label, LabelExt};

    use gtk_test::{assert_label, assert_text, find_child_by_name};
    use relm_test::{click, mouse_move_to};

    use crate::Win;

    #[test]
    fn label_change() {
        let (_component, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
        let inc_button = &widgets.inc_button;
        let dec_button = &widgets.dec_button;
        let label = &widgets.label;
        let inc_menu = &widgets.inc_menu;
        let dec_menu = &widgets.dec_menu;
        let increment_menu = &widgets.increment_menu;
        let file_menu = &widgets.file_menu;

        let counter = &widgets.counter;
        let counter_inc_button: Button = find_child_by_name(counter.widget(), "inc_button").expect("button");
        let counter_label: Label = find_child_by_name(counter.widget(), "label").expect("label");

        assert_label!(inc_button, "+");
        assert_label!(dec_button, "-");

        let menu_click = || {
            click(file_menu);
            mouse_move_to(increment_menu);
            click(inc_menu);
        };

        assert_text!(label, 0);
        assert_text!(counter_label, 0);
        assert_label!(inc_menu, "By one 0");
        assert_label!(dec_menu, "By minus one 0");
        click(inc_button);
        assert_text!(label, 1);
        assert_text!(counter_label, 1);
        assert_label!(inc_menu, "By one 1");
        assert_label!(dec_menu, "By minus one 1");
        menu_click();
        assert_text!(label, 2);
        assert_text!(counter_label, 2);
        assert_label!(inc_menu, "By one 2");
        assert_label!(dec_menu, "By minus one 2");
        click(inc_button);
        assert_text!(label, 3);
        assert_text!(counter_label, 3);
        assert_label!(inc_menu, "By one 3");
        assert_label!(dec_menu, "By minus one 3");

        click(&counter_inc_button);
        assert_text!(label, 3);
        assert_text!(counter_label, 4);
        assert_label!(inc_menu, "By one 3");
        assert_label!(dec_menu, "By minus one 3");

        menu_click();
        assert_text!(label, 4);
        assert_text!(counter_label, 4);
        assert_label!(inc_menu, "By one 4");
        assert_label!(dec_menu, "By minus one 4");

        let menu_click = || {
            click(file_menu);
            mouse_move_to(increment_menu);
            click(dec_menu);
        };

        menu_click();
        assert_text!(label, 3);
        assert_text!(counter_label, 3);
        assert_label!(inc_menu, "By one 3");
        assert_label!(dec_menu, "By minus one 3");
        menu_click();
        assert_text!(label, 2);
        assert_text!(counter_label, 2);
        assert_label!(inc_menu, "By one 2");
        assert_label!(dec_menu, "By minus one 2");
        menu_click();
        assert_text!(label, 1);
        assert_text!(counter_label, 1);
        assert_label!(inc_menu, "By one 1");
        assert_label!(dec_menu, "By minus one 1");
        menu_click();
        assert_text!(label, 0);
        assert_text!(counter_label, 0);
        assert_label!(inc_menu, "By one 0");
        assert_label!(dec_menu, "By minus one 0");
        menu_click();
        assert_text!(label, -1);
        assert_text!(counter_label, -1);
        assert_label!(inc_menu, "By one -1");
        assert_label!(dec_menu, "By minus one -1");
    }
}
<|endoftext|>


<commit_before>// Lints
#![forbid(private_in_public)]
#![forbid(bare_trait_objects)]
#![deny(unused_must_use)]
#![deny(unused_assignments)]
#![deny(clippy::missing_safety_doc)]
#![allow(clippy::empty_loop)]
// no_std
#![no_std]
// Unstable features
#![feature(asm)]
#![feature(allocator_api)]
#![feature(const_fn)]
#![feature(integer_atomics)]
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]

mod allocator;
pub mod syscall;

use core::alloc::Layout;
use core::panic::PanicInfo;

#[macro_use]
extern crate alloc;

extern "Rust" {
    fn main() -> u64;
}

#[no_mangle]
pub extern "C" fn _start() {
    let return_code = unsafe { main() };
    self::syscall::exit(return_code);
}

#[panic_handler]
#[no_mangle]
extern "C" fn panic(info: &PanicInfo) -> ! {
    use self::syscall::debug_print;
    unsafe {
        if let Some(location) = info.location() {
            let _ = debug_print(&format!(
                "Error: file '{}', line {}",
                location.file(),
                location.line()
            ));
        } else {
            let _ = debug_print("Error: (location unavailable)");
        }

        if let Some(msg) = info.message() {
            let _ = debug_print(&format!("  {:?}", msg));
        } else {
            let _ = debug_print("  Info unavailable");
        }

        asm!("cli"::::"intel","volatile");
        asm!("hlt"::::"intel","volatile");
    }
    loop {}
}

#[global_allocator]
static HEAP_ALLOCATOR: allocator::GlobAlloc =
    allocator::GlobAlloc::new(allocator::BlockAllocator::new());

#[alloc_error_handler]
fn out_of_memory(_: Layout) -> ! {
    unsafe {
        asm!("cli"::::"intel","volatile");
        asm!("hlt"::::"intel","volatile");
    }
    loop {}
}
<commit_msg>Exit process when they panic<commit_after>// Lints
#![forbid(private_in_public)]
#![forbid(bare_trait_objects)]
#![deny(unused_must_use)]
#![deny(unused_assignments)]
#![deny(clippy::missing_safety_doc)]
#![allow(clippy::empty_loop)]
// no_std
#![no_std]
// Unstable features
#![feature(asm)]
#![feature(allocator_api)]
#![feature(const_fn)]
#![feature(integer_atomics)]
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]

mod allocator;
pub mod syscall;

use core::alloc::Layout;
use core::panic::PanicInfo;

#[macro_use]
extern crate alloc;

extern "Rust" {
    fn main() -> u64;
}

#[no_mangle]
pub extern "C" fn _start() {
    let return_code = unsafe { main() };
    self::syscall::exit(return_code);
}

#[panic_handler]
#[no_mangle]
extern "C" fn panic(info: &PanicInfo) -> ! {
    use self::syscall::debug_print;
    if let Some(location) = info.location() {
        let _ = debug_print(&format!(
            "Error: file '{}', line {}",
            location.file(),
            location.line()
        ));
    } else {
        let _ = debug_print("Error: (location unavailable)");
    }

    if let Some(msg) = info.message() {
        let _ = debug_print(&format!("  {:?}", msg));
    } else {
        let _ = debug_print("  Info unavailable");
    }

    syscall::exit(1)
}

#[global_allocator]
static HEAP_ALLOCATOR: allocator::GlobAlloc =
    allocator::GlobAlloc::new(allocator::BlockAllocator::new());

#[alloc_error_handler]
fn out_of_memory(_: Layout) -> ! {
    unsafe {
        asm!("xchg bx, bx"::::"intel","volatile");
        asm!("cli"::::"intel","volatile");
        asm!("hlt"::::"intel","volatile");
    }
    loop {}
}
<|endoftext|>


<commit_before>use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
    iter: I,
    /// Remember a peeked value, even if it was None.
    peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
        Peekable { iter, peeked: None }
    }
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        match self.peeked.take() {
            Some(v) => v,
            None => self.iter.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(mut self) -> usize {
        match self.peeked.take() {
            Some(None) => 0,
            Some(Some(_)) => 1 + self.iter.count(),
            None => self.iter.count(),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        match self.peeked.take() {
            Some(None) => None,
            Some(v @ Some(_)) if n == 0 => v,
            Some(Some(_)) => self.iter.nth(n - 1),
            None => self.iter.nth(n),
        }
    }

    #[inline]
    fn last(mut self) -> Option<I::Item> {
        let peek_opt = match self.peeked.take() {
            Some(None) => return None,
            Some(v) => v,
            None => None,
        };
        self.iter.last().or(peek_opt)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = match self.peeked {
            Some(None) => return (0, Some(0)),
            Some(Some(_)) => 1,
            None => 0,
        };
        let (lo, hi) = self.iter.size_hint();
        let lo = lo.saturating_add(peek_len);
        let hi = match hi {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lo, hi)
    }

    #[inline]
    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let acc = match self.peeked.take() {
            Some(None) => return try { init },
            Some(Some(v)) => f(init, v)?,
            None => init,
        };
        self.iter.try_fold(acc, f)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        let acc = match self.peeked {
            Some(None) => return init,
            Some(Some(v)) => fold(init, v),
            None => init,
        };
        self.iter.fold(acc, fold)
    }
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        match self.peeked.as_mut() {
            Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
            Some(None) => None,
            None => self.iter.next_back(),
        }
    }

    #[inline]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        match self.peeked.take() {
            Some(None) => try { init },
            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                Ok(acc) => f(acc, v),
                Err(e) => {
                    self.peeked = Some(Some(v));
                    Try::from_error(e)
                }
            },
            None => self.iter.try_rfold(init, f),
        }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        match self.peeked {
            Some(None) => init,
            Some(Some(v)) => {
                let acc = self.iter.rfold(init, &mut fold);
                fold(acc, v)
            }
            None => self.iter.rfold(init, fold),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
    /// Returns a reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// [`next`]: Iterator::next
    ///
    /// Because `peek()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the
    /// examples below.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let xs = [1, 2, 3];
    ///
    /// let mut iter = xs.iter().peekable();
    ///
    /// // peek() lets us see into the future
    /// assert_eq!(iter.peek(), Some(&&1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// assert_eq!(iter.next(), Some(&2));
    ///
    /// // The iterator does not advance even if we `peek` multiple times
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.peek(), Some(&&3));
    ///
    /// assert_eq!(iter.next(), Some(&3));
    ///
    /// // After the iterator is finished, so is `peek()`
    /// assert_eq!(iter.peek(), None);
    /// assert_eq!(iter.next(), None);
    /// ```
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn peek(&mut self) -> Option<&I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_ref()
    }

    /// Returns a mutable reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// Because `peek_mut()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the examples
    /// below.
    ///
    /// [`next`]: Iterator::next
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// #![feature(peekable_peek_mut)]
    /// let mut iter = [1, 2, 3].iter().peekable();
    ///
    /// // Like with `peek()`, we can see into the future without advancing the iterator.
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// // Peek into the iterator and set the value behind the mutable reference.
    /// if let Some(p) = iter.peek_mut() {
    ///     assert_eq!(*p, &2);
    ///     *p = &5;
    /// }
    ///
    /// // The value we put in reappears as the iterator continues.
    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
    /// ```
    #[inline]
    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
    pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_mut()
    }

    /// Consume and return the next value of this iterator if a condition is true.
    ///
    /// If `func` returns `true` for the next value of this iterator, consume and return it.
    /// Otherwise, return `None`.
    ///
    /// # Examples
    /// Consume a number if it's equal to 0.
    /// ```
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if(|&x| x == 0), None);
    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    ///
    /// Consume any number less than 10.
    /// ```
    /// let mut iter = (1..20).peekable();
    /// // Consume all numbers less than 10
    /// while iter.next_if(|&x| x < 10).is_some() {}
    /// // The next value returned will be 10
    /// assert_eq!(iter.next(), Some(10));
    /// ```
    #[stable(feature = "peekable_next_if", since = "1.49.0")]
    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
        match self.next() {
            Some(matched) if func(&matched) => Some(matched),
            other => {
                // Since we called `self.next()`, we consumed `self.peeked`.
                assert!(self.peeked.is_none());
                self.peeked = Some(other);
                None
            }
        }
    }

    /// Consume and return the next item if it is equal to `expected`.
    ///
    /// # Example
    /// Consume a number if it's equal to 0.
    /// ```
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if_eq(&0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if_eq(&0), None);
    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    #[stable(feature = "peekable_next_if", since = "1.49.0")]
    pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
    where
        T: ?Sized,
        I::Item: PartialEq<T>,
    {
        self.next_if(|next| next == expected)
    }
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
    I: SourceIter<Source = S>,
{
    type Source = S;

    #[inline]
    unsafe fn as_inner(&mut self) -> &mut S {
        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
        unsafe { SourceIter::as_inner(&mut self.iter) }
    }
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
<commit_msg>bump rust version for peekable_next_if feature<commit_after>use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
use crate::ops::Try;

/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`peekable`]: Iterator::peekable
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
    iter: I,
    /// Remember a peeked value, even if it was None.
    peeked: Option<Option<I::Item>>,
}

impl<I: Iterator> Peekable<I> {
    pub(in crate::iter) fn new(iter: I) -> Peekable<I> {
        Peekable { iter, peeked: None }
    }
}

// Peekable must remember if a None has been seen in the `.peek()` method.
// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
// underlying iterator at most once. This does not by itself make the iterator
// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
    type Item = I::Item;

    #[inline]
    fn next(&mut self) -> Option<I::Item> {
        match self.peeked.take() {
            Some(v) => v,
            None => self.iter.next(),
        }
    }

    #[inline]
    #[rustc_inherit_overflow_checks]
    fn count(mut self) -> usize {
        match self.peeked.take() {
            Some(None) => 0,
            Some(Some(_)) => 1 + self.iter.count(),
            None => self.iter.count(),
        }
    }

    #[inline]
    fn nth(&mut self, n: usize) -> Option<I::Item> {
        match self.peeked.take() {
            Some(None) => None,
            Some(v @ Some(_)) if n == 0 => v,
            Some(Some(_)) => self.iter.nth(n - 1),
            None => self.iter.nth(n),
        }
    }

    #[inline]
    fn last(mut self) -> Option<I::Item> {
        let peek_opt = match self.peeked.take() {
            Some(None) => return None,
            Some(v) => v,
            None => None,
        };
        self.iter.last().or(peek_opt)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = match self.peeked {
            Some(None) => return (0, Some(0)),
            Some(Some(_)) => 1,
            None => 0,
        };
        let (lo, hi) = self.iter.size_hint();
        let lo = lo.saturating_add(peek_len);
        let hi = match hi {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lo, hi)
    }

    #[inline]
    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let acc = match self.peeked.take() {
            Some(None) => return try { init },
            Some(Some(v)) => f(init, v)?,
            None => init,
        };
        self.iter.try_fold(acc, f)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        let acc = match self.peeked {
            Some(None) => return init,
            Some(Some(v)) => fold(init, v),
            None => init,
        };
        self.iter.fold(acc, fold)
    }
}

#[stable(feature = "double_ended_peek_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Peekable<I>
where
    I: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        match self.peeked.as_mut() {
            Some(v @ Some(_)) => self.iter.next_back().or_else(|| v.take()),
            Some(None) => None,
            None => self.iter.next_back(),
        }
    }

    #[inline]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        match self.peeked.take() {
            Some(None) => try { init },
            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                Ok(acc) => f(acc, v),
                Err(e) => {
                    self.peeked = Some(Some(v));
                    Try::from_error(e)
                }
            },
            None => self.iter.try_rfold(init, f),
        }
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        match self.peeked {
            Some(None) => init,
            Some(Some(v)) => {
                let acc = self.iter.rfold(init, &mut fold);
                fold(acc, v)
            }
            None => self.iter.rfold(init, fold),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}

#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator> FusedIterator for Peekable<I> {}

impl<I: Iterator> Peekable<I> {
    /// Returns a reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// [`next`]: Iterator::next
    ///
    /// Because `peek()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the
    /// examples below.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let xs = [1, 2, 3];
    ///
    /// let mut iter = xs.iter().peekable();
    ///
    /// // peek() lets us see into the future
    /// assert_eq!(iter.peek(), Some(&&1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// assert_eq!(iter.next(), Some(&2));
    ///
    /// // The iterator does not advance even if we `peek` multiple times
    /// assert_eq!(iter.peek(), Some(&&3));
    /// assert_eq!(iter.peek(), Some(&&3));
    ///
    /// assert_eq!(iter.next(), Some(&3));
    ///
    /// // After the iterator is finished, so is `peek()`
    /// assert_eq!(iter.peek(), None);
    /// assert_eq!(iter.next(), None);
    /// ```
    #[inline]
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn peek(&mut self) -> Option<&I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_ref()
    }

    /// Returns a mutable reference to the next() value without advancing the iterator.
    ///
    /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
    /// But if the iteration is over, `None` is returned.
    ///
    /// Because `peek_mut()` returns a reference, and many iterators iterate over
    /// references, there can be a possibly confusing situation where the
    /// return value is a double reference. You can see this effect in the examples
    /// below.
    ///
    /// [`next`]: Iterator::next
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// #![feature(peekable_peek_mut)]
    /// let mut iter = [1, 2, 3].iter().peekable();
    ///
    /// // Like with `peek()`, we can see into the future without advancing the iterator.
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.peek_mut(), Some(&mut &1));
    /// assert_eq!(iter.next(), Some(&1));
    ///
    /// // Peek into the iterator and set the value behind the mutable reference.
    /// if let Some(p) = iter.peek_mut() {
    ///     assert_eq!(*p, &2);
    ///     *p = &5;
    /// }
    ///
    /// // The value we put in reappears as the iterator continues.
    /// assert_eq!(iter.collect::<Vec<_>>(), vec![&5, &3]);
    /// ```
    #[inline]
    #[unstable(feature = "peekable_peek_mut", issue = "78302")]
    pub fn peek_mut(&mut self) -> Option<&mut I::Item> {
        let iter = &mut self.iter;
        self.peeked.get_or_insert_with(|| iter.next()).as_mut()
    }

    /// Consume and return the next value of this iterator if a condition is true.
    ///
    /// If `func` returns `true` for the next value of this iterator, consume and return it.
    /// Otherwise, return `None`.
    ///
    /// # Examples
    /// Consume a number if it's equal to 0.
    /// ```
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if(|&x| x == 0), None);
    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    ///
    /// Consume any number less than 10.
    /// ```
    /// let mut iter = (1..20).peekable();
    /// // Consume all numbers less than 10
    /// while iter.next_if(|&x| x < 10).is_some() {}
    /// // The next value returned will be 10
    /// assert_eq!(iter.next(), Some(10));
    /// ```
    #[stable(feature = "peekable_next_if", since = "1.50.0")]
    pub fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> {
        match self.next() {
            Some(matched) if func(&matched) => Some(matched),
            other => {
                // Since we called `self.next()`, we consumed `self.peeked`.
                assert!(self.peeked.is_none());
                self.peeked = Some(other);
                None
            }
        }
    }

    /// Consume and return the next item if it is equal to `expected`.
    ///
    /// # Example
    /// Consume a number if it's equal to 0.
    /// ```
    /// let mut iter = (0..5).peekable();
    /// // The first item of the iterator is 0; consume it.
    /// assert_eq!(iter.next_if_eq(&0), Some(0));
    /// // The next item returned is now 1, so `consume` will return `false`.
    /// assert_eq!(iter.next_if_eq(&0), None);
    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
    /// assert_eq!(iter.next(), Some(1));
    /// ```
    #[stable(feature = "peekable_next_if", since = "1.50.0")]
    pub fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item>
    where
        T: ?Sized,
        I::Item: PartialEq<T>,
    {
        self.next_if(|next| next == expected)
    }
}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Peekable<I> where I: TrustedLen {}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<S: Iterator, I: Iterator> SourceIter for Peekable<I>
where
    I: SourceIter<Source = S>,
{
    type Source = S;

    #[inline]
    unsafe fn as_inner(&mut self) -> &mut S {
        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
        unsafe { SourceIter::as_inner(&mut self.iter) }
    }
}

#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
<|endoftext|>


<commit_before>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "] }

        raw_text = { ( !["{{"] ~ any )+ }
        raw_block_text = { ( !["{{{{"] ~ any )+ }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = _{ string_literal | array_literal | object_literal }
        escape_literal = { (!["\""] ~ (["\\\""] | any))* }
        string_literal = { ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (literal? ~ [":"] ~ literal? ~ [","]?)* ~ ["}"] }

        symbol_and_path = { ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"] }

        identifier = @{ symbol_and_path+ }
        name = { subexpression | identifier }

        param = { literal | name }
        hash = { identifier ~ ["="] ~ param }
        exp_line = { whitespace_omitter? ~ name ~ (hash|param)* ~ whitespace_omitter? }

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        whitespace_omitter = { ["~"] }

        expression = { ["{{"] ~ exp_line ~ ["}}"] }
        html_expression = { ["{{{"] ~ exp_line ~ ["}}}"] }
        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{#"] ~ exp_line ~ ["}}"] }
        helper_block_end = { ["{{/"] ~ whitespace_omitter? ~ name ~ whitespace_omitter? ~ ["}}"] }
        helper_block = { helper_block_start ~ template ~ invert_tag? ~
                         template? ~ helper_block_end}
        raw_block_start = { ["{{{{#"] ~ exp_line ~ ["}}}}"] }
        raw_block_end = { ["{{{{/"] ~ whitespace_omitter? ~ name ~ whitespace_omitter? ~ ["}}}}"] }
        raw_block = { raw_block_start ~ raw_block_text ~ raw_block_end }

        comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = _{ (
            raw_text |
            expression |
            html_expression |
            helper_block |
            raw_block |
            comment)*
        }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>"));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"", "quot: \\\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.string_literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_escape_literal() {
    let mut rdp = Rdp::new(StringInput::new("nice\\\"anc"));
    assert!(rdp.escape_literal());
    assert!(rdp.end());
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.comment());
        assert!(rdp.end());
    }
}
<commit_msg>(feat) implemented almost all grammar of handlebars [#81]<commit_after>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )+ }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = _{ string_literal |
                     array_literal |
                     object_literal |
                     number_literal |
                     null_literal |
                     boolean_literal }

        null_literal = @{ ["null"] }
        boolean_literal = @{ ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = { ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ reference* }
        name = { subexpression | identifier }

        param = { literal | reference | subexpression }
        hash = @{ identifier ~ ["="] ~ param }
        exp_line = _{ name ~ (hash|param)* }

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        whitespace_omitter = { ["~"] }

        expression = { ["{{"] ~ whitespace_omitter? ~ exp_line ~
                                whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ whitespace_omitter? ~ exp_line ~
                                      whitespace_omitter? ~ ["}}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ whitespace_omitter? ~ ["/"] ~ name ~
                                      whitespace_omitter? ~ ["}}"] }
        helper_block = { helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                         helper_block_end }

        raw_block_start = { ["{{{{"] ~ whitespace_omitter? ~ ["#"] ~ exp_line ~
                                       whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ whitespace_omitter? ~ ["/"] ~ name ~
                                     whitespace_omitter? ~ ["}}}}"] }
        raw_block = { raw_block_start ~ raw_block_text ~ raw_block_end }

        comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_block |
            raw_block |
            comment )*
        }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}",
                 "{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}",
                 "{{{html 1}}}",
                 "{{{html \"literal\"}}}",
                 "{{{html ref}}}",
                 "{{{html (sub)}}}",
                 "{{{html (sub 123)}}}",
                 "{{{html []}}}",
                 "{{{html {}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{#if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{#if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}
<|endoftext|>


<commit_before>mod render;

use self::render::*;
use super::module::*;

use glutin::{self, Api, ContextBuilder, ControlFlow, EventsLoop, GlContext, GlRequest, Window,
             WindowBuilder, WindowEvent};
use modular_flow as mf;

use std::env;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use gfx;
use gfx::texture;
use gfx::traits::{Factory, FactoryExt};
use gfx::{Bind, CommandBuffer, Device, Encoder, IntoIndexBuffer, PipelineState, Resources, Slice};
use gfx::memory::Usage;
use gfx::buffer::Role;
use gfx::handle::{Buffer, DepthStencilView, RenderTargetView, Sampler, ShaderResourceView, Texture};
use gfx_window_glutin as gfx_glutin;
use gfx_text;
use gfx_device_gl as gl;

pub fn gui_main() {
    let mut model = Model::new();
    main_loop(&mut model);
}

type Graph = mf::Graph<Mutex<Box<GuiModule>>>;
type Interface = mf::Interface<Mutex<Box<GuiModule>>>;

/// Model holds info about GUI state
/// and program state
struct Model {
    time: f32,
    graph: Arc<Graph>,
    window_size: [f32; 2],
    mouse_pos: [f32; 2],
    node_z: Vec<mf::NodeId>,
}

impl Model {
    fn new() -> Model {
        Model {
            graph: Graph::new(),
            time: 0.0,
            window_size: [0.0, 0.0],
            mouse_pos: [0.0, 0.0],
            node_z: Vec::new(),
        }
    }

    fn update_depth(&mut self) {
        use std::collections::HashSet;
        let graph_nodes = self.graph.node_map();
        let mut seen = HashSet::new();
        self.node_z.drain_filter(|node| {
            seen.insert(*node);
            !graph_nodes.contains_key(node)
        });
        for (id, _) in &graph_nodes {
            if !seen.contains(id) {
                self.node_z.push(*id);
            }
        }
    }
    fn update(&mut self) {
        self.update_depth();
    }

    fn handle_mouse_input(&mut self, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;

        let graph_nodes = self.graph.node_map();
        let mut hit = false;
        let mut idx = self.node_z.len();
        for id in self.node_z.iter() {
            idx -= 1;
            if let Some(node) = graph_nodes.get(id) {
                let mut module = node.module().lock().unwrap();
                let rect = *module.window_rect();
                if point_in_rect(self.mouse_pos, &rect) {
                    module.handle_click(self, state, button);
                    hit = true;
                    break;
                }
            }
        }
        if hit {
            if let ElementState::Pressed = state {
                let removed = self.node_z.remove(idx);
                self.node_z.push(removed);
            }
        }
    }

    fn handle(&mut self, event: &glutin::Event) {
        use glutin::WindowEvent::*;
        use glutin::*;
        //println!("{:?}", event);
        match event {
            glutin::Event::WindowEvent {
                window_id: _,
                event,
            } => match event {
                Resized(w, h) => {
                    self.window_size = [*w as f32, *h as f32];
                }
                CursorMoved {
                    device_id: _,
                    position,
                } => {
                    self.mouse_pos = [position.0 as f32, position.1 as f32];
                }
                MouseInput {
                    device_id: _,
                    state,
                    button,
                } => {
                    self.handle_mouse_input(&state, &button);
                }
                _ => (),
            },
            _ => (),
        }
    }
}

fn main_loop(model: &mut Model) {
    // init window
    let mut events_loop = EventsLoop::new();
    let context = ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
    let builder = WindowBuilder::new().with_title(String::from("flow-synth"));
    let (window, mut device, mut factory, mut main_color, mut main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    let mut target = Target {
        color: main_color,
        depth: main_depth,
    };

    // init rendering pipeline
    let mut ctx = RenderContext::new(factory.clone());

    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "foo",
        Arc::new(move |ifc| {
            Mutex::new(Box::new(GuiModuleWrapper::new(
                TestModule::new(ifc),
                mod_ctx.clone(),
            )))
        }),
    ));
    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "bar",
        Arc::new(move |ifc| {
            let mut w = GuiModuleWrapper::new(TestModule::new(ifc), mod_ctx.clone());
            w.window_rect.translate[0] = 256.0;
            Mutex::new(Box::new(w))
        }),
    ));

    // begin main loop
    let mut running = true;
    let timer = Instant::now();
    let mut frames = VecDeque::new();
    while running {
        let now = timer.elapsed();
        model.time = now.as_secs() as f32 + now.subsec_nanos() as f32 / 1_000_000_000.0;
        frames.push_back(model.time);
        while let Some(&old_frame) = frames.front() {
            if old_frame < model.time - 1.0 {
                frames.pop_front();
            } else {
                break;
            }
        }
        model.update();
        for node in model.graph.nodes() {
            let mut module = node.module().lock().unwrap();
            module.update(&model);
        }
        events_loop.poll_events(|event| {
            model.handle(&event);
            for node in model.graph.nodes() {
                let mut module = node.module().lock().unwrap();
                module.handle(&model, &event);
            }
            use glutin::WindowEvent::*;
            match event {
                glutin::Event::WindowEvent {
                    window_id: _,
                    event,
                } => match event {
                    Closed => running = false,
                    Resized(_, _) => {
                        gfx_glutin::update_views(&window, &mut target.color, &mut target.depth);
                    }
                    _ => (),
                },
                _ => (),
            }
        });

        ctx.begin_frame(&target);

        let mut z_idx = 0;
        let graph_nodes = model.graph.node_map();
        for id in &model.node_z {
            match graph_nodes.get(id) {
                Some(node) => {
                    let mut module = node.module().lock().unwrap();
                    module.render(&mut device, &mut ctx, z_idx);
                    z_idx += 1;
                }
                None => (), // node was removed between call to model.update() and here. safe to ignore
            }
        }

        // debug text
        ctx.draw_text(
            &format!("FPS={} Time={}", frames.len(), model.time),
            [0.0, 0.0],
            [1.0, 1.0, 1.0],
        );

        ctx.end_frame(&mut device, &target);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

const TITLE_BAR_HEIGHT: f32 = 24.0;
const BORDER_SIZE: f32 = 1.0;

trait GuiModule: Module {
    fn render(&mut self, &mut gl::Device, &mut RenderContext, i32);
    fn window_rect(&self) -> &Rect;

    fn update(&mut self, model: &Model);
    fn handle(&mut self, model: &Model, event: &glutin::Event);
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton);
}
struct GuiModuleWrapper<T: Module> {
    module: T,

    window_rect: Rect,
    size: [f32; 2],
    drag: Option<[f32; 2]>,
    dirty: bool,

    internal_ctx: RenderContext,
    module_target_texture: Texture<gl::Resources, gfx::format::R8_G8_B8_A8>,
    module_depth_texture: Texture<gl::Resources, gfx::format::D24_S8>,
    module_target_resource: ShaderResourceView<gl::Resources, [f32; 4]>,
    module_target: Target,
}

impl<T: Module> GuiModuleWrapper<T> {
    fn new(module: T, ctx: RenderContext) -> GuiModuleWrapper<T> {
        let mut factory = ctx.factory().clone();
        let size = [256.0; 2];
        let module_target_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_color_target = factory
            .view_texture_as_render_target(
                &module_target_texture,
                0,    //level
                None, //layer
            )
            .unwrap();
        let module_target_resource = factory
            .view_texture_as_shader_resource::<gfx::format::Rgba8>(
                &module_target_texture,
                (0, 0), // levels
                gfx::format::Swizzle::new(),
            )
            .unwrap();

        let module_depth_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::DEPTH_STENCIL,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_depth_target = factory
            .view_texture_as_depth_stencil(
                &module_depth_texture,
                0,    //level
                None, //layer
                texture::DepthStencilFlags::empty(),
            )
            .unwrap();

        let module_target = Target {
            color: module_color_target,
            depth: module_depth_target,
        };

        GuiModuleWrapper {
            module,
            window_rect: Rect {
                translate: [0.0, 0.0, 0.0],
                scale: size,
            },
            size,
            drag: None,
            dirty: true,
            internal_ctx: ctx,
            module_target_resource,
            module_target_texture,
            module_depth_texture,
            module_target,
        }
    }
    fn render_self(&mut self) {
        self.internal_ctx.draw_rect(ColoredRect { // borders
            translate: [0.0, 0.0, 0.0],
            scale: self.size,
            color: [1.0, 1.0, 1.0],
        });
        self.internal_ctx.draw_rect(ColoredRect { // background
            translate: [BORDER_SIZE, BORDER_SIZE + TITLE_BAR_HEIGHT, 0.0],
            scale: [self.size[0] - BORDER_SIZE * 2.0, self.size[1] - BORDER_SIZE * 2.0 - TITLE_BAR_HEIGHT],
            color: [0.1, 0.1, 0.1],
        });
        self.internal_ctx.draw_rect(ColoredRect { // title bar
            translate: [BORDER_SIZE, BORDER_SIZE, 0.0],
            scale: [self.size[0] - BORDER_SIZE * 2.0, TITLE_BAR_HEIGHT],
            color: [0.0, 0.0, 0.0],
        });
        let title = &self.title();
        self.internal_ctx
            .draw_text(title, [4.0, 4.0], [1.0, 1.0, 1.0]);
    }
}

impl<T> GuiModule for GuiModuleWrapper<T>
where
    T: Module,
{
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext, z_idx: i32) {
        if self.dirty {
            self.internal_ctx.begin_frame(&self.module_target);
            self.render_self();
            self.internal_ctx.end_frame(device, &self.module_target);
            self.dirty = false;
        }

        self.window_rect.translate[2] = z_idx as f32;
        ctx.draw_textured_rect(self.window_rect, self.module_target_resource.clone());
    }
    fn update(&mut self, model: &Model) {
        if let Some(drag) = self.drag {
            self.window_rect.translate = [
                (-drag[0] + model.mouse_pos[0]).floor(),
                (-drag[1] + model.mouse_pos[1]).floor(),
                0.0,
            ];
        }
    }
    fn handle(&mut self, model: &Model, event: &glutin::Event) {}
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;
        match button {
            MouseButton::Left => match state {
                ElementState::Pressed => {
                    let mut title_rect = self.window_rect;
                    title_rect.scale[1] = TITLE_BAR_HEIGHT + BORDER_SIZE;
                    if point_in_rect(model.mouse_pos, &title_rect) {
                        self.drag = Some([
                            model.mouse_pos[0] - self.window_rect.translate[0],
                            model.mouse_pos[1] - self.window_rect.translate[1],
                        ]);
                    }
                }
                ElementState::Released => {
                    self.drag = None;
                }
            },
            _ => {}
        }
    }
    fn window_rect(&self) -> &Rect {
        &self.window_rect
    }
}
impl<T> Module for GuiModuleWrapper<T>
where
    T: Module,
{
    fn start(&mut self) {
        T::start(&mut self.module);
    }
    fn title(&self) -> String {
        T::title(&self.module)
    }
}
<commit_msg>Fix depth bug with many nodes<commit_after>mod render;

use self::render::*;
use super::module::*;

use glutin::{self, Api, ContextBuilder, ControlFlow, EventsLoop, GlContext, GlRequest, Window,
             WindowBuilder, WindowEvent};
use modular_flow as mf;

use std::env;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use std::time::{Duration, Instant};
use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use gfx;
use gfx::texture;
use gfx::traits::{Factory, FactoryExt};
use gfx::{Bind, CommandBuffer, Device, Encoder, IntoIndexBuffer, PipelineState, Resources, Slice};
use gfx::memory::Usage;
use gfx::buffer::Role;
use gfx::handle::{Buffer, DepthStencilView, RenderTargetView, Sampler, ShaderResourceView, Texture};
use gfx_window_glutin as gfx_glutin;
use gfx_text;
use gfx_device_gl as gl;

pub fn gui_main() {
    let mut model = Model::new();
    main_loop(&mut model);
}

type Graph = mf::Graph<Mutex<Box<GuiModule>>>;
type Interface = mf::Interface<Mutex<Box<GuiModule>>>;

/// Model holds info about GUI state
/// and program state
struct Model {
    time: f32,
    graph: Arc<Graph>,
    window_size: [f32; 2],
    mouse_pos: [f32; 2],
    node_z: Vec<mf::NodeId>,
}

impl Model {
    fn new() -> Model {
        Model {
            graph: Graph::new(),
            time: 0.0,
            window_size: [0.0, 0.0],
            mouse_pos: [0.0, 0.0],
            node_z: Vec::new(),
        }
    }

    fn update_depth(&mut self) {
        use std::collections::HashSet;
        let graph_nodes = self.graph.node_map();
        let mut seen = HashSet::new();
        self.node_z.drain_filter(|node| {
            seen.insert(*node);
            !graph_nodes.contains_key(node)
        });
        for (id, _) in &graph_nodes {
            if !seen.contains(id) {
                self.node_z.push(*id);
            }
        }
    }
    fn update(&mut self) {
        self.update_depth();
    }

    fn handle_mouse_input(&mut self, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;

        let graph_nodes = self.graph.node_map();
        let mut hit = false;
        let mut idx = self.node_z.len();
        for id in self.node_z.iter().rev() {
            idx -= 1;
            if let Some(node) = graph_nodes.get(id) {
                let mut module = node.module().lock().unwrap();
                let rect = *module.window_rect();
                if point_in_rect(self.mouse_pos, &rect) {
                    module.handle_click(self, state, button);
                    hit = true;
                    break;
                }
            }
        }
        if hit {
            if let ElementState::Pressed = state {
                let removed = self.node_z.remove(idx);
                self.node_z.push(removed);
            }
        }
    }

    fn handle(&mut self, event: &glutin::Event) {
        use glutin::WindowEvent::*;
        use glutin::*;
        //println!("{:?}", event);
        match event {
            glutin::Event::WindowEvent {
                window_id: _,
                event,
            } => match event {
                Resized(w, h) => {
                    self.window_size = [*w as f32, *h as f32];
                }
                CursorMoved {
                    device_id: _,
                    position,
                } => {
                    self.mouse_pos = [position.0 as f32, position.1 as f32];
                }
                MouseInput {
                    device_id: _,
                    state,
                    button,
                } => {
                    self.handle_mouse_input(&state, &button);
                }
                _ => (),
            },
            _ => (),
        }
    }
}

fn main_loop(model: &mut Model) {
    // init window
    let mut events_loop = EventsLoop::new();
    let context = ContextBuilder::new().with_gl_profile(glutin::GlProfile::Core);
    let builder = WindowBuilder::new().with_title(String::from("flow-synth"));
    let (window, mut device, mut factory, mut main_color, mut main_depth) =
        gfx_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    let mut target = Target {
        color: main_color,
        depth: main_depth,
    };

    // init rendering pipeline
    let mut ctx = RenderContext::new(factory.clone());

    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "foo",
        Arc::new(move |ifc| {
            Mutex::new(Box::new(GuiModuleWrapper::new(
                TestModule::new(ifc),
                mod_ctx.clone(),
            )))
        }),
    ));
    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "bar",
        Arc::new(move |ifc| {
            let mut w = GuiModuleWrapper::new(TestModule::new(ifc), mod_ctx.clone());
            w.window_rect.translate[0] = 256.0;
            Mutex::new(Box::new(w))
        }),
    ));
    let mod_ctx = ctx.clone();
    model.graph.add_node(&mf::MetaModule::new(
        "baz",
        Arc::new(move |ifc| {
            let mut w = GuiModuleWrapper::new(TestModule::new(ifc), mod_ctx.clone());
            w.window_rect.translate[0] = 512.0;
            Mutex::new(Box::new(w))
        }),
    ));

    // begin main loop
    let mut running = true;
    let timer = Instant::now();
    let mut frames = VecDeque::new();
    while running {
        let now = timer.elapsed();
        model.time = now.as_secs() as f32 + now.subsec_nanos() as f32 / 1_000_000_000.0;
        frames.push_back(model.time);
        while let Some(&old_frame) = frames.front() {
            if old_frame < model.time - 1.0 {
                frames.pop_front();
            } else {
                break;
            }
        }
        model.update();
        for node in model.graph.nodes() {
            let mut module = node.module().lock().unwrap();
            module.update(&model);
        }
        events_loop.poll_events(|event| {
            model.handle(&event);
            for node in model.graph.nodes() {
                let mut module = node.module().lock().unwrap();
                module.handle(&model, &event);
            }
            use glutin::WindowEvent::*;
            match event {
                glutin::Event::WindowEvent {
                    window_id: _,
                    event,
                } => match event {
                    Closed => running = false,
                    Resized(_, _) => {
                        gfx_glutin::update_views(&window, &mut target.color, &mut target.depth);
                    }
                    _ => (),
                },
                _ => (),
            }
        });

        ctx.begin_frame(&target);

        let mut z_idx = 0;
        let graph_nodes = model.graph.node_map();
        for id in &model.node_z {
            match graph_nodes.get(id) {
                Some(node) => {
                    let mut module = node.module().lock().unwrap();
                    module.render(&mut device, &mut ctx, 1.0 - z_idx as f32 / graph_nodes.len() as f32);
                    z_idx += 1;
                }
                None => (), // node was removed between call to model.update() and here. safe to ignore
            }
        }

        // debug text
        ctx.draw_text(
            &format!("FPS={} Time={}", frames.len(), model.time),
            [0.0, 0.0],
            [1.0, 1.0, 1.0],
        );

        ctx.end_frame(&mut device, &target);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

const TITLE_BAR_HEIGHT: f32 = 24.0;
const BORDER_SIZE: f32 = 1.0;

trait GuiModule: Module {
    fn render(&mut self, &mut gl::Device, &mut RenderContext, f32);
    fn window_rect(&self) -> &Rect;

    fn update(&mut self, model: &Model);
    fn handle(&mut self, model: &Model, event: &glutin::Event);
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton);
}
struct GuiModuleWrapper<T: Module> {
    module: T,

    window_rect: Rect,
    size: [f32; 2],
    drag: Option<[f32; 2]>,
    dirty: bool,

    internal_ctx: RenderContext,
    module_target_texture: Texture<gl::Resources, gfx::format::R8_G8_B8_A8>,
    module_depth_texture: Texture<gl::Resources, gfx::format::D24_S8>,
    module_target_resource: ShaderResourceView<gl::Resources, [f32; 4]>,
    module_target: Target,
}

impl<T: Module> GuiModuleWrapper<T> {
    fn new(module: T, ctx: RenderContext) -> GuiModuleWrapper<T> {
        let mut factory = ctx.factory().clone();
        let size = [256.0; 2];
        let module_target_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_color_target = factory
            .view_texture_as_render_target(
                &module_target_texture,
                0,    //level
                None, //layer
            )
            .unwrap();
        let module_target_resource = factory
            .view_texture_as_shader_resource::<gfx::format::Rgba8>(
                &module_target_texture,
                (0, 0), // levels
                gfx::format::Swizzle::new(),
            )
            .unwrap();

        let module_depth_texture = factory
            .create_texture(
                texture::Kind::D2(size[0] as u16, size[1] as u16, texture::AaMode::Single),
                1, //levels
                gfx::DEPTH_STENCIL,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let module_depth_target = factory
            .view_texture_as_depth_stencil(
                &module_depth_texture,
                0,    //level
                None, //layer
                texture::DepthStencilFlags::empty(),
            )
            .unwrap();

        let module_target = Target {
            color: module_color_target,
            depth: module_depth_target,
        };

        GuiModuleWrapper {
            module,
            window_rect: Rect {
                translate: [0.0, 0.0, 0.0],
                scale: size,
            },
            size,
            drag: None,
            dirty: true,
            internal_ctx: ctx,
            module_target_resource,
            module_target_texture,
            module_depth_texture,
            module_target,
        }
    }
    fn render_self(&mut self) {
        self.internal_ctx.draw_rect(ColoredRect { // borders
            translate: [0.0, 0.0, 0.0],
            scale: self.size,
            color: [1.0, 1.0, 1.0],
        });
        self.internal_ctx.draw_rect(ColoredRect { // background
            translate: [BORDER_SIZE, BORDER_SIZE + TITLE_BAR_HEIGHT, 0.0],
            scale: [self.size[0] - BORDER_SIZE * 2.0, self.size[1] - BORDER_SIZE * 2.0 - TITLE_BAR_HEIGHT],
            color: [0.1, 0.1, 0.1],
        });
        self.internal_ctx.draw_rect(ColoredRect { // title bar
            translate: [BORDER_SIZE, BORDER_SIZE, 0.0],
            scale: [self.size[0] - BORDER_SIZE * 2.0, TITLE_BAR_HEIGHT],
            color: [0.0, 0.0, 0.0],
        });
        let title = &self.title();
        self.internal_ctx
            .draw_text(title, [4.0, 4.0], [1.0, 1.0, 1.0]);
    }
}

impl<T> GuiModule for GuiModuleWrapper<T>
where
    T: Module,
{
    fn render(&mut self, device: &mut gl::Device, ctx: &mut RenderContext, z_idx: f32) {
        if self.dirty {
            self.internal_ctx.begin_frame(&self.module_target);
            self.render_self();
            self.internal_ctx.end_frame(device, &self.module_target);
            self.dirty = false;
        }

        self.window_rect.translate[2] = z_idx;
        ctx.draw_textured_rect(self.window_rect, self.module_target_resource.clone());
    }
    fn update(&mut self, model: &Model) {
        if let Some(drag) = self.drag {
            self.window_rect.translate = [
                (-drag[0] + model.mouse_pos[0]).floor(),
                (-drag[1] + model.mouse_pos[1]).floor(),
                0.0,
            ];
        }
    }
    fn handle(&mut self, model: &Model, event: &glutin::Event) {}
    fn handle_click(&mut self, model: &Model, state: &glutin::ElementState, button: &glutin::MouseButton) {
        use glutin::*;
        match button {
            MouseButton::Left => match state {
                ElementState::Pressed => {
                    let mut title_rect = self.window_rect;
                    title_rect.scale[1] = TITLE_BAR_HEIGHT + BORDER_SIZE;
                    if point_in_rect(model.mouse_pos, &title_rect) {
                        self.drag = Some([
                            model.mouse_pos[0] - self.window_rect.translate[0],
                            model.mouse_pos[1] - self.window_rect.translate[1],
                        ]);
                    }
                }
                ElementState::Released => {
                    self.drag = None;
                }
            },
            _ => {}
        }
    }
    fn window_rect(&self) -> &Rect {
        &self.window_rect
    }
}
impl<T> Module for GuiModuleWrapper<T>
where
    T: Module,
{
    fn start(&mut self) {
        T::start(&mut self.module);
    }
    fn title(&self) -> String {
        T::title(&self.module)
    }
}
<|endoftext|>


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

#![crate_name="string_cache_macros"]
#![crate_type="dylib"]

#![feature(macro_rules, plugin_registrar, quote, managed_boxes)]
#![allow(unused_imports)]  // for quotes

extern crate syntax;
extern crate rustc;

use rustc::plugin::Registry;
use syntax::codemap::Span;
use syntax::ast::{TokenTree, TTTok};
use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr};
use syntax::parse::token::{get_ident, InternedString, LIT_STR, IDENT};

use std::iter::Chain;
use std::slice::{Items, Found, NotFound};
use std::gc::Gc;

mod data;

#[path="../../shared/static_atom.rs"]
mod static_atom;

macro_rules! bail ( ($cx:expr, $sp:expr, $msg:expr) => ({
    $cx.span_err($sp, $msg);
    return ::syntax::ext::base::DummyResult::any($sp);
}))

macro_rules! bail_if ( ($e:expr, $cx:expr, $sp:expr, $msg:expr) => (
    if $e { bail!($cx, $sp, $msg) }
))

macro_rules! expect ( ($cx:expr, $sp:expr, $e:expr, $msg:expr) => (
    match $e {
        Some(x) => x,
        None => bail!($cx, $sp, $msg),
    }
))

fn all_atoms<'a>() -> Chain<Items<'a, &'static str>, Items<'a, &'static str>> {
    data::fast_set_atoms.iter().chain(data::other_atoms.iter())
}

// Build a PhfMap yielding static atom IDs.
// Takes no arguments.
fn expand_static_atom_map(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, cx, sp, "Usage: static_atom_map!()");
    let tts: Vec<TokenTree> = all_atoms().enumerate().flat_map(|(i, k)| {
        let i = i as u32;
        (quote_tokens!(&mut *cx, $k => $i,)).move_iter()
    }).collect();
    MacExpr::new(quote_expr!(&mut *cx, phf_map!($tts)))
}

// Build the array to convert IDs back to strings.
// FIXME: share storage with the PhfMap keys.
fn expand_static_atom_array(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, cx, sp, "Usage: static_atom_array!()");
    let tts: Vec<TokenTree> = all_atoms().flat_map(|k|
        quote_tokens!(&mut *cx, $k,).move_iter()
    ).collect();
    MacExpr::new(quote_expr!(&mut *cx, &[$tts]))
}

fn atom_tok_to_str(t: &TokenTree) -> Option<InternedString> {
    Some(get_ident(match *t {
        TTTok(_, IDENT(s, _)) => s,
        TTTok(_, LIT_STR(s)) => s.ident(),
        _ => return None,
    }))
}

fn find_atom(name: InternedString) -> Option<uint> {
    // Use bsearch instead of bsearch_elem because of type mismatch
    // between &'t str and &'static str.
    match data::fast_set_atoms.binary_search(|&x| x.cmp(&name.get())) {
        Found(i) => Some(i),
        NotFound(_) => match data::other_atoms.binary_search(|&x| x.cmp(&name.get())) {
            Found(i) => Some(i+64),
            NotFound(_) => None,
        },
    }
}

struct AtomResult {
    expr: Gc<ast::Expr>,
    pat: Gc<ast::Pat>,
}

impl MacResult for AtomResult {
    fn make_expr(&self) -> Option<Gc<ast::Expr>> {
        Some(self.expr)
    }

    fn make_pat(&self) -> Option<Gc<ast::Pat>> {
        Some(self.pat)
    }
}

// Translate `atom!(title)` or `atom!("font-weight")` into an `Atom` constant or pattern.
fn expand_atom(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    let usage = "Usage: atom!(html) or atom!(\"font-weight\")";
    let name = match tt {
        [ref t] => expect!(cx, sp, atom_tok_to_str(t), usage),
        _ => bail!(cx, sp, usage),
    };

    let i = expect!(cx, sp, find_atom(name.clone()),
        format!("Unknown static atom {:s}", name.get()).as_slice());

    let data = static_atom::add_tag(i as u32);

    box AtomResult {
        expr: quote_expr!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
        pat: quote_pat!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
    } as Box<MacResult>
}

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("static_atom_map", expand_static_atom_map);
    reg.register_macro("static_atom_array", expand_static_atom_array);
    reg.register_macro("atom", expand_atom);
}
<commit_msg>Fixes for Servo's older Rust<commit_after>// Copyright 2014 The Servo Project Developers. See the
// COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name="string_cache_macros"]
#![crate_type="dylib"]

#![feature(macro_rules, plugin_registrar, quote, managed_boxes)]
#![allow(unused_imports)]  // for quotes

extern crate syntax;
extern crate rustc;

use rustc::plugin::Registry;
use syntax::codemap::Span;
use syntax::ast::{TokenTree, TTTok};
use syntax::ast;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr};
use syntax::parse::token::{get_ident, InternedString, LIT_STR, IDENT};

use std::iter::Chain;
use std::slice::Items;
use std::gc::Gc;

mod data;

#[path="../../shared/static_atom.rs"]
mod static_atom;

macro_rules! bail ( ($cx:expr, $sp:expr, $msg:expr) => ({
    $cx.span_err($sp, $msg);
    return ::syntax::ext::base::DummyResult::any($sp);
}))

macro_rules! bail_if ( ($e:expr, $cx:expr, $sp:expr, $msg:expr) => (
    if $e { bail!($cx, $sp, $msg) }
))

macro_rules! expect ( ($cx:expr, $sp:expr, $e:expr, $msg:expr) => (
    match $e {
        Some(x) => x,
        None => bail!($cx, $sp, $msg),
    }
))

fn all_atoms<'a>() -> Chain<Items<'a, &'static str>, Items<'a, &'static str>> {
    data::fast_set_atoms.iter().chain(data::other_atoms.iter())
}

// Build a PhfMap yielding static atom IDs.
// Takes no arguments.
fn expand_static_atom_map(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, cx, sp, "Usage: static_atom_map!()");
    let tts: Vec<TokenTree> = all_atoms().enumerate().flat_map(|(i, k)| {
        let i = i as u32;
        (quote_tokens!(&mut *cx, $k => $i,)).move_iter()
    }).collect();
    MacExpr::new(quote_expr!(&mut *cx, phf_map!($tts)))
}

// Build the array to convert IDs back to strings.
// FIXME: share storage with the PhfMap keys.
fn expand_static_atom_array(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    bail_if!(tt.len() != 0, cx, sp, "Usage: static_atom_array!()");
    let tts: Vec<TokenTree> = all_atoms().flat_map(|k|
        quote_tokens!(&mut *cx, $k,).move_iter()
    ).collect();
    MacExpr::new(quote_expr!(&mut *cx, &[$tts]))
}

fn atom_tok_to_str(t: &TokenTree) -> Option<InternedString> {
    Some(get_ident(match *t {
        TTTok(_, IDENT(s, _)) => s,
        TTTok(_, LIT_STR(s)) => s.ident(),
        _ => return None,
    }))
}

fn find_atom(name: InternedString) -> Option<uint> {
    // Use bsearch instead of bsearch_elem because of type mismatch
    // between &'t str and &'static str.
    data::fast_set_atoms.bsearch(|&x| x.cmp(&name.get())).or_else(||
        data::other_atoms.bsearch(|&x| x.cmp(&name.get())).map(|i| i+64))

}

struct AtomResult {
    expr: Gc<ast::Expr>,
    pat: Gc<ast::Pat>,
}

impl MacResult for AtomResult {
    fn make_expr(&self) -> Option<Gc<ast::Expr>> {
        Some(self.expr)
    }

    fn make_pat(&self) -> Option<Gc<ast::Pat>> {
        Some(self.pat)
    }
}

// Translate `atom!(title)` or `atom!("font-weight")` into an `Atom` constant or pattern.
fn expand_atom(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> Box<MacResult> {
    let usage = "Usage: atom!(html) or atom!(\"font-weight\")";
    let name = match tt {
        [ref t] => expect!(cx, sp, atom_tok_to_str(t), usage),
        _ => bail!(cx, sp, usage),
    };

    let i = expect!(cx, sp, find_atom(name.clone()),
        format!("Unknown static atom {:s}", name.get()).as_slice());

    let data = static_atom::add_tag(i as u32);

    box AtomResult {
        expr: quote_expr!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
        pat: quote_pat!(&mut *cx, ::string_cache::atom::Atom { data: $data }),
    } as Box<MacResult>
}

// NB: This needs to be public or we get a linker error.
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("static_atom_map", expand_static_atom_map);
    reg.register_macro("static_atom_array", expand_static_atom_array);
    reg.register_macro("atom", expand_atom);
}
<|endoftext|>