<commit_before>use std::collections::HashSet;

use orbtk::prelude::*;

#[derive(Debug, Copy, Clone)]
enum Action {
    AddItem,
    ClearText,
    EntryActivated(Entity),
    IncrementCounter,
    RemoveItem,
    ToggleTheme(Entity),
}

#[derive(AsAny)]
pub struct MainViewState {
    action: Option<Action>,
}

impl Default for MainViewState {
    fn default() -> Self {
        MainViewState { action: None }
    }
}

impl MainViewState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }
}

impl State for MainViewState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = self.action {
            match action {
                Action::AddItem => {
                    let len = MainView::list_ref(&ctx.widget()).len();

                    if len < 5 {
                        MainView::list_mut(&mut ctx.widget()).push(format!("Item {}", len + 1));
                        ctx.child("items").clone_or_default::<usize>("Item");
                        ItemsWidget::count_set(&mut ctx.child("items"), len + 1);
                        Button::enabled_set(&mut ctx.child("remove-item-button"), true);

                        if len == 4 {
                            Button::enabled_set(&mut ctx.child("add-item-button"), false);
                        }
                    }
                }
                Action::RemoveItem => {
                    let len = MainView::list_ref(&ctx.widget()).len();
                    if len > 0 {
                        MainView::list_mut(&mut ctx.widget()).remove(len - 1);
                        ItemsWidget::count_set(&mut ctx.child("items"), len - 1);
                        Button::enabled_set(&mut ctx.child("add-item-button"), true);

                        if len == 1 {
                            Button::enabled_set(&mut ctx.child("remove-item-button"), false);
                        }
                    }
                }
                Action::IncrementCounter => {
                    *MainView::counter_mut(&mut ctx.widget()) += 1;

                    let counter = *MainView::counter_ref(&ctx.widget());

                    MainView::result_set(
                        &mut ctx.widget(),
                        String::from(format!("Button count: {}", counter)),
                    );
                }
                Action::ClearText => {
                    MainView::text_one_set(&mut ctx.widget(), String::default());
                    MainView::text_two_set(&mut ctx.widget(), String::default());
                }
                Action::EntryActivated(entity) => {
                    let text = TextBox::text_clone(&ctx.get_widget(entity));
                    println!("submitting {}", text);
                    TextBox::text_mut(&mut ctx.get_widget(entity)).clear();
                }
                Action::ToggleTheme(entity) => {
                    let light = *ctx.get_widget(entity).get::<bool>("selected");

                    let theme = if light { light_theme() } else { dark_theme() };
                    ctx.switch_theme(theme);
                }
            }

            self.action = None;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        let mut selection_string = "Selected:".to_string();

        for index in &MainView::selected_indices_ref(&ctx.widget()).0 {
            selection_string = format!("{} {}", selection_string, index);
        }

        TextBlock::text_set(&mut ctx.child("selection"), selection_string);
    }
}

fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
    TextBlock::new().text(text).style("header").build(ctx)
}

type List = Vec<String>;

widget!(
    MainView<MainViewState> {
        selected_indices: SelectedIndices,
        counter: usize,
        list_count: usize,
        combo_box_list_count: usize,
        list: List,
        selection_list: List,
        combo_box_list: List,
        selection_list_count: usize,
        text_one: String,
        text_two: String,
        result: String
    }
);

impl Template for MainView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let slider = Slider::new()
            .min(0.0)
            .max(1.0)
            // .on_changed(move |states, entity| {
            //     state(id, states).action(Action::ValueChanged(entity));
            // })
            .build(ctx);

        self.name("MainView")
            .result("Button count: 0")
            .counter(0)
            .selected_indices(HashSet::new())
            .list(vec![
                "Item 1".to_string(),
                "Item 2".to_string(),
                "Item 3".to_string(),
            ])
            .list_count(3)
            .selection_list(vec![
                "Select Item 1".to_string(),
                "Select Item 2".to_string(),
                "Select Item 3".to_string(),
                "Select Item 4".to_string(),
                "Select Item 5".to_string(),
                "Select Item 6".to_string(),
                "Select Item 7".to_string(),
                "Select Item 8".to_string(),
                "Select Item 9".to_string(),
                "Select Item 10".to_string(),
            ])
            .combo_box_list(vec![
                "CB 1".to_string(),
                "CB 2".to_string(),
                "CB 3".to_string(),
                "CB 4".to_string(),
                "CB 5".to_string(),
                "CB 6".to_string(),
                "CB 7".to_string(),
                "CB 8".to_string(),
                "CB 9".to_string(),
                "CB 10".to_string(),
            ])
            .selection_list_count(10)
            .combo_box_list_count(10)
            .child(
                Grid::new()
                    .margin(8)
                    .columns(
                        Columns::create()
                            .push(132)
                            .push(16)
                            .push(132)
                            .push(16)
                            .push(132),
                    )
                    .rows(Rows::create().push("*").push(32))
                    .child(
                        Stack::new()
                            .attach(Grid::column(0))
                            .attach(Grid::row(0))
                            // Column 0
                            .child(create_header(ctx, "Buttons"))
                            .child(
                                Button::new()
                                    .text("Button")
                                    .margin((0, 8, 0, 0))
                                    .icon(material_icons_font::MD_CHECK)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(1))
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::IncrementCounter);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .text("Primary")
                                    .style("button_primary")
                                    .margin((0, 8, 0, 0))
                                    .icon(material_icons_font::MD_360)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(2))
                                    .build(ctx),
                            )
                            .child(
                                ToggleButton::new()
                                    .style("button_single_content")
                                    .text("ToggleButton")
                                    .margin((0, 8, 2, 0))
                                    .icon(material_icons_font::MD_ALARM_ON)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(3))
                                    .build(ctx),
                            )
                            .child(
                                CheckBox::new()
                                    .text("CheckBox")
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Switch::new()
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(5))
                                    .build(ctx),
                            )
                            .child(slider)
                            .child(
                                ProgressBar::new()
                                    .val(slider)
                                    .margin((0, 8, 0, 0))
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Stack::new()
                            .attach(Grid::column(2))
                            .attach(Grid::row(0))
                            .child(create_header(ctx, "Text"))
                            .child(
                                TextBlock::new()
                                    .style("body")
                                    .text(("result", id))
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(1))
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_one", id))
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_two", id))
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .margin((0, 8, 0, 0))
                                    .style("button_single_content")
                                    .text("clear text")
                                    .icon(material_icons_font::MD_CLEAR)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::ClearText);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                NumericBox::new()
                                    .margin((0, 8, 0, 0))
                                    .max(123)
                                    .step(0.123)
                                    .val(0.123)
                                    .build(ctx),
                            )
                            .child(
                                PasswordBox::new()
                                    .margin((0, 8, 0, 0))
                                    .water_mark("Password")
                                    .v_align("center")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Grid::new()
                            .rows(
                                Rows::create()
                                    .push("auto")
                                    .push(32)
                                    .push(16)
                                    .push(204)
                                    .push("auto")
                                    .push(192)
                                    .push("auto"),
                            )
                            .columns(Columns::create().push("*").push(4).push("*"))
                            .attach(Grid::column(4))
                            .attach(Grid::row(0))
                            .child(
                                TextBlock::new()
                                    .text("Items")
                                    .style("header")
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(0))
                                    .build(ctx),
                            )
                            .child(
                                ComboBox::new()
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("combo_box_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .style("small_text")
                                            .margin((0, 0, 0, 2))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .selected_index(0)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(1))
                                    .margin((0, 8, 0, 0))
                                    .count(("combo_box_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                ItemsWidget::new()
                                    .id("items")
                                    .padding((4, 4, 4, 2))
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(3))
                                    .margin((0, 0, 0, 8))
                                    // bc = build-context
                                    .items_builder(move |bc, index| {
                                        let text = bc.get_widget(id).get::<Vec<String>>("list")
                                            [index]
                                            .clone();

                                        Button::new().margin((0, 0, 0, 2)).text(text).build(bc)
                                    })
                                    .count(("list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .style("button_single_content")
                                    .id("remove-item-button")
                                    .icon(material_icons_font::MD_REMOVE_CIRCLE)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::RemoveItem);
                                        true
                                    })
                                    .min_width(0)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .style("button_single_content")
                                    .id("add-item-button")
                                    .icon(material_icons_font::MD_ADD_CIRCLE)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::AddItem);
                                        true
                                    })
                                    .min_width(0)
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                ListView::new()
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(5))
                                    .selected_indices(id)
                                    .margin((0, 16, 0, 8))
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("selection_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .margin((0, 0, 0, 2))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .on_selection_changed(|_, _, _| println!("Selection changed"))
                                    .count(("selection_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                // todo: wrong text width????
                                TextBlock::new()
                                    .style("body")
                                    .id("selection")
                                    .max_width(120)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(6))
                                    .text("Selected:")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Stack::new()
                            .orientation("horizontal")
                            .attach(Grid::row(1))
                            .attach(Grid::column(0))
                            .child(
                                TextBlock::new()
                                    .style("body")
                                    .text("Toggle theme: ")
                                    .v_align("center")
                                    .margin((0, 0, 4, 0))
                                    .build(ctx),
                            )
                            .child(
                                Switch::new()
                                    .on_changed("selected", move |states, entity| {
                                        state(id, states).action(Action::ToggleTheme(entity));
                                    })
                                    .v_align("center")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}

fn main() {
    // use this only if you want to run it as web application.
    orbtk::initialize();

    Application::new()
        .window(|ctx| {
            Window::new()
                .title("OrbTk - widgets example")
                .position((100, 100))
                .size(468, 730)
                .resizeable(true)
                .child(MainView::new().build(ctx))
                .build(ctx)
        })
        .run();
}

// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
    states.get_mut(id)
}
<commit_msg>clippy fixes<commit_after>use std::collections::HashSet;

use orbtk::prelude::*;

#[derive(Debug, Copy, Clone)]
enum Action {
    AddItem,
    ClearText,
    EntryActivated(Entity),
    IncrementCounter,
    RemoveItem,
    ToggleTheme(Entity),
}

#[derive(AsAny)]
pub struct MainViewState {
    action: Option<Action>,
}

impl Default for MainViewState {
    fn default() -> Self {
        MainViewState { action: None }
    }
}

impl MainViewState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }
}

impl State for MainViewState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = self.action {
            match action {
                Action::AddItem => {
                    let len = MainView::list_ref(&ctx.widget()).len();

                    if len < 5 {
                        MainView::list_mut(&mut ctx.widget()).push(format!("Item {}", len + 1));
                        ctx.child("items").clone_or_default::<usize>("Item");
                        ItemsWidget::count_set(&mut ctx.child("items"), len + 1);
                        Button::enabled_set(&mut ctx.child("remove-item-button"), true);

                        if len == 4 {
                            Button::enabled_set(&mut ctx.child("add-item-button"), false);
                        }
                    }
                }
                Action::RemoveItem => {
                    let len = MainView::list_ref(&ctx.widget()).len();
                    if len > 0 {
                        MainView::list_mut(&mut ctx.widget()).remove(len - 1);
                        ItemsWidget::count_set(&mut ctx.child("items"), len - 1);
                        Button::enabled_set(&mut ctx.child("add-item-button"), true);

                        if len == 1 {
                            Button::enabled_set(&mut ctx.child("remove-item-button"), false);
                        }
                    }
                }
                Action::IncrementCounter => {
                    *MainView::counter_mut(&mut ctx.widget()) += 1;

                    let counter = *MainView::counter_ref(&ctx.widget());

                    MainView::result_set(
                        &mut ctx.widget(),
                        format!("Button count: {}", counter),
                    );
                }
                Action::ClearText => {
                    MainView::text_one_set(&mut ctx.widget(), String::default());
                    MainView::text_two_set(&mut ctx.widget(), String::default());
                }
                Action::EntryActivated(entity) => {
                    let text = TextBox::text_clone(&ctx.get_widget(entity));
                    println!("submitting {}", text);
                    TextBox::text_mut(&mut ctx.get_widget(entity)).clear();
                }
                Action::ToggleTheme(entity) => {
                    let light = *ctx.get_widget(entity).get::<bool>("selected");

                    let theme = if light { light_theme() } else { dark_theme() };
                    ctx.switch_theme(theme);
                }
            }

            self.action = None;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        let mut selection_string = "Selected:".to_string();

        for index in &MainView::selected_indices_ref(&ctx.widget()).0 {
            selection_string = format!("{} {}", selection_string, index);
        }

        TextBlock::text_set(&mut ctx.child("selection"), selection_string);
    }
}

fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
    TextBlock::new().text(text).style("header").build(ctx)
}

type List = Vec<String>;

widget!(
    MainView<MainViewState> {
        selected_indices: SelectedIndices,
        counter: usize,
        list_count: usize,
        combo_box_list_count: usize,
        list: List,
        selection_list: List,
        combo_box_list: List,
        selection_list_count: usize,
        text_one: String,
        text_two: String,
        result: String
    }
);

impl Template for MainView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let slider = Slider::new()
            .min(0.0)
            .max(1.0)
            // .on_changed(move |states, entity| {
            //     state(id, states).action(Action::ValueChanged(entity));
            // })
            .build(ctx);

        self.name("MainView")
            .result("Button count: 0")
            .counter(0)
            .selected_indices(HashSet::new())
            .list(vec![
                "Item 1".to_string(),
                "Item 2".to_string(),
                "Item 3".to_string(),
            ])
            .list_count(3)
            .selection_list(vec![
                "Select Item 1".to_string(),
                "Select Item 2".to_string(),
                "Select Item 3".to_string(),
                "Select Item 4".to_string(),
                "Select Item 5".to_string(),
                "Select Item 6".to_string(),
                "Select Item 7".to_string(),
                "Select Item 8".to_string(),
                "Select Item 9".to_string(),
                "Select Item 10".to_string(),
            ])
            .combo_box_list(vec![
                "CB 1".to_string(),
                "CB 2".to_string(),
                "CB 3".to_string(),
                "CB 4".to_string(),
                "CB 5".to_string(),
                "CB 6".to_string(),
                "CB 7".to_string(),
                "CB 8".to_string(),
                "CB 9".to_string(),
                "CB 10".to_string(),
            ])
            .selection_list_count(10)
            .combo_box_list_count(10)
            .child(
                Grid::new()
                    .margin(8)
                    .columns(
                        Columns::create()
                            .push(132)
                            .push(16)
                            .push(132)
                            .push(16)
                            .push(132),
                    )
                    .rows(Rows::create().push("*").push(32))
                    .child(
                        Stack::new()
                            .attach(Grid::column(0))
                            .attach(Grid::row(0))
                            // Column 0
                            .child(create_header(ctx, "Buttons"))
                            .child(
                                Button::new()
                                    .text("Button")
                                    .margin((0, 8, 0, 0))
                                    .icon(material_icons_font::MD_CHECK)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(1))
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::IncrementCounter);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .text("Primary")
                                    .style("button_primary")
                                    .margin((0, 8, 0, 0))
                                    .icon(material_icons_font::MD_360)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(2))
                                    .build(ctx),
                            )
                            .child(
                                ToggleButton::new()
                                    .style("button_single_content")
                                    .text("ToggleButton")
                                    .margin((0, 8, 2, 0))
                                    .icon(material_icons_font::MD_ALARM_ON)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(3))
                                    .build(ctx),
                            )
                            .child(
                                CheckBox::new()
                                    .text("CheckBox")
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Switch::new()
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(5))
                                    .build(ctx),
                            )
                            .child(slider)
                            .child(
                                ProgressBar::new()
                                    .val(slider)
                                    .margin((0, 8, 0, 0))
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Stack::new()
                            .attach(Grid::column(2))
                            .attach(Grid::row(0))
                            .child(create_header(ctx, "Text"))
                            .child(
                                TextBlock::new()
                                    .style("body")
                                    .text(("result", id))
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(1))
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_one", id))
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                TextBox::new()
                                    .water_mark("TextBox...")
                                    .text(("text_two", id))
                                    .margin((0, 8, 0, 0))
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(2))
                                    .on_activate(move |states, entity| {
                                        state(id, states).action(Action::EntryActivated(entity));
                                    })
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .margin((0, 8, 0, 0))
                                    .style("button_single_content")
                                    .text("clear text")
                                    .icon(material_icons_font::MD_CLEAR)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::ClearText);
                                        true
                                    })
                                    .build(ctx),
                            )
                            .child(
                                NumericBox::new()
                                    .margin((0, 8, 0, 0))
                                    .max(123)
                                    .step(0.123)
                                    .val(0.123)
                                    .build(ctx),
                            )
                            .child(
                                PasswordBox::new()
                                    .margin((0, 8, 0, 0))
                                    .water_mark("Password")
                                    .v_align("center")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Grid::new()
                            .rows(
                                Rows::create()
                                    .push("auto")
                                    .push(32)
                                    .push(16)
                                    .push(204)
                                    .push("auto")
                                    .push(192)
                                    .push("auto"),
                            )
                            .columns(Columns::create().push("*").push(4).push("*"))
                            .attach(Grid::column(4))
                            .attach(Grid::row(0))
                            .child(
                                TextBlock::new()
                                    .text("Items")
                                    .style("header")
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(0))
                                    .build(ctx),
                            )
                            .child(
                                ComboBox::new()
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("combo_box_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .style("small_text")
                                            .margin((0, 0, 0, 2))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .selected_index(0)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(1))
                                    .margin((0, 8, 0, 0))
                                    .count(("combo_box_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                ItemsWidget::new()
                                    .id("items")
                                    .padding((4, 4, 4, 2))
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(3))
                                    .margin((0, 0, 0, 8))
                                    // bc = build-context
                                    .items_builder(move |bc, index| {
                                        let text = bc.get_widget(id).get::<Vec<String>>("list")
                                            [index]
                                            .clone();

                                        Button::new().margin((0, 0, 0, 2)).text(text).build(bc)
                                    })
                                    .count(("list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .style("button_single_content")
                                    .id("remove-item-button")
                                    .icon(material_icons_font::MD_REMOVE_CIRCLE)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::RemoveItem);
                                        true
                                    })
                                    .min_width(0)
                                    .attach(Grid::column(0))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                Button::new()
                                    .style("button_single_content")
                                    .id("add-item-button")
                                    .icon(material_icons_font::MD_ADD_CIRCLE)
                                    .on_click(move |states, _| {
                                        state(id, states).action(Action::AddItem);
                                        true
                                    })
                                    .min_width(0)
                                    .attach(Grid::column(2))
                                    .attach(Grid::row(4))
                                    .build(ctx),
                            )
                            .child(
                                ListView::new()
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(5))
                                    .selected_indices(id)
                                    .margin((0, 16, 0, 8))
                                    .items_builder(move |bc, index| {
                                        let text = bc
                                            .get_widget(id)
                                            .get::<Vec<String>>("selection_list")[index]
                                            .clone();
                                        TextBlock::new()
                                            .margin((0, 0, 0, 2))
                                            .v_align("center")
                                            .text(text)
                                            .build(bc)
                                    })
                                    .on_selection_changed(|_, _, _| println!("Selection changed"))
                                    .count(("selection_list_count", id))
                                    .build(ctx),
                            )
                            .child(
                                // todo: wrong text width????
                                TextBlock::new()
                                    .style("body")
                                    .id("selection")
                                    .max_width(120)
                                    .attach(Grid::column(0))
                                    .attach(Grid::column_span(3))
                                    .attach(Grid::row(6))
                                    .text("Selected:")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .child(
                        Stack::new()
                            .orientation("horizontal")
                            .attach(Grid::row(1))
                            .attach(Grid::column(0))
                            .child(
                                TextBlock::new()
                                    .style("body")
                                    .text("Toggle theme: ")
                                    .v_align("center")
                                    .margin((0, 0, 4, 0))
                                    .build(ctx),
                            )
                            .child(
                                Switch::new()
                                    .on_changed("selected", move |states, entity| {
                                        state(id, states).action(Action::ToggleTheme(entity));
                                    })
                                    .v_align("center")
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}

fn main() {
    // use this only if you want to run it as web application.
    orbtk::initialize();

    Application::new()
        .window(|ctx| {
            Window::new()
                .title("OrbTk - widgets example")
                .position((100, 100))
                .size(468, 730)
                .resizeable(true)
                .child(MainView::new().build(ctx))
                .build(ctx)
        })
        .run();
}

// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
    states.get_mut(id)
}
<|endoftext|>


<commit_before>extern crate rdkafka;
extern crate futures;
extern crate rand;

mod test_utils;

use futures::*;

use rdkafka::consumer::{Consumer, CommitMode};
use rdkafka::topic_partition_list::TopicPartitionList;

use test_utils::*;

// All produced messages should be consumed.
#[test]
fn test_produce_consume_base() {
    let topic_name = rand_test_topic();
    let message_map = produce_messages(&topic_name, 100, &value_fn, &key_fn, None);
    let mut consumer = create_stream_consumer(&topic_name);

    let _consumer_future = consumer.start()
        .take(100)
        .for_each(|message| {
            match message {
                Ok(m) => {
                    let id = message_map.get(&(m.partition(), m.offset())).unwrap();
                    assert_eq!(m.payload_view::<str>().unwrap().unwrap(), value_fn(*id));
                    assert_eq!(m.key_view::<str>().unwrap().unwrap(), key_fn(*id));
                },
                e => panic!("Error receiving message: {:?}", e)
            };
            Ok(())
        })
        .wait();
}

// All messages should go to the same partition.
#[test]
fn test_produce_partition() {
    let topic_name = rand_test_topic();
    let message_map = produce_messages(&topic_name, 100, &value_fn, &key_fn, Some(0));

    let res = message_map.iter()
        .filter(|&(&(partition, _), _)| partition == 0)
        .count();

    assert_eq!(res, 100);
}

#[test]
fn test_metadata() {
    let topic_name = rand_test_topic();
    produce_messages(&topic_name, 1, &value_fn, &key_fn, Some(0));
    produce_messages(&topic_name, 1, &value_fn, &key_fn, Some(1));
    produce_messages(&topic_name, 1, &value_fn, &key_fn, Some(2));
    let consumer = create_stream_consumer(&topic_name);

    let metadata = consumer.fetch_metadata(5000).unwrap();

    let topic_metadata = metadata.topics().iter()
        .find(|m| m.name() == topic_name).unwrap();

    let mut ids = topic_metadata.partitions().iter().map(|p| p.id()).collect::<Vec<_>>();
    ids.sort();

    assert_eq!(ids, vec![0, 1, 2]);
    // assert_eq!(topic_metadata.error(), None);
    assert_eq!(topic_metadata.partitions().len(), 3);
    assert_eq!(topic_metadata.partitions()[0].leader(), 0);
    assert_eq!(topic_metadata.partitions()[1].leader(), 0);
    assert_eq!(topic_metadata.partitions()[2].leader(), 0);
    assert_eq!(topic_metadata.partitions()[0].replicas(), &[0]);
    assert_eq!(topic_metadata.partitions()[0].isr(), &[0]);
}

#[test]
fn test_consumer_commit() {
    let topic_name = rand_test_topic();
    produce_messages(&topic_name, 10, &value_fn, &key_fn, Some(0));
    produce_messages(&topic_name, 11, &value_fn, &key_fn, Some(1));
    produce_messages(&topic_name, 12, &value_fn, &key_fn, Some(2));
    let mut consumer = create_stream_consumer(&topic_name);

    let _consumer_future = consumer.start()
        .take(33)
        .for_each(|message| {
            match message {
                Ok(m) => {
                    if m.partition() == 1 {
                        consumer.commit_message(&m, CommitMode::Async).unwrap();
                    }
                },
                e => panic!("Error receiving message: {:?}", e)
            };
            Ok(())
        })
        .wait();

    assert_eq!(consumer.fetch_watermarks(&topic_name, 0, 5000).unwrap(), (0, 10));
    assert_eq!(consumer.fetch_watermarks(&topic_name, 1, 5000).unwrap(), (0, 11));
    assert_eq!(consumer.fetch_watermarks(&topic_name, 2, 5000).unwrap(), (0, 12));

    let mut assignment = TopicPartitionList::new();
    assignment.add_topic_with_partitions_and_offsets(&topic_name, &vec![(0, -1001), (1, -1001), (2, -1001)]);
    assert_eq!(assignment, consumer.assignment().unwrap());

    let mut committed = TopicPartitionList::new();
    committed.add_topic_with_partitions_and_offsets(&topic_name, &vec![(0, -1001), (1, 11), (2, -1001)]);
    assert_eq!(committed, consumer.committed(5000).unwrap());

    let mut position = TopicPartitionList::new();
    position.add_topic_with_partitions_and_offsets(&topic_name, &vec![(0, 10), (1, 11), (2, 12)]);
    assert_eq!(position, consumer.position().unwrap());
}

#[test]
fn test_subscription() {
    let topic_name = rand_test_topic();
    produce_messages(&topic_name, 10, &value_fn, &key_fn, None);
    let mut consumer = create_stream_consumer(&topic_name);

    let _consumer_future = consumer.start().take(10).wait();

    let subscription = TopicPartitionList::with_topics(vec![topic_name.as_str()].as_slice());
    assert_eq!(subscription, consumer.subscription().unwrap());
}
<commit_msg>Add logging config to tests<commit_after>extern crate env_logger;
extern crate futures;
extern crate rand;
extern crate rdkafka;

mod test_utils;

use futures::*;

use rdkafka::consumer::{Consumer, CommitMode};
use rdkafka::topic_partition_list::TopicPartitionList;

use test_utils::*;

// All produced messages should be consumed.
#[test]
fn test_produce_consume_base() {
    let _r = env_logger::init();

    let topic_name = rand_test_topic();
    let message_map = produce_messages(&topic_name, 100, &value_fn, &key_fn, None);
    let mut consumer = create_stream_consumer(&topic_name);

    let _consumer_future = consumer.start()
        .take(100)
        .for_each(|message| {
            match message {
                Ok(m) => {
                    let id = message_map.get(&(m.partition(), m.offset())).unwrap();
                    assert_eq!(m.payload_view::<str>().unwrap().unwrap(), value_fn(*id));
                    assert_eq!(m.key_view::<str>().unwrap().unwrap(), key_fn(*id));
                },
                e => panic!("Error receiving message: {:?}", e)
            };
            Ok(())
        })
        .wait();
}

// All messages should go to the same partition.
#[test]
fn test_produce_partition() {
    let _r = env_logger::init();

    let topic_name = rand_test_topic();
    let message_map = produce_messages(&topic_name, 100, &value_fn, &key_fn, Some(0));

    let res = message_map.iter()
        .filter(|&(&(partition, _), _)| partition == 0)
        .count();

    assert_eq!(res, 100);
}

#[test]
fn test_metadata() {
    let _r = env_logger::init();

    let topic_name = rand_test_topic();
    produce_messages(&topic_name, 1, &value_fn, &key_fn, Some(0));
    produce_messages(&topic_name, 1, &value_fn, &key_fn, Some(1));
    produce_messages(&topic_name, 1, &value_fn, &key_fn, Some(2));
    let consumer = create_stream_consumer(&topic_name);

    let metadata = consumer.fetch_metadata(5000).unwrap();

    let topic_metadata = metadata.topics().iter()
        .find(|m| m.name() == topic_name).unwrap();

    let mut ids = topic_metadata.partitions().iter().map(|p| p.id()).collect::<Vec<_>>();
    ids.sort();

    assert_eq!(ids, vec![0, 1, 2]);
    // assert_eq!(topic_metadata.error(), None);
    assert_eq!(topic_metadata.partitions().len(), 3);
    assert_eq!(topic_metadata.partitions()[0].leader(), 0);
    assert_eq!(topic_metadata.partitions()[1].leader(), 0);
    assert_eq!(topic_metadata.partitions()[2].leader(), 0);
    assert_eq!(topic_metadata.partitions()[0].replicas(), &[0]);
    assert_eq!(topic_metadata.partitions()[0].isr(), &[0]);
}

#[test]
fn test_consumer_commit() {
    let _r = env_logger::init();

    let topic_name = rand_test_topic();
    produce_messages(&topic_name, 10, &value_fn, &key_fn, Some(0));
    produce_messages(&topic_name, 11, &value_fn, &key_fn, Some(1));
    produce_messages(&topic_name, 12, &value_fn, &key_fn, Some(2));
    let mut consumer = create_stream_consumer(&topic_name);

    let _consumer_future = consumer.start()
        .take(33)
        .for_each(|message| {
            match message {
                Ok(m) => {
                    if m.partition() == 1 {
                        consumer.commit_message(&m, CommitMode::Async).unwrap();
                    }
                },
                e => panic!("Error receiving message: {:?}", e)
            };
            Ok(())
        })
        .wait();

    assert_eq!(consumer.fetch_watermarks(&topic_name, 0, 5000).unwrap(), (0, 10));
    assert_eq!(consumer.fetch_watermarks(&topic_name, 1, 5000).unwrap(), (0, 11));
    assert_eq!(consumer.fetch_watermarks(&topic_name, 2, 5000).unwrap(), (0, 12));

    let mut assignment = TopicPartitionList::new();
    assignment.add_topic_with_partitions_and_offsets(&topic_name, &vec![(0, -1001), (1, -1001), (2, -1001)]);
    assert_eq!(assignment, consumer.assignment().unwrap());

    let mut committed = TopicPartitionList::new();
    committed.add_topic_with_partitions_and_offsets(&topic_name, &vec![(0, -1001), (1, 11), (2, -1001)]);
    assert_eq!(committed, consumer.committed(5000).unwrap());

    let mut position = TopicPartitionList::new();
    position.add_topic_with_partitions_and_offsets(&topic_name, &vec![(0, 10), (1, 11), (2, 12)]);
    assert_eq!(position, consumer.position().unwrap());
}

#[test]
fn test_subscription() {
    let _r = env_logger::init();

    let topic_name = rand_test_topic();
    produce_messages(&topic_name, 10, &value_fn, &key_fn, None);
    let mut consumer = create_stream_consumer(&topic_name);

    let _consumer_future = consumer.start().take(10).wait();

    let subscription = TopicPartitionList::with_topics(vec![topic_name.as_str()].as_slice());
    assert_eq!(subscription, consumer.subscription().unwrap());
}
<|endoftext|>


<commit_before>use std::thread::sleep;
use std::time::{Instant, Duration};

use rand::random;
use kvproto::pdpb;

use super::node::new_node_cluster;
use super::server::new_server_cluster;
use super::cluster::{Cluster, Simulator};
use super::transport_simulate::Isolate;

fn wait_down_peers<T: Simulator>(cluster: &Cluster<T>, count: u64) -> u64 {
    let begin = Instant::now();
    for _ in 1..100 {
        if cluster.get_down_peers().len() != count as usize {
            sleep(Duration::from_millis(100));
        } else {
            break;
        }
    }
    begin.elapsed().as_secs()
}

fn check_down_seconds(peer: &pdpb::PeerStats, secs: u64) {
    debug!("down {} secs {}", peer.get_down_seconds(), secs);
    assert!(peer.get_down_seconds() <= secs);
}

fn test_leader_down_and_become_leader_again<T: Simulator>(cluster: &mut Cluster<T>, count: u64) {
    // Isolate node.
    let node = cluster.leader_of_region(1).unwrap();
    let node_id = node.get_id();
    cluster.add_send_filter(Isolate::new(node_id));

    // Kill another node.
    let next_id = if node_id < count { node_id + 1 } else { 1 };
    cluster.stop_node(next_id);

    // Check node and another are down.
    let secs = wait_down_peers(cluster, 2);
    let down_peers = cluster.get_down_peers();
    debug!("down_peers: {:?}", down_peers);
    check_down_seconds(down_peers.get(&node_id).unwrap(), secs);
    check_down_seconds(down_peers.get(&next_id).unwrap(), secs);

    // Restart node and sleep a few seconds.
    let sleep_secs = 3;
    cluster.clear_send_filters();
    wait_down_peers(cluster, 1);
    sleep(Duration::from_secs(sleep_secs));

    // Wait node to become leader again.
    loop {
        cluster.transfer_leader(1, node.clone());
        if let Some(peer) = cluster.leader_of_region(1) {
            if peer.get_id() == node_id {
                break;
            }
        }
        sleep(Duration::from_millis(100));
    }
    wait_down_peers(cluster, 1);

    // Ensure that node will not reuse the previous peer heartbeats.
    let prev_secs = cluster.get_down_peers().get(&next_id).unwrap().get_down_seconds();
    for _ in 1..100 {
        let down_secs = cluster.get_down_peers().get(&next_id).unwrap().get_down_seconds();
        if down_secs != prev_secs {
            assert!(down_secs < sleep_secs);
            break;
        }
        sleep(Duration::from_millis(100));
    }
}

fn test_down_peers<T: Simulator>(cluster: &mut Cluster<T>, count: u64) {
    cluster.cfg.raft_store.max_peer_down_duration = Duration::from_millis(500);
    cluster.run();

    // Kill 1, 3
    cluster.stop_node(1);
    cluster.stop_node(3);
    let secs = wait_down_peers(cluster, 2);

    // Check 1, 3 are down.
    let down_peers = cluster.get_down_peers();
    check_down_seconds(down_peers.get(&1).unwrap(), secs);
    check_down_seconds(down_peers.get(&3).unwrap(), secs);

    // Restart 1, 3
    cluster.run_node(1);
    cluster.run_node(3);
    wait_down_peers(cluster, 0);

    for _ in 0..3 {
        let n = random::<u64>() % count + 1;

        // kill n.
        cluster.stop_node(n);
        let secs = wait_down_peers(cluster, 1);

        // Check i is down and others are not down.
        for i in 1..(count + 1) {
            match cluster.get_down_peers().get(&i) {
                Some(peer) => {
                    assert_eq!(i, n);
                    check_down_seconds(peer, secs);
                }
                None => assert!(i != n),
            }
        }

        // Restart n.
        cluster.run_node(n);
        wait_down_peers(cluster, 0);
    }

    test_leader_down_and_become_leader_again(cluster, count);
}

#[test]
fn test_node_down_peers() {
    let mut cluster = new_node_cluster(0, 5);
    test_down_peers(&mut cluster, 5);
}

#[test]
fn test_server_down_peers() {
    let mut cluster = new_server_cluster(0, 5);
    test_down_peers(&mut cluster, 5);
}
<commit_msg>tests: fix test_down_peers. (#1027)<commit_after>use std::thread::sleep;
use std::time::{Instant, Duration};

use rand::random;
use kvproto::pdpb;

use super::node::new_node_cluster;
use super::server::new_server_cluster;
use super::cluster::{Cluster, Simulator};
use super::transport_simulate::Isolate;

fn wait_down_peers<T: Simulator>(cluster: &Cluster<T>, count: u64) -> u64 {
    let begin = Instant::now();
    for _ in 1..100 {
        if cluster.get_down_peers().len() != count as usize {
            sleep(Duration::from_millis(100));
        } else {
            break;
        }
    }
    begin.elapsed().as_secs()
}

fn check_down_seconds(peer: &pdpb::PeerStats, secs: u64) {
    debug!("down {} secs {}", peer.get_down_seconds(), secs);
    assert!(peer.get_down_seconds() <= secs);
}

fn test_leader_down_and_become_leader_again<T: Simulator>(cluster: &mut Cluster<T>, count: u64) {
    // Isolate node.
    let node = cluster.leader_of_region(1).unwrap();
    let node_id = node.get_id();
    cluster.add_send_filter(Isolate::new(node_id));
    debug!("node: {:?}", node);

    // Kill another node.
    let next_id = if node_id < count { node_id + 1 } else { 1 };
    cluster.stop_node(next_id);

    // Wait other node to become leader.
    let begin = Instant::now();
    for _ in 1..100 {
        cluster.reset_leader_of_region(1);
        if let Some(peer) = cluster.leader_of_region(1) {
            if peer.get_id() != node_id {
                break;
            }
        }
        sleep(Duration::from_millis(100));
    }
    assert!(node_id != cluster.leader_of_region(1).unwrap().get_id());
    wait_down_peers(cluster, 2);

    // Check node and another are down.
    let down_secs = begin.elapsed().as_secs();
    let down_peers = cluster.get_down_peers();
    debug!("down_secs: {} down_peers: {:?}", down_secs, down_peers);
    check_down_seconds(down_peers.get(&node_id).unwrap(), down_secs);
    check_down_seconds(down_peers.get(&next_id).unwrap(), down_secs);

    // Restart node and sleep a few seconds.
    let sleep_secs = 3;
    cluster.clear_send_filters();
    wait_down_peers(cluster, 1);
    sleep(Duration::from_secs(sleep_secs));

    // Wait node to become leader again.
    for _ in 1..100 {
        cluster.transfer_leader(1, node.clone());
        if let Some(peer) = cluster.leader_of_region(1) {
            if peer.get_id() == node_id {
                break;
            }
        }
        sleep(Duration::from_millis(100));
    }
    assert!(node_id == cluster.leader_of_region(1).unwrap().get_id());
    wait_down_peers(cluster, 1);

    // Ensure that node will not reuse the previous peer heartbeats.
    let prev_secs = cluster.get_down_peers().get(&next_id).unwrap().get_down_seconds();
    for _ in 1..100 {
        let down_secs = cluster.get_down_peers().get(&next_id).unwrap().get_down_seconds();
        if down_secs != prev_secs {
            assert!(down_secs < sleep_secs);
            break;
        }
        sleep(Duration::from_millis(100));
    }
}

fn test_down_peers<T: Simulator>(cluster: &mut Cluster<T>, count: u64) {
    cluster.cfg.raft_store.max_peer_down_duration = Duration::from_millis(500);
    cluster.run();

    // Kill 1, 3
    cluster.stop_node(1);
    cluster.stop_node(3);
    let secs = wait_down_peers(cluster, 2);

    // Check 1, 3 are down.
    let down_peers = cluster.get_down_peers();
    check_down_seconds(down_peers.get(&1).unwrap(), secs);
    check_down_seconds(down_peers.get(&3).unwrap(), secs);

    // Restart 1, 3
    cluster.run_node(1);
    cluster.run_node(3);
    wait_down_peers(cluster, 0);

    for _ in 0..3 {
        let n = random::<u64>() % count + 1;

        // kill n.
        cluster.stop_node(n);
        let secs = wait_down_peers(cluster, 1);

        // Check i is down and others are not down.
        for i in 1..(count + 1) {
            match cluster.get_down_peers().get(&i) {
                Some(peer) => {
                    assert_eq!(i, n);
                    check_down_seconds(peer, secs);
                }
                None => assert!(i != n),
            }
        }

        // Restart n.
        cluster.run_node(n);
        wait_down_peers(cluster, 0);
    }

    test_leader_down_and_become_leader_again(cluster, count);
}

#[test]
fn test_node_down_peers() {
    let mut cluster = new_node_cluster(0, 5);
    test_down_peers(&mut cluster, 5);
}

#[test]
fn test_server_down_peers() {
    let mut cluster = new_server_cluster(0, 5);
    test_down_peers(&mut cluster, 5);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub struct MachineCode<'a> {
    instructions: Vec<Instruction<'a>>,
    label_locations: HashMap<&'a str, i32>
}

pub struct Instruction<'a> {
    label: &'a str,
    operation: &'a str,
    operands: Vec<&'a str>
}

pub fn parse_instruction<'a>(instruction: &'a str) -> Instruction<'a> {
    let mut instruction_iterator = instruction.split(" ");
    let instruction_vector = instruction_iterator.collect::<Vec<&str>>();

    let mut operands_iterator = instruction_vector[1].split(",");
    let operands_vector = operands_iterator.collect::<Vec<&str>>();

    Instruction {
        label: "",
        operation: instruction_vector[0],
        operands: operands_vector
    }
}

pub fn assemble<'a>(program: &'a str) -> Vec<Instruction<'a>> {
    let instruction_iterator = program.split("\n");
    let mut instructions: Vec<Instruction> = Vec::with_capacity(2);
    let mut label_locations = HashMap::new();

    for (index, line) in instruction_iterator.enumerate() {
        println!("{}", line);
        let instruction = parse_instruction(line);
        if (instruction.label != "") {
          label_locations.insert(instruction.label, index);
        }

        instructions.push(instruction);

    }
    instructions
}

#[test]
fn can_assemble() {
    let program = "ldi r0,$0f\ninc r0";
    let instructions = assemble(program);

    assert_eq!(instructions.len(), 2);

    let ldi = &instructions[0];
    assert_eq!("", ldi.label);
    assert_eq!("ldi", ldi.operation);
    assert_eq!(vec!["r0","$0f"], ldi.operands);

    let inc = &instructions[1];
    assert_eq!("", inc.label);
    assert_eq!("inc", inc.operation);
    assert_eq!(vec!["r0"], inc.operands);
}
<commit_msg>assemble now keeps track of labels<commit_after>use std::collections::HashMap;

pub struct MachineCode<'a> {
    instructions: Vec<Instruction<'a>>,
    label_locations: HashMap<&'a str, usize>
}

pub struct Instruction<'a> {
    label: &'a str,
    operation: &'a str,
    operands: Vec<&'a str>
}

pub fn parse_instruction<'a>(instruction: &'a str) -> Instruction<'a> {
    let instruction_iterator = instruction.split(" ");
    let mut instruction_vector = instruction_iterator.collect::<Vec<&str>>();

    let operands_iterator = instruction_vector.pop().unwrap().split(",");
    let operands_vector = operands_iterator.collect::<Vec<&str>>();

    let operation = instruction_vector.pop().unwrap();
    let label = instruction_vector.pop().unwrap_or("");

    Instruction {
        label: label,
        operation: operation,
        operands: operands_vector
    }
}

pub fn assemble<'a>(program: &'a str) -> MachineCode<'a> {
    let instruction_iterator = program.split("\n");
    let mut instructions: Vec<Instruction> = Vec::with_capacity(2);
    let mut label_locations = HashMap::new();

    for (index, line) in instruction_iterator.enumerate() {
        println!("{}", line);
        let instruction = parse_instruction(line);
        if (instruction.label != "") {
          label_locations.insert(instruction.label, index);
        }

        instructions.push(instruction);

    }
    MachineCode {
      instructions: instructions,
      label_locations: label_locations
    }
}

#[test]
fn can_assemble() {
    let program = "ldi r0,$0f\nspecial inc r0";
    let machine_code = assemble(program);

    assert_eq!(machine_code.instructions.len(), 2);

    let ldi = &machine_code.instructions[0];
    assert_eq!("", ldi.label);
    assert_eq!("ldi", ldi.operation);
    assert_eq!(vec!["r0","$0f"], ldi.operands);

    let inc = &machine_code.instructions[1];
    assert_eq!("special", inc.label);
    assert_eq!("inc", inc.operation);
    assert_eq!(vec!["r0"], inc.operands);

    let labels = &machine_code.label_locations;
    assert_eq!(labels.get("special"), Some(&1usize));
}
<|endoftext|>


<commit_before>/// Conversion from an `Iterator`.
///
/// By implementing `FromIterator` for a type, you define how it will be
/// created from an iterator. This is common for types which describe a
/// collection of some kind.
///
/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead
/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s
/// documentation for more examples.
///
/// [`from_iter`]: #tymethod.from_iter
/// [`Iterator`]: trait.Iterator.html
/// [`collect`]: trait.Iterator.html#method.collect
///
/// See also: [`IntoIterator`].
///
/// [`IntoIterator`]: trait.IntoIterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::iter::FromIterator;
///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
///
/// Using [`collect`] to implicitly use `FromIterator`:
///
/// ```
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v: Vec<i32> = five_fives.collect();
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
///
/// Implementing `FromIterator` for your type:
///
/// ```
/// use std::iter::FromIterator;
///
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
///     fn new() -> MyCollection {
///         MyCollection(Vec::new())
///     }
///
///     fn add(&mut self, elem: i32) {
///         self.0.push(elem);
///     }
/// }
///
/// // and we'll implement FromIterator
/// impl FromIterator<i32> for MyCollection {
///     fn from_iter<I: IntoIterator<Item=i32>>(iter: I) -> Self {
///         let mut c = MyCollection::new();
///
///         for i in iter {
///             c.add(i);
///         }
///
///         c
///     }
/// }
///
/// // Now we can make a new iterator...
/// let iter = (0..5).into_iter();
///
/// // ... and make a MyCollection out of it
/// let c = MyCollection::from_iter(iter);
///
/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]);
///
/// // collect works too!
///
/// let iter = (0..5).into_iter();
/// let c: MyCollection = iter.collect();
///
/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
    message = "a value of type `{Self}` cannot be built from an iterator \
               over elements of type `{A}`",
    label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
)]
pub trait FromIterator<A>: Sized {
    /// Creates a value from an iterator.
    ///
    /// See the [module-level documentation] for more.
    ///
    /// [module-level documentation]: index.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use std::iter::FromIterator;
    ///
    /// let five_fives = std::iter::repeat(5).take(5);
    ///
    /// let v = Vec::from_iter(five_fives);
    ///
    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}

/// Conversion into an `Iterator`.
///
/// By implementing `IntoIterator` for a type, you define how it will be
/// converted to an iterator. This is common for types which describe a
/// collection of some kind.
///
/// One benefit of implementing `IntoIterator` is that your type will [work
/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator).
///
/// See also: [`FromIterator`].
///
/// [`FromIterator`]: trait.FromIterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let v = vec![1, 2, 3];
/// let mut iter = v.into_iter();
///
/// assert_eq!(Some(1), iter.next());
/// assert_eq!(Some(2), iter.next());
/// assert_eq!(Some(3), iter.next());
/// assert_eq!(None, iter.next());
/// ```
/// Implementing `IntoIterator` for your type:
///
/// ```
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
///     fn new() -> MyCollection {
///         MyCollection(Vec::new())
///     }
///
///     fn add(&mut self, elem: i32) {
///         self.0.push(elem);
///     }
/// }
///
/// // and we'll implement IntoIterator
/// impl IntoIterator for MyCollection {
///     type Item = i32;
///     type IntoIter = std::vec::IntoIter<Self::Item>;
///
///     fn into_iter(self) -> Self::IntoIter {
///         self.0.into_iter()
///     }
/// }
///
/// // Now we can make a new collection...
/// let mut c = MyCollection::new();
///
/// // ... add some stuff to it ...
/// c.add(0);
/// c.add(1);
/// c.add(2);
///
/// // ... and then turn it into an Iterator:
/// for (i, n) in c.into_iter().enumerate() {
///     assert_eq!(i as i32, n);
/// }
/// ```
///
/// It is common to use `IntoIterator` as a trait bound. This allows
/// the input collection type to change, so long as it is still an
/// iterator. Additional bounds can be specified by restricting on
/// `Item`:
///
/// ```rust
/// fn collect_as_strings<T>(collection: T) -> Vec<String>
/// where
///     T: IntoIterator,
///     T::Item: std::fmt::Debug,
/// {
///     collection
///         .into_iter()
///         .map(|item| format!("{:?}", item))
///         .collect()
/// }
/// ```
#[rustc_diagnostic_item = "IntoIterator"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
    /// The type of the elements being iterated over.
    #[stable(feature = "rust1", since = "1.0.0")]
    type Item;

    /// Which kind of iterator are we turning this into?
    #[stable(feature = "rust1", since = "1.0.0")]
    type IntoIter: Iterator<Item = Self::Item>;

    /// Creates an iterator from a value.
    ///
    /// See the [module-level documentation] for more.
    ///
    /// [module-level documentation]: index.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let v = vec![1, 2, 3];
    /// let mut iter = v.into_iter();
    ///
    /// assert_eq!(Some(1), iter.next());
    /// assert_eq!(Some(2), iter.next());
    /// assert_eq!(Some(3), iter.next());
    /// assert_eq!(None, iter.next());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into_iter(self) -> Self::IntoIter;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> IntoIterator for I {
    type Item = I::Item;
    type IntoIter = I;

    fn into_iter(self) -> I {
        self
    }
}

/// Extend a collection with the contents of an iterator.
///
/// Iterators produce a series of values, and collections can also be thought
/// of as a series of values. The `Extend` trait bridges this gap, allowing you
/// to extend a collection by including the contents of that iterator. When
/// extending a collection with an already existing key, that entry is updated
/// or, in the case of collections that permit multiple entries with equal
/// keys, that entry is inserted.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// // You can extend a String with some chars:
/// let mut message = String::from("The first three letters are: ");
///
/// message.extend(&['a', 'b', 'c']);
///
/// assert_eq!("abc", &message[29..32]);
/// ```
///
/// Implementing `Extend`:
///
/// ```
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
///     fn new() -> MyCollection {
///         MyCollection(Vec::new())
///     }
///
///     fn add(&mut self, elem: i32) {
///         self.0.push(elem);
///     }
/// }
///
/// // since MyCollection has a list of i32s, we implement Extend for i32
/// impl Extend<i32> for MyCollection {
///
///     // This is a bit simpler with the concrete type signature: we can call
///     // extend on anything which can be turned into an Iterator which gives
///     // us i32s. Because we need i32s to put into MyCollection.
///     fn extend<T: IntoIterator<Item=i32>>(&mut self, iter: T) {
///
///         // The implementation is very straightforward: loop through the
///         // iterator, and add() each element to ourselves.
///         for elem in iter {
///             self.add(elem);
///         }
///     }
/// }
///
/// let mut c = MyCollection::new();
///
/// c.add(5);
/// c.add(6);
/// c.add(7);
///
/// // let's extend our collection with three more numbers
/// c.extend(vec![1, 2, 3]);
///
/// // we've added these elements onto the end
/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Extend<A> {
    /// Extends a collection with the contents of an iterator.
    ///
    /// As this is the only required method for this trait, the [trait-level] docs
    /// contain more details.
    ///
    /// [trait-level]: trait.Extend.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// // You can extend a String with some chars:
    /// let mut message = String::from("abc");
    ///
    /// message.extend(['d', 'e', 'f'].iter());
    ///
    /// assert_eq!("abcdef", &message);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T);

    /// Extends a collection with exactly one element.
    #[unstable(feature = "extend_one", issue = "none")]
    fn extend_one(&mut self, item: A) {
        self.extend(Some(item));
    }

    /// Reserves capacity in a collection for the given number of additional elements.
    ///
    /// The default implementation does nothing.
    #[unstable(feature = "extend_one", issue = "none")]
    fn extend_reserve(&mut self, _additional: usize) {}
}

#[stable(feature = "extend_for_unit", since = "1.28.0")]
impl Extend<()> for () {
    fn extend<T: IntoIterator<Item = ()>>(&mut self, iter: T) {
        iter.into_iter().for_each(drop)
    }
    fn extend_one(&mut self, _item: ()) {}
}
<commit_msg>Use a canonical name for extend_reserve(additional)<commit_after>/// Conversion from an `Iterator`.
///
/// By implementing `FromIterator` for a type, you define how it will be
/// created from an iterator. This is common for types which describe a
/// collection of some kind.
///
/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead
/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s
/// documentation for more examples.
///
/// [`from_iter`]: #tymethod.from_iter
/// [`Iterator`]: trait.Iterator.html
/// [`collect`]: trait.Iterator.html#method.collect
///
/// See also: [`IntoIterator`].
///
/// [`IntoIterator`]: trait.IntoIterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use std::iter::FromIterator;
///
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
///
/// Using [`collect`] to implicitly use `FromIterator`:
///
/// ```
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v: Vec<i32> = five_fives.collect();
///
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
///
/// Implementing `FromIterator` for your type:
///
/// ```
/// use std::iter::FromIterator;
///
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
///     fn new() -> MyCollection {
///         MyCollection(Vec::new())
///     }
///
///     fn add(&mut self, elem: i32) {
///         self.0.push(elem);
///     }
/// }
///
/// // and we'll implement FromIterator
/// impl FromIterator<i32> for MyCollection {
///     fn from_iter<I: IntoIterator<Item=i32>>(iter: I) -> Self {
///         let mut c = MyCollection::new();
///
///         for i in iter {
///             c.add(i);
///         }
///
///         c
///     }
/// }
///
/// // Now we can make a new iterator...
/// let iter = (0..5).into_iter();
///
/// // ... and make a MyCollection out of it
/// let c = MyCollection::from_iter(iter);
///
/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]);
///
/// // collect works too!
///
/// let iter = (0..5).into_iter();
/// let c: MyCollection = iter.collect();
///
/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(
    message = "a value of type `{Self}` cannot be built from an iterator \
               over elements of type `{A}`",
    label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
)]
pub trait FromIterator<A>: Sized {
    /// Creates a value from an iterator.
    ///
    /// See the [module-level documentation] for more.
    ///
    /// [module-level documentation]: index.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use std::iter::FromIterator;
    ///
    /// let five_fives = std::iter::repeat(5).take(5);
    ///
    /// let v = Vec::from_iter(five_fives);
    ///
    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}

/// Conversion into an `Iterator`.
///
/// By implementing `IntoIterator` for a type, you define how it will be
/// converted to an iterator. This is common for types which describe a
/// collection of some kind.
///
/// One benefit of implementing `IntoIterator` is that your type will [work
/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator).
///
/// See also: [`FromIterator`].
///
/// [`FromIterator`]: trait.FromIterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let v = vec![1, 2, 3];
/// let mut iter = v.into_iter();
///
/// assert_eq!(Some(1), iter.next());
/// assert_eq!(Some(2), iter.next());
/// assert_eq!(Some(3), iter.next());
/// assert_eq!(None, iter.next());
/// ```
/// Implementing `IntoIterator` for your type:
///
/// ```
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
///     fn new() -> MyCollection {
///         MyCollection(Vec::new())
///     }
///
///     fn add(&mut self, elem: i32) {
///         self.0.push(elem);
///     }
/// }
///
/// // and we'll implement IntoIterator
/// impl IntoIterator for MyCollection {
///     type Item = i32;
///     type IntoIter = std::vec::IntoIter<Self::Item>;
///
///     fn into_iter(self) -> Self::IntoIter {
///         self.0.into_iter()
///     }
/// }
///
/// // Now we can make a new collection...
/// let mut c = MyCollection::new();
///
/// // ... add some stuff to it ...
/// c.add(0);
/// c.add(1);
/// c.add(2);
///
/// // ... and then turn it into an Iterator:
/// for (i, n) in c.into_iter().enumerate() {
///     assert_eq!(i as i32, n);
/// }
/// ```
///
/// It is common to use `IntoIterator` as a trait bound. This allows
/// the input collection type to change, so long as it is still an
/// iterator. Additional bounds can be specified by restricting on
/// `Item`:
///
/// ```rust
/// fn collect_as_strings<T>(collection: T) -> Vec<String>
/// where
///     T: IntoIterator,
///     T::Item: std::fmt::Debug,
/// {
///     collection
///         .into_iter()
///         .map(|item| format!("{:?}", item))
///         .collect()
/// }
/// ```
#[rustc_diagnostic_item = "IntoIterator"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
    /// The type of the elements being iterated over.
    #[stable(feature = "rust1", since = "1.0.0")]
    type Item;

    /// Which kind of iterator are we turning this into?
    #[stable(feature = "rust1", since = "1.0.0")]
    type IntoIter: Iterator<Item = Self::Item>;

    /// Creates an iterator from a value.
    ///
    /// See the [module-level documentation] for more.
    ///
    /// [module-level documentation]: index.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let v = vec![1, 2, 3];
    /// let mut iter = v.into_iter();
    ///
    /// assert_eq!(Some(1), iter.next());
    /// assert_eq!(Some(2), iter.next());
    /// assert_eq!(Some(3), iter.next());
    /// assert_eq!(None, iter.next());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into_iter(self) -> Self::IntoIter;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> IntoIterator for I {
    type Item = I::Item;
    type IntoIter = I;

    fn into_iter(self) -> I {
        self
    }
}

/// Extend a collection with the contents of an iterator.
///
/// Iterators produce a series of values, and collections can also be thought
/// of as a series of values. The `Extend` trait bridges this gap, allowing you
/// to extend a collection by including the contents of that iterator. When
/// extending a collection with an already existing key, that entry is updated
/// or, in the case of collections that permit multiple entries with equal
/// keys, that entry is inserted.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// // You can extend a String with some chars:
/// let mut message = String::from("The first three letters are: ");
///
/// message.extend(&['a', 'b', 'c']);
///
/// assert_eq!("abc", &message[29..32]);
/// ```
///
/// Implementing `Extend`:
///
/// ```
/// // A sample collection, that's just a wrapper over Vec<T>
/// #[derive(Debug)]
/// struct MyCollection(Vec<i32>);
///
/// // Let's give it some methods so we can create one and add things
/// // to it.
/// impl MyCollection {
///     fn new() -> MyCollection {
///         MyCollection(Vec::new())
///     }
///
///     fn add(&mut self, elem: i32) {
///         self.0.push(elem);
///     }
/// }
///
/// // since MyCollection has a list of i32s, we implement Extend for i32
/// impl Extend<i32> for MyCollection {
///
///     // This is a bit simpler with the concrete type signature: we can call
///     // extend on anything which can be turned into an Iterator which gives
///     // us i32s. Because we need i32s to put into MyCollection.
///     fn extend<T: IntoIterator<Item=i32>>(&mut self, iter: T) {
///
///         // The implementation is very straightforward: loop through the
///         // iterator, and add() each element to ourselves.
///         for elem in iter {
///             self.add(elem);
///         }
///     }
/// }
///
/// let mut c = MyCollection::new();
///
/// c.add(5);
/// c.add(6);
/// c.add(7);
///
/// // let's extend our collection with three more numbers
/// c.extend(vec![1, 2, 3]);
///
/// // we've added these elements onto the end
/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Extend<A> {
    /// Extends a collection with the contents of an iterator.
    ///
    /// As this is the only required method for this trait, the [trait-level] docs
    /// contain more details.
    ///
    /// [trait-level]: trait.Extend.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// // You can extend a String with some chars:
    /// let mut message = String::from("abc");
    ///
    /// message.extend(['d', 'e', 'f'].iter());
    ///
    /// assert_eq!("abcdef", &message);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T);

    /// Extends a collection with exactly one element.
    #[unstable(feature = "extend_one", issue = "none")]
    fn extend_one(&mut self, item: A) {
        self.extend(Some(item));
    }

    /// Reserves capacity in a collection for the given number of additional elements.
    ///
    /// The default implementation does nothing.
    #[unstable(feature = "extend_one", issue = "none")]
    fn extend_reserve(&mut self, additional: usize) {
        let _ = additional;
    }
}

#[stable(feature = "extend_for_unit", since = "1.28.0")]
impl Extend<()> for () {
    fn extend<T: IntoIterator<Item = ()>>(&mut self, iter: T) {
        iter.into_iter().for_each(drop)
    }
    fn extend_one(&mut self, _item: ()) {}
}
<|endoftext|>


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

#![allow(non_camel_case_types)]

pub use self::FileMatch::*;

use std::borrow::Cow;
use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use session::search_paths::{SearchPaths, PathKind};
use util::fs as rustcfs;

#[derive(Copy, Clone)]
pub enum FileMatch {
    FileMatches,
    FileDoesntMatch,
}

// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.

pub struct FileSearch<'a> {
    pub sysroot: &'a Path,
    pub search_paths: &'a SearchPaths,
    pub triple: &'a str,
    pub kind: PathKind,
}

impl<'a> FileSearch<'a> {
    pub fn for_each_lib_search_path<F>(&self, mut f: F) where
        F: FnMut(&Path, PathKind)
    {
        let mut visited_dirs = HashSet::new();

        for (path, kind) in self.search_paths.iter(self.kind) {
            f(path, kind);
            visited_dirs.insert(path.to_path_buf());
        }

        debug!("filesearch: searching lib path");
        let tlib_path = make_target_lib_path(self.sysroot,
                                             self.triple);
        if !visited_dirs.contains(&tlib_path) {
            f(&tlib_path, PathKind::All);
        }

        visited_dirs.insert(tlib_path);
    }

    pub fn get_lib_path(&self) -> PathBuf {
        make_target_lib_path(self.sysroot, self.triple)
    }

    pub fn search<F>(&self, mut pick: F)
        where F: FnMut(&Path, PathKind) -> FileMatch
    {
        self.for_each_lib_search_path(|lib_search_path, kind| {
            debug!("searching {}", lib_search_path.display());
            match fs::read_dir(lib_search_path) {
                Ok(files) => {
                    let files = files.filter_map(|p| p.ok().map(|s| s.path()))
                                     .collect::<Vec<_>>();
                    fn is_rlib(p: &Path) -> bool {
                        p.extension().and_then(|s| s.to_str()) == Some("rlib")
                    }
                    // Reading metadata out of rlibs is faster, and if we find both
                    // an rlib and a dylib we only read one of the files of
                    // metadata, so in the name of speed, bring all rlib files to
                    // the front of the search list.
                    let files1 = files.iter().filter(|p| is_rlib(p));
                    let files2 = files.iter().filter(|p| !is_rlib(p));
                    for path in files1.chain(files2) {
                        debug!("testing {}", path.display());
                        let maybe_picked = pick(path, kind);
                        match maybe_picked {
                            FileMatches => {
                                debug!("picked {}", path.display());
                            }
                            FileDoesntMatch => {
                                debug!("rejected {}", path.display());
                            }
                        }
                    }
                }
                Err(..) => (),
            }
        });
    }

    pub fn new(sysroot: &'a Path,
               triple: &'a str,
               search_paths: &'a SearchPaths,
               kind: PathKind) -> FileSearch<'a> {
        debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
        FileSearch {
            sysroot: sysroot,
            search_paths: search_paths,
            triple: triple,
            kind: kind,
        }
    }

    // Returns a list of directories where target-specific dylibs might be located.
    pub fn get_dylib_search_paths(&self) -> Vec<PathBuf> {
        let mut paths = Vec::new();
        self.for_each_lib_search_path(|lib_search_path, _| {
            paths.push(lib_search_path.to_path_buf());
        });
        paths
    }

    // Returns a list of directories where target-specific tool binaries are located.
    pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
        let mut p = PathBuf::from(self.sysroot);
        p.push(find_libdir(self.sysroot).as_ref());
        p.push(RUST_LIB_DIR);
        p.push(&self.triple);
        p.push("bin");
        vec![p]
    }
}

pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
    let mut p = PathBuf::from(find_libdir(sysroot).as_ref());
    assert!(p.is_relative());
    p.push(RUST_LIB_DIR);
    p.push(target_triple);
    p.push("lib");
    p
}

fn make_target_lib_path(sysroot: &Path,
                        target_triple: &str) -> PathBuf {
    sysroot.join(&relative_target_lib_path(sysroot, target_triple))
}

pub fn get_or_default_sysroot() -> PathBuf {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: Option<PathBuf>) -> Option<PathBuf> {
        path.and_then(|path| {
            match fs::canonicalize(&path) {
                // See comments on this target function, but the gist is that
                // gcc chokes on verbatim paths which fs::canonicalize generates
                // so we try to avoid those kinds of paths.
                Ok(canon) => Some(rustcfs::fix_windows_verbatim_for_gcc(&canon)),
                Err(e) => bug!("failed to get realpath: {}", e),
            }
        })
    }

    match canonicalize(env::current_exe().ok()) {
        Some(mut p) => { p.pop(); p.pop(); p }
        None => bug!("can't determine value for sysroot")
    }
}

// The name of the directory rustc expects libraries to be located.
fn find_libdir(sysroot: &Path) -> Cow<'static, str> {
    // FIXME: This is a quick hack to make the rustc binary able to locate
    // Rust libraries in Linux environments where libraries might be installed
    // to lib64/lib32. This would be more foolproof by basing the sysroot off
    // of the directory where librustc is located, rather than where the rustc
    // binary is.
    //If --libdir is set during configuration to the value other than
    // "lib" (i.e. non-default), this value is used (see issue #16552).

    match option_env!("CFG_LIBDIR_RELATIVE") {
        Some(libdir) if libdir != "lib" => return libdir.into(),
        _ => if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() {
            return PRIMARY_LIB_DIR.into();
        } else {
            return SECONDARY_LIB_DIR.into();
        }
    }

    #[cfg(target_pointer_width = "64")]
    const PRIMARY_LIB_DIR: &'static str = "lib64";

    #[cfg(target_pointer_width = "32")]
    const PRIMARY_LIB_DIR: &'static str = "lib32";

    const SECONDARY_LIB_DIR: &'static str = "lib";
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
const RUST_LIB_DIR: &'static str = "rustlib";
<commit_msg>Return early to avoid excessive indentation.`<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_camel_case_types)]

pub use self::FileMatch::*;

use std::borrow::Cow;
use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use session::search_paths::{SearchPaths, PathKind};
use util::fs as rustcfs;

#[derive(Copy, Clone)]
pub enum FileMatch {
    FileMatches,
    FileDoesntMatch,
}

// A module for searching for libraries
// FIXME (#2658): I'm not happy how this module turned out. Should
// probably just be folded into cstore.

pub struct FileSearch<'a> {
    pub sysroot: &'a Path,
    pub search_paths: &'a SearchPaths,
    pub triple: &'a str,
    pub kind: PathKind,
}

impl<'a> FileSearch<'a> {
    pub fn for_each_lib_search_path<F>(&self, mut f: F) where
        F: FnMut(&Path, PathKind)
    {
        let mut visited_dirs = HashSet::new();

        for (path, kind) in self.search_paths.iter(self.kind) {
            f(path, kind);
            visited_dirs.insert(path.to_path_buf());
        }

        debug!("filesearch: searching lib path");
        let tlib_path = make_target_lib_path(self.sysroot,
                                             self.triple);
        if !visited_dirs.contains(&tlib_path) {
            f(&tlib_path, PathKind::All);
        }

        visited_dirs.insert(tlib_path);
    }

    pub fn get_lib_path(&self) -> PathBuf {
        make_target_lib_path(self.sysroot, self.triple)
    }

    pub fn search<F>(&self, mut pick: F)
        where F: FnMut(&Path, PathKind) -> FileMatch
    {
        self.for_each_lib_search_path(|lib_search_path, kind| {
            debug!("searching {}", lib_search_path.display());
            let files = match fs::read_dir(lib_search_path) {
                Ok(files) => files,
                Err(..) => return,
            };
            let files = files.filter_map(|p| p.ok().map(|s| s.path()))
                             .collect::<Vec<_>>();
            fn is_rlib(p: &Path) -> bool {
                p.extension().and_then(|s| s.to_str()) == Some("rlib")
            }
            // Reading metadata out of rlibs is faster, and if we find both
            // an rlib and a dylib we only read one of the files of
            // metadata, so in the name of speed, bring all rlib files to
            // the front of the search list.
            let files1 = files.iter().filter(|p| is_rlib(p));
            let files2 = files.iter().filter(|p| !is_rlib(p));
            for path in files1.chain(files2) {
                debug!("testing {}", path.display());
                let maybe_picked = pick(path, kind);
                match maybe_picked {
                    FileMatches => {
                        debug!("picked {}", path.display());
                    }
                    FileDoesntMatch => {
                        debug!("rejected {}", path.display());
                    }
                }
            }
        });
    }

    pub fn new(sysroot: &'a Path,
               triple: &'a str,
               search_paths: &'a SearchPaths,
               kind: PathKind) -> FileSearch<'a> {
        debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
        FileSearch {
            sysroot: sysroot,
            search_paths: search_paths,
            triple: triple,
            kind: kind,
        }
    }

    // Returns a list of directories where target-specific dylibs might be located.
    pub fn get_dylib_search_paths(&self) -> Vec<PathBuf> {
        let mut paths = Vec::new();
        self.for_each_lib_search_path(|lib_search_path, _| {
            paths.push(lib_search_path.to_path_buf());
        });
        paths
    }

    // Returns a list of directories where target-specific tool binaries are located.
    pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
        let mut p = PathBuf::from(self.sysroot);
        p.push(find_libdir(self.sysroot).as_ref());
        p.push(RUST_LIB_DIR);
        p.push(&self.triple);
        p.push("bin");
        vec![p]
    }
}

pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
    let mut p = PathBuf::from(find_libdir(sysroot).as_ref());
    assert!(p.is_relative());
    p.push(RUST_LIB_DIR);
    p.push(target_triple);
    p.push("lib");
    p
}

fn make_target_lib_path(sysroot: &Path,
                        target_triple: &str) -> PathBuf {
    sysroot.join(&relative_target_lib_path(sysroot, target_triple))
}

pub fn get_or_default_sysroot() -> PathBuf {
    // Follow symlinks.  If the resolved path is relative, make it absolute.
    fn canonicalize(path: Option<PathBuf>) -> Option<PathBuf> {
        path.and_then(|path| {
            match fs::canonicalize(&path) {
                // See comments on this target function, but the gist is that
                // gcc chokes on verbatim paths which fs::canonicalize generates
                // so we try to avoid those kinds of paths.
                Ok(canon) => Some(rustcfs::fix_windows_verbatim_for_gcc(&canon)),
                Err(e) => bug!("failed to get realpath: {}", e),
            }
        })
    }

    match canonicalize(env::current_exe().ok()) {
        Some(mut p) => { p.pop(); p.pop(); p }
        None => bug!("can't determine value for sysroot")
    }
}

// The name of the directory rustc expects libraries to be located.
fn find_libdir(sysroot: &Path) -> Cow<'static, str> {
    // FIXME: This is a quick hack to make the rustc binary able to locate
    // Rust libraries in Linux environments where libraries might be installed
    // to lib64/lib32. This would be more foolproof by basing the sysroot off
    // of the directory where librustc is located, rather than where the rustc
    // binary is.
    //If --libdir is set during configuration to the value other than
    // "lib" (i.e. non-default), this value is used (see issue #16552).

    match option_env!("CFG_LIBDIR_RELATIVE") {
        Some(libdir) if libdir != "lib" => return libdir.into(),
        _ => if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() {
            return PRIMARY_LIB_DIR.into();
        } else {
            return SECONDARY_LIB_DIR.into();
        }
    }

    #[cfg(target_pointer_width = "64")]
    const PRIMARY_LIB_DIR: &'static str = "lib64";

    #[cfg(target_pointer_width = "32")]
    const PRIMARY_LIB_DIR: &'static str = "lib32";

    const SECONDARY_LIB_DIR: &'static str = "lib";
}

// The name of rustc's own place to organize libraries.
// Used to be "rustc", now the default is "rustlib"
const RUST_LIB_DIR: &'static str = "rustlib";
<|endoftext|>