<commit_before>use std::collections::{BTreeMap, BTreeSet};

use anyhow::Result;
use log::debug;

use crate::{
    analysis::{cfg, dis},
    aspace::AddressSpace,
    module::Module,
    RVA, VA,
};

#[derive(Default)]
pub struct CallGraph {
    // call instruction indexes...
    /// map from function start to the addresses that call here.
    /// lookup via `call_instruction_functions` to figure out the functions that
    /// call here.
    pub calls_to:   BTreeMap<VA, Vec<VA>>,
    /// map from an instruction to the addresses that it calls (usually one).
    pub calls_from: BTreeMap<VA, Vec<VA>>,

    // instruction membership indexes...
    /// map from function start to the instructions in its CFG that call
    /// elsewhere. lookup via `calls_to` to figoure out the functions that
    /// this function calls.
    pub function_call_instructions: BTreeMap<VA, Vec<VA>>,
    /// map from instruction to starts of functions whose CFGs contain the
    /// instruction (usually one).
    pub call_instruction_functions: BTreeMap<VA, Vec<VA>>,
}

pub fn get_call_import_xref(imports: &BTreeSet<VA>, va: VA, insn: &zydis::DecodedInstruction) -> Option<VA> {
    assert!(matches!(insn.mnemonic, zydis::enums::Mnemonic::CALL));

    // calls always have a first operand
    let op = crate::analysis::cfg::get_first_operand(insn).unwrap();

    if !matches!(op.ty, zydis::OperandType::MEMORY) {
        // doesn't look like `call [...]`
        return None;
    }

    if let Ok(Some(ptr)) = crate::analysis::cfg::get_memory_operand_ptr(va, insn, op) {
        if imports.contains(&ptr) {
            Some(ptr)
        } else {
            None
        }
    } else {
        None
    }
}

pub fn build_call_graph(module: &Module, cfgs: &BTreeMap<VA, cfg::CFG>, imports: &BTreeSet<VA>) -> Result<CallGraph> {
    debug!("call graph");

    let mut cg: CallGraph = Default::default();
    let decoder = dis::get_disassembler(module)?;

    for &import in imports.iter() {
        cg.calls_to.entry(import).or_default();
    }

    for (&function, cfg) in cfgs.iter() {
        debug!("call graph: {:#x}", function);

        // ensure there are at least (empty) entries for all the keys in `functions`
        cg.function_call_instructions.entry(function).or_default();
        cg.calls_to.entry(function).or_default();

        for basic_block in cfg.basic_blocks.values() {
            let buf = module
                .address_space
                .read_bytes(basic_block.address, basic_block.length as usize)?;

            for (offset, insn) in dis::linear_disassemble(&decoder, &buf) {
                if let Ok(Some(insn)) = insn {
                    if matches!(insn.mnemonic, zydis::enums::Mnemonic::CALL) {
                        let va = basic_block.address + offset as RVA;
                        cg.function_call_instructions.entry(function).or_default().push(va);
                        cg.call_instruction_functions.entry(va).or_default().push(function);

                        if let Some(import) = get_call_import_xref(imports, va, &insn) {
                            cg.calls_from.entry(va).or_default().push(import);
                            cg.calls_to.entry(import).or_default().push(va);
                        } else {
                            for flow in cfg::get_call_insn_flow(module, va, &insn)?.iter() {
                                if let cfg::Flow::Call(target) = *flow {
                                    cg.calls_from.entry(va).or_default().push(target);
                                    cg.calls_to.entry(target).or_default().push(va);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    Ok(cg)
}

#[cfg(test)]
mod tests {
    use crate::{
        analysis::{call_graph, cfg::CFG, pe},
        rsrc::*,
        VA,
    };
    use anyhow::Result;
    use std::collections::{BTreeMap, BTreeSet};

    #[test]
    fn k32() -> Result<()> {
        let buf = get_buf(Rsrc::K32);
        let pe = crate::loader::pe::PE::from_bytes(&buf)?;
        let imports: BTreeSet<VA> = crate::analysis::pe::get_imports(&pe)?.keys().cloned().collect();

        let mut cfgs: BTreeMap<VA, CFG> = Default::default();
        for &function in pe::find_function_starts(&pe)?.iter() {
            if let Ok(cfg) = crate::analysis::cfg::build_cfg(&pe.module, function) {
                cfgs.insert(function, cfg);
            }
        }

        let cg = call_graph::build_call_graph(&pe.module, &cfgs, &imports)?;

        assert_eq!(cg.calls_to[&0x180001068].len(), 2);
        assert!(cg.calls_to[&0x180001068].iter().find(|&&v| v == 0x18000F775).is_some());
        assert!(cg.calls_to[&0x180001068].iter().find(|&&v| v == 0x180060504).is_some());
        assert!(cg.calls_from[&0x180060504]
            .iter()
            .find(|&&v| v == 0x180001068)
            .is_some());
        assert!(cg.call_instruction_functions[&0x180060504]
            .iter()
            .find(|&&v| v == 0x1800602C0)
            .is_some());
        assert!(cg.function_call_instructions[&0x1800602C0]
            .iter()
            .find(|&&v| v == 0x180060504)
            .is_some());

        // ```
        // .text:00000001800134D0 sub_1800134D0 proc near
        // .text:...
        // .text:00000001800134D4 call    cs:KernelBaseGetGlobalData
        // ```
        //
        // this should result in a call flow to IAT entry 0x1800773F0
        #[allow(non_snake_case)]
        let KernelBaseGetGlobalData = 0x1800773F0;
        assert!(cg.function_call_instructions[&0x1800134D0]
            .iter()
            .find(|&&v| v == 0x1800134D4)
            .is_some());
        assert!(cg.calls_from[&0x1800134D4]
            .iter()
            .find(|&&v| v == KernelBaseGetGlobalData)
            .is_some());
        assert!(cg.calls_to[&KernelBaseGetGlobalData]
            .iter()
            .find(|&&v| v == 0x1800134D4)
            .is_some());

        Ok(())
    }

    #[test]
    fn mimi() -> Result<()> {
        let buf = get_buf(Rsrc::MIMI);
        let pe = crate::loader::pe::PE::from_bytes(&buf)?;
        let imports: BTreeSet<VA> = crate::analysis::pe::get_imports(&pe)?.keys().cloned().collect();

        let mut cfgs: BTreeMap<VA, CFG> = Default::default();
        for &function in pe::find_function_starts(&pe)?.iter() {
            if let Ok(cfg) = crate::analysis::cfg::build_cfg(&pe.module, function) {
                cfgs.insert(function, cfg);
            }
        }

        let cg = call_graph::build_call_graph(&pe.module, &cfgs, &imports)?;

        assert!(cg.function_call_instructions.get(&0x45CC62).is_some());
        assert!(cg.function_call_instructions.get(&0x45D028).is_some());
        assert!(cg.function_call_instructions.get(&0x45D16A).is_some());

        assert_eq!(cg.calls_to[&0x40B1F1].len(), 3);

        assert!(cg.calls_to[&0x40B1F1].iter().find(|&&v| v == 0x45CC9D).is_some());
        assert!(cg.calls_to[&0x40B1F1].iter().find(|&&v| v == 0x45D080).is_some());
        assert!(cg.calls_to[&0x40B1F1].iter().find(|&&v| v == 0x45D1B7).is_some());

        Ok(())
    }
}
<commit_msg>call graph: add some doc<commit_after>use std::collections::{BTreeMap, BTreeSet};

use anyhow::Result;
use log::debug;

use crate::{
    analysis::{cfg, dis},
    aspace::AddressSpace,
    module::Module,
    RVA, VA,
};

#[derive(Default)]
pub struct CallGraph {
    // call instruction indexes...
    /// map from function start to the addresses that call here.
    /// lookup via `call_instruction_functions` to figure out the functions that
    /// call here.
    pub calls_to:   BTreeMap<VA, Vec<VA>>,
    /// map from an instruction to the addresses that it calls (usually one).
    pub calls_from: BTreeMap<VA, Vec<VA>>,

    // instruction membership indexes...
    /// map from function start to the instructions in its CFG that call
    /// elsewhere. lookup via `calls_to` to figoure out the functions that
    /// this function calls.
    pub function_call_instructions: BTreeMap<VA, Vec<VA>>,
    /// map from instruction to starts of functions whose CFGs contain the
    /// instruction (usually one).
    pub call_instruction_functions: BTreeMap<VA, Vec<VA>>,
}

pub fn get_call_import_xref(imports: &BTreeSet<VA>, va: VA, insn: &zydis::DecodedInstruction) -> Option<VA> {
    assert!(matches!(insn.mnemonic, zydis::enums::Mnemonic::CALL));

    // calls always have a first operand
    let op = crate::analysis::cfg::get_first_operand(insn).unwrap();

    if !matches!(op.ty, zydis::OperandType::MEMORY) {
        // doesn't look like `call [...]`
        return None;
    }

    if let Ok(Some(ptr)) = crate::analysis::cfg::get_memory_operand_ptr(va, insn, op) {
        if imports.contains(&ptr) {
            Some(ptr)
        } else {
            None
        }
    } else {
        None
    }
}

// provide `imports` if you've done analysis of the module to find
// the pointers used in the import table.
// when provided, will extract the call edges to the import pointers.
// otherwise, the call to/from import edges won't be indexed.
pub fn build_call_graph(module: &Module, cfgs: &BTreeMap<VA, cfg::CFG>, imports: &BTreeSet<VA>) -> Result<CallGraph> {
    debug!("call graph");

    let mut cg: CallGraph = Default::default();
    let decoder = dis::get_disassembler(module)?;

    for &import in imports.iter() {
        cg.calls_to.entry(import).or_default();
    }

    for (&function, cfg) in cfgs.iter() {
        debug!("call graph: {:#x}", function);

        // ensure there are at least (empty) entries for all the keys in `functions`
        cg.function_call_instructions.entry(function).or_default();
        cg.calls_to.entry(function).or_default();

        for basic_block in cfg.basic_blocks.values() {
            let buf = module
                .address_space
                .read_bytes(basic_block.address, basic_block.length as usize)?;

            for (offset, insn) in dis::linear_disassemble(&decoder, &buf) {
                if let Ok(Some(insn)) = insn {
                    if matches!(insn.mnemonic, zydis::enums::Mnemonic::CALL) {
                        let va = basic_block.address + offset as RVA;
                        cg.function_call_instructions.entry(function).or_default().push(va);
                        cg.call_instruction_functions.entry(va).or_default().push(function);

                        if let Some(import) = get_call_import_xref(imports, va, &insn) {
                            cg.calls_from.entry(va).or_default().push(import);
                            cg.calls_to.entry(import).or_default().push(va);
                        } else {
                            for flow in cfg::get_call_insn_flow(module, va, &insn)?.iter() {
                                if let cfg::Flow::Call(target) = *flow {
                                    cg.calls_from.entry(va).or_default().push(target);
                                    cg.calls_to.entry(target).or_default().push(va);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    Ok(cg)
}

#[cfg(test)]
mod tests {
    use crate::{
        analysis::{call_graph, cfg::CFG, pe},
        rsrc::*,
        VA,
    };
    use anyhow::Result;
    use std::collections::{BTreeMap, BTreeSet};

    #[test]
    fn k32() -> Result<()> {
        let buf = get_buf(Rsrc::K32);
        let pe = crate::loader::pe::PE::from_bytes(&buf)?;
        let imports: BTreeSet<VA> = crate::analysis::pe::get_imports(&pe)?.keys().cloned().collect();

        let mut cfgs: BTreeMap<VA, CFG> = Default::default();
        for &function in pe::find_function_starts(&pe)?.iter() {
            if let Ok(cfg) = crate::analysis::cfg::build_cfg(&pe.module, function) {
                cfgs.insert(function, cfg);
            }
        }

        let cg = call_graph::build_call_graph(&pe.module, &cfgs, &imports)?;

        assert_eq!(cg.calls_to[&0x180001068].len(), 2);
        assert!(cg.calls_to[&0x180001068].iter().find(|&&v| v == 0x18000F775).is_some());
        assert!(cg.calls_to[&0x180001068].iter().find(|&&v| v == 0x180060504).is_some());
        assert!(cg.calls_from[&0x180060504]
            .iter()
            .find(|&&v| v == 0x180001068)
            .is_some());
        assert!(cg.call_instruction_functions[&0x180060504]
            .iter()
            .find(|&&v| v == 0x1800602C0)
            .is_some());
        assert!(cg.function_call_instructions[&0x1800602C0]
            .iter()
            .find(|&&v| v == 0x180060504)
            .is_some());

        // ```
        // .text:00000001800134D0 sub_1800134D0 proc near
        // .text:...
        // .text:00000001800134D4 call    cs:KernelBaseGetGlobalData
        // ```
        //
        // this should result in a call flow to IAT entry 0x1800773F0
        #[allow(non_snake_case)]
        let KernelBaseGetGlobalData = 0x1800773F0;
        assert!(cg.function_call_instructions[&0x1800134D0]
            .iter()
            .find(|&&v| v == 0x1800134D4)
            .is_some());
        assert!(cg.calls_from[&0x1800134D4]
            .iter()
            .find(|&&v| v == KernelBaseGetGlobalData)
            .is_some());
        assert!(cg.calls_to[&KernelBaseGetGlobalData]
            .iter()
            .find(|&&v| v == 0x1800134D4)
            .is_some());

        Ok(())
    }

    #[test]
    fn mimi() -> Result<()> {
        let buf = get_buf(Rsrc::MIMI);
        let pe = crate::loader::pe::PE::from_bytes(&buf)?;
        let imports: BTreeSet<VA> = crate::analysis::pe::get_imports(&pe)?.keys().cloned().collect();

        let mut cfgs: BTreeMap<VA, CFG> = Default::default();
        for &function in pe::find_function_starts(&pe)?.iter() {
            if let Ok(cfg) = crate::analysis::cfg::build_cfg(&pe.module, function) {
                cfgs.insert(function, cfg);
            }
        }

        let cg = call_graph::build_call_graph(&pe.module, &cfgs, &imports)?;

        assert!(cg.function_call_instructions.get(&0x45CC62).is_some());
        assert!(cg.function_call_instructions.get(&0x45D028).is_some());
        assert!(cg.function_call_instructions.get(&0x45D16A).is_some());

        assert_eq!(cg.calls_to[&0x40B1F1].len(), 3);

        assert!(cg.calls_to[&0x40B1F1].iter().find(|&&v| v == 0x45CC9D).is_some());
        assert!(cg.calls_to[&0x40B1F1].iter().find(|&&v| v == 0x45D080).is_some());
        assert!(cg.calls_to[&0x40B1F1].iter().find(|&&v| v == 0x45D1B7).is_some());

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    collections::HashSet,
};

use crate::{prelude::*, utils::SelectionMode as SelMode};

use super::behaviors::{MouseBehavior, SelectionBehavior};

static CONTAINER: &'static str = "container";
static ITEMS_PANEL: &'static str = "items_panel";

type SelectedItem = Option<Entity>;

#[derive(Default, AsAny)]
pub struct ComboBoxItemState {
    request_selection_toggle: Cell<bool>,
    selected_container: Entity,
    combo_box: Entity,
    builder: WidgetBuildContext,
}

impl ComboBoxItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ComboBoxItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        // let selected = *ctx.widget().get::<bool>("selected");

        let entity = ctx.entity;
        let index: u32 = *ctx.widget().get("index");

        // unselect previous selected item.
        if let Some(item) = ctx
            .get_widget(self.combo_box)
            .clone::<SelectedItem>("selected_item")
        {
            ctx.get_widget(item).set("selected", false);
            ctx.get_widget(item).update_theme_by_state(false);
        }

        ctx.widget().set("selected", true);
        ctx.widget().update_theme_by_state(false);
        ctx.get_widget(self.combo_box)
            .set("selected_index", index as i32);
        ctx.get_widget(self.combo_box)
            .set("selected_item", Some(entity));
        // let index = ctx.index_as_child(entity).unwrap();

        // if let Some(parent) = &mut ctx.get_widget(self.combo_box) {
        //     // let selection_mode = *parent.get::<SelectionMode>("selection_mode");
        //     // deselect item
        //     if selected {
        //         // parent
        //         //     .get_mut::<SelectedEntities>("selected_entities")
        //         //     .0
        //         //     .remove(&entity);
        //         // parent
        //         //     .get_mut::<SelectedIndices>("selected_indices")
        //         //     .0
        //         //     .remove(&index);
        //         return;
        //     }

        //     // if parent
        //     //     .get::<SelectedEntities>("selected_entities")
        //     //     .0
        //     //     .contains(&entity)
        //     //     || selection_mode == SelMode::None
        //     // {
        //     //     return;
        //     // }

        //     // if selection_mode == SelMode::Single {
        //     //     parent
        //     //         .get_mut::<SelectedEntities>("selected_entities")
        //     //         .0
        //     //         .clear();
        //     //     parent
        //     //         .get_mut::<SelectedIndices>("selected_indices")
        //     //         .0
        //     //         .clear();
        //     // }

        //     // parent
        //     //     .get_mut::<SelectedEntities>("selected_entities")
        //     //     .0
        //     //     .insert(entity);
        //     // parent
        //     //     .get_mut::<SelectedIndices>("selected_indices")
        //     //     .0
        //     //     .insert(index);
        // }
    }
}

widget!(
    ComboBoxItem<ComboBoxItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the css selector property.
        selector: Selector,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool,

        /// Sets or shares the index inside of the combobox item collection.
        index: u32
    }
);

impl ComboBoxItem {
    fn selected_container(mut self, selected_container: impl Into<Entity>) -> Self {
        self.state_mut().selected_container = selected_container.into();
        self
    }

    fn combo_box(mut self, combo_box: impl Into<Entity>) -> Self {
        self.state_mut().combo_box = combo_box.into();
        self
    }

    // Define the template build function for the selected content of the ComboBoxItems.
    fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Box::new(builder));
        self
    }
}

impl Template for ComboBoxItem {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("ComboBoxItem")
            .min_width(64.0)
            .height(24.0)
            .selected(false)
            .pressed(false)
            .selector("list-view-item")
            .padding(0.0)
            .background("transparent")
            .border_radius(0.0)
            .border_width(0.0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32.0)
            .font("Roboto Regular")
            .on_click(move |states, _| {
                states.get::<ComboBoxItemState>(id).toggle_selection();
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

/// The `ComboBoxState` is used to manipulate the position of the thumb of the slider widget.
#[derive(Default, AsAny)]
pub struct ComboBoxState {
    builder: WidgetBuildContext,
    count: usize,
    items_panel: Entity,
    selected_container: Entity,
}

impl State for ComboBoxState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder(build_context, i);
                        let item = ComboBoxItem::create()
                            .index(i as u32)
                            .combo_box(entity)
                            .selected_container(self.selected_container);

                        // if let Some(builder) = self.builder {
                        //     item.items_builder((*builder).clone());
                        // }

                        let item = item.build(build_context);

                        let mouse_behavior = MouseBehavior::create().build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_properties_by_theme();
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        // for index in ctx
        //     .widget()
        //     .get::<SelectedEntities>("selected_entities")
        //     .0
        //     .clone()
        //     .symmetric_difference(&*self.selected_entities.borrow())
        // {
        //     let mut widget = ctx.get_widget(*index);
        //     widget.set("selected", !widget.get::<bool>("selected"));

        //     widget.update_theme_by_state(false);
        // }

        // *self.selected_entities.borrow_mut() = ctx
        //     .widget()
        //     .get::<SelectedEntities>("selected_entities")
        //     .0
        //     .clone();
    }
}

// todo use code of list view item, by create combobox item insert entity of popup container

widget!(
    /// The `ComboBox` represents an selection widget with a drop-down list.
    ///
    /// **CSS element:** `ComboBox`
    ComboBox<ComboBoxState>: MouseHandler, ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shared the count.
        count: usize,

        /// Sets or shares the css selector property.
        selector: Selector,

        /// Sets or shares the selected index. If the value is -1 no item is selected.
        selected_index: i32,

        /// The entity of the selected item.
        selected_item: SelectedItem,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the flag if the drop down is open.
        selected: bool
    }
);

impl ComboBox {
    /// Define the template build function for the content of the ComboBoxItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Box::new(builder));
        self
    }
}

impl Template for ComboBox {
    fn template(mut self, id: Entity, ctx: &mut BuildContext) -> Self {
        let container = Container::create()
            .selector(Selector::default().id(CONTAINER))
            .background(id)
            .border_radius(id)
            .border_width(id)
            .border_brush(id)
            .padding(id)
            .build(ctx);
        self.state_mut().selected_container = container;

        let items_panel = Stack::create()
            .vertical_alignment("start")
            .selector(Selector::default().id(ITEMS_PANEL))
            .orientation("vertical")
            .build(ctx);

        self.state_mut().items_panel = items_panel;
        let scroll_viewer = ScrollViewer::create()
            .scroll_viewer_mode(("disabled", "auto"))
            .child(items_panel)
            .build(ctx);

        let popup = Popup::create()
            .height(200.0)
            .open(("selected", id))
            .child(scroll_viewer)
            .child(
                ScrollIndicator::create()
                    .padding(2.0)
                    .content_id(items_panel.0)
                    .scroll_offset(scroll_viewer)
                    .opacity(id)
                    .build(ctx),
            )
            .target(container.0)
            .build(ctx);

        let _ = ctx.append_child_to_overlay(popup);

        self.name("ComboBox")
            .selector("combo_box")
            .height(32.0)
            .min_width(80.0)
            .selected(false)
            .selected_index(-1)
            .child(
                MouseBehavior::create()
                    .pressed(id)
                    .enabled(id)
                    .selector(id)
                    .child(
                        SelectionBehavior::create()
                            .selected(id)
                            .enabled(id)
                            .selector(id)
                            .parent(id.0)
                            .child(container)
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}
<commit_msg>Add selected content to container.<commit_after>use std::{
    sync::Arc,
    cell::{Cell, RefCell},
    collections::HashSet,
};

use crate::{prelude::*, utils::SelectionMode as SelMode};

use super::behaviors::{MouseBehavior, SelectionBehavior};

static CONTAINER: &'static str = "container";
static ITEMS_PANEL: &'static str = "items_panel";

type SelectedItem = Option<Entity>;

#[derive(Default, AsAny)]
pub struct ComboBoxItemState {
    request_selection_toggle: Cell<bool>,
    index: usize,
    selected_container: Entity,
    combo_box: Entity,
    // ugly work around for item builder context clone, todo make it better 😉
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
}

impl ComboBoxItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ComboBoxItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        // let selected = *ctx.widget().get::<bool>("selected");

        let entity = ctx.entity;

        // unselect previous selected item.
        if let Some(item) = ctx
            .get_widget(self.combo_box)
            .clone::<SelectedItem>("selected_item")
        {
            ctx.get_widget(item).set("selected", false);
            ctx.get_widget(item).update_theme_by_state(false);
        }

        ctx.widget().set("selected", true);
        ctx.widget().update_theme_by_state(false);
        ctx.get_widget(self.combo_box)
            .set("selected_index", self.index as i32);
        ctx.get_widget(self.combo_box)
            .set("selected_item", Some(entity));

        // Add selected content to combobox
        let index = self.index;
        let selected_container = self.selected_container;
        if let Some(builder) = &self.builder {
            ctx.clear_children_of(selected_container);
            let build_context = &mut ctx.build_context();
            let selected_content = builder.borrow()(build_context, index);
            build_context.append_child(selected_container, selected_content);
        }

        // ctx.get_widget(&self.selected_container.into())
        // let index = ctx.index_as_child(entity).unwrap();

        // if let Some(parent) = &mut ctx.get_widget(self.combo_box) {
        //     // let selection_mode = *parent.get::<SelectionMode>("selection_mode");
        //     // deselect item
        //     if selected {
        //         // parent
        //         //     .get_mut::<SelectedEntities>("selected_entities")
        //         //     .0
        //         //     .remove(&entity);
        //         // parent
        //         //     .get_mut::<SelectedIndices>("selected_indices")
        //         //     .0
        //         //     .remove(&index);
        //         return;
        //     }

        //     // if parent
        //     //     .get::<SelectedEntities>("selected_entities")
        //     //     .0
        //     //     .contains(&entity)
        //     //     || selection_mode == SelMode::None
        //     // {
        //     //     return;
        //     // }

        //     // if selection_mode == SelMode::Single {
        //     //     parent
        //     //         .get_mut::<SelectedEntities>("selected_entities")
        //     //         .0
        //     //         .clear();
        //     //     parent
        //     //         .get_mut::<SelectedIndices>("selected_indices")
        //     //         .0
        //     //         .clear();
        //     // }

        //     // parent
        //     //     .get_mut::<SelectedEntities>("selected_entities")
        //     //     .0
        //     //     .insert(entity);
        //     // parent
        //     //     .get_mut::<SelectedIndices>("selected_indices")
        //     //     .0
        //     //     .insert(index);
        // }
    }
}

widget!(
    ComboBoxItem<ComboBoxItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the css selector property.
        selector: Selector,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl ComboBoxItem {
    fn selected_container(mut self, selected_container: impl Into<Entity>) -> Self {
        self.state_mut().selected_container = selected_container.into();
        self
    }

    fn index(mut self, index: usize) -> Self {
        self.state_mut().index = index;
        self
    }

    fn combo_box(mut self, combo_box: impl Into<Entity>) -> Self {
        self.state_mut().combo_box = combo_box.into();
        self
    }

    // Define the template build function for the selected content of the ComboBoxItems.
    fn items_builder(
        &mut self,
        builder: &Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>,
    ) {
        self.state_mut().builder = Some(builder.clone());
    }
}

impl Template for ComboBoxItem {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("ComboBoxItem")
            .min_width(64.0)
            .height(24.0)
            .selected(false)
            .pressed(false)
            .selector("list-view-item")
            .padding(0.0)
            .background("transparent")
            .border_radius(0.0)
            .border_width(0.0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32.0)
            .font("Roboto Regular")
            .on_click(move |states, _| {
                states.get::<ComboBoxItemState>(id).toggle_selection();
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

/// The `ComboBoxState` is used to manipulate the position of the thumb of the slider widget.
#[derive(Default, AsAny)]
pub struct ComboBoxState {
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
    count: usize,
    items_panel: Entity,
    selected_container: Entity,
}

impl State for ComboBoxState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder.borrow()(build_context, i);
                        let mut item = ComboBoxItem::create()
                            .index(i)
                            .combo_box(entity)
                            .selected_container(self.selected_container);

                        if let Some(builder) = &self.builder {
                           item.items_builder(builder);
                        }

                        let item = item.build(build_context);

                        let mouse_behavior = MouseBehavior::create().build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_properties_by_theme();
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        // for index in ctx
        //     .widget()
        //     .get::<SelectedEntities>("selected_entities")
        //     .0
        //     .clone()
        //     .symmetric_difference(&*self.selected_entities.borrow())
        // {
        //     let mut widget = ctx.get_widget(*index);
        //     widget.set("selected", !widget.get::<bool>("selected"));

        //     widget.update_theme_by_state(false);
        // }

        // *self.selected_entities.borrow_mut() = ctx
        //     .widget()
        //     .get::<SelectedEntities>("selected_entities")
        //     .0
        //     .clone();
    }
}

// todo use code of list view item, by create combobox item insert entity of popup container

widget!(
    /// The `ComboBox` represents an selection widget with a drop-down list.
    ///
    /// **CSS element:** `ComboBox`
    ComboBox<ComboBoxState>: MouseHandler, ChangedHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shared the count.
        count: usize,

        /// Sets or shares the css selector property.
        selector: Selector,

        /// Sets or shares the selected index. If the value is -1 no item is selected.
        selected_index: i32,

        /// The entity of the selected item.
        selected_item: SelectedItem,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the flag if the drop down is open.
        selected: bool
    }
);

impl ComboBox {
    /// Define the template build function for the content of the ComboBoxItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Arc::new(RefCell::new(builder)));
        self
    }
}

impl Template for ComboBox {
    fn template(mut self, id: Entity, ctx: &mut BuildContext) -> Self {
        let container = Container::create()
            .selector(Selector::default().id(CONTAINER))
            .background(id)
            .border_radius(id)
            .border_width(id)
            .border_brush(id)
            .padding(id)
            .build(ctx);
        self.state_mut().selected_container = container;

        let items_panel = Stack::create()
            .vertical_alignment("start")
            .selector(Selector::default().id(ITEMS_PANEL))
            .orientation("vertical")
            .build(ctx);

        self.state_mut().items_panel = items_panel;
        let scroll_viewer = ScrollViewer::create()
            .scroll_viewer_mode(("disabled", "auto"))
            .child(items_panel)
            .build(ctx);

        let popup = Popup::create()
            .height(200.0)
            .open(("selected", id))
            .child(scroll_viewer)
            .child(
                ScrollIndicator::create()
                    .padding(2.0)
                    .content_id(items_panel.0)
                    .scroll_offset(scroll_viewer)
                    .opacity(id)
                    .build(ctx),
            )
            .target(container.0)
            .build(ctx);

        let _ = ctx.append_child_to_overlay(popup);

        self.name("ComboBox")
            .selector("combo_box")
            .height(32.0)
            .min_width(80.0)
            .selected(false)
            .selected_index(-1)
            .child(
                MouseBehavior::create()
                    .pressed(id)
                    .enabled(id)
                    .selector(id)
                    .child(
                        SelectionBehavior::create()
                            .selected(id)
                            .enabled(id)
                            .selector(id)
                            .parent(id.0)
                            .child(container)
                            .build(ctx),
                    )
                    .build(ctx),
            )
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use env::Env;
use library;
use nameutil;
use super::ffi_type::*;
use traits::*;

pub fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, classes: &[&library::Class]) -> Result<()> {
    for klass in classes {
        try!(generate_object_funcs(w, env, &klass.c_type,
            &klass.glib_get_type, &klass.functions));
    }

    Ok(())
}

pub fn generate_interfaces_funcs<W: Write>(w: &mut W, env: &Env, interfaces: &[&library::Interface]) -> Result<()> {
    for interface in interfaces {
        try!(generate_object_funcs(w, env,  &interface.c_type,
            &interface.glib_get_type, &interface.functions));
    }

    Ok(())
}

fn generate_object_funcs<W: Write>(w: &mut W, env: &Env, c_type: &str,
    glib_get_type: &str, functions: &[library::Function]) -> Result<()> {
    try!(writeln!(w, ""));
    try!(writeln!(w, "    //========================================================================="));
    try!(writeln!(w, "    // {}", c_type));
    try!(writeln!(w, "    //========================================================================="));
    if glib_get_type != "intern" {
        try!(writeln!(w, "    pub fn {:<36}() -> GType;", glib_get_type));
    }

    for func in functions {
        let (commented, sig) = function_signature(env, func, false);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "    {}pub fn {:<36}{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn generate_callbacks<W: Write>(w: &mut W, env: &Env, callbacks: &[&library::Function]) -> Result<()> {
    for func in callbacks {
        let (commented, sig) = function_signature(env, func, true);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "{}pub type {} = unsafe extern \"C\" fn{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (bool, String) {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par, bare);
        parameter_strs.push(par_str);
        if c { commented = true; }
    }

    (commented, format!("({}){}", parameter_strs.connect(", "), ret_str))
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}

fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) {
    if let &library::Type::Fundamental(library::Fundamental::VarArgs) = env.library.type_(par.typ) {
        return (false, "...".into());
    }
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    let commented = ffi_type.is_err();
    let res = if bare {
        ffi_type.as_str().into()
    }
    else {
        format!("{}: {}", nameutil::mangle_keywords(&*par.name), ffi_type.as_str())
    };
    (commented, res)
}
<commit_msg>Don't show object name without functions<commit_after>use std::io::{Result, Write};

use env::Env;
use library;
use nameutil;
use super::ffi_type::*;
use traits::*;

pub fn generate_classes_funcs<W: Write>(w: &mut W, env: &Env, classes: &[&library::Class]) -> Result<()> {
    for klass in classes {
        try!(generate_object_funcs(w, env, &klass.c_type,
            &klass.glib_get_type, &klass.functions));
    }

    Ok(())
}

pub fn generate_interfaces_funcs<W: Write>(w: &mut W, env: &Env, interfaces: &[&library::Interface]) -> Result<()> {
    for interface in interfaces {
        try!(generate_object_funcs(w, env,  &interface.c_type,
            &interface.glib_get_type, &interface.functions));
    }

    Ok(())
}

fn generate_object_funcs<W: Write>(w: &mut W, env: &Env, c_type: &str,
    glib_get_type: &str, functions: &[library::Function]) -> Result<()> {
    let write_get_type = glib_get_type != "intern";
    if write_get_type && !functions.is_empty() {
        try!(writeln!(w, ""));
        try!(writeln!(w, "    //========================================================================="));
        try!(writeln!(w, "    // {}", c_type));
        try!(writeln!(w, "    //========================================================================="));
    }
    if write_get_type {
        try!(writeln!(w, "    pub fn {:<36}() -> GType;", glib_get_type));
    }

    for func in functions {
        let (commented, sig) = function_signature(env, func, false);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "    {}pub fn {:<36}{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn generate_callbacks<W: Write>(w: &mut W, env: &Env, callbacks: &[&library::Function]) -> Result<()> {
    for func in callbacks {
        let (commented, sig) = function_signature(env, func, true);
        let comment = if commented { "//" } else { "" };
        try!(writeln!(w, "{}pub type {} = unsafe extern \"C\" fn{};",
                      comment, func.c_identifier.as_ref().unwrap(), sig));
    }

    Ok(())
}

pub fn function_signature(env: &Env, func: &library::Function, bare: bool) -> (bool, String) {
    let (mut commented, ret_str) = function_return_value(env, func);

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &func.parameters {
        let (c, par_str) = function_parameter(env, par, bare);
        parameter_strs.push(par_str);
        if c { commented = true; }
    }

    (commented, format!("({}){}", parameter_strs.connect(", "), ret_str))
}

fn function_return_value(env: &Env, func: &library::Function) -> (bool, String) {
    if func.ret.typ == Default::default() { return (false, String::new()) }
    let ffi_type = ffi_type(env, func.ret.typ, &func.ret.c_type);
    let commented = ffi_type.is_err();
    (commented, format!(" -> {}", ffi_type.as_str()))
}

fn function_parameter(env: &Env, par: &library::Parameter, bare: bool) -> (bool, String) {
    if let &library::Type::Fundamental(library::Fundamental::VarArgs) = env.library.type_(par.typ) {
        return (false, "...".into());
    }
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    let commented = ffi_type.is_err();
    let res = if bare {
        ffi_type.as_str().into()
    }
    else {
        format!("{}: {}", nameutil::mangle_keywords(&*par.name), ffi_type.as_str())
    };
    (commented, res)
}
<|endoftext|>


<commit_before>extern crate cmake;
extern crate gcc;
extern crate pkg_config;

use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn main() {
    if env::var("LIBCUBEB_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libcubeb").is_ok() {
            return;
        }
    }

    if !Path::new("libcubeb/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init", "--recursive"])
            .status();
    }

    let target = env::var("TARGET").unwrap();
    //    let host = env::var("HOST").unwrap();
    let windows = target.contains("windows");
    let darwin = target.contains("darwin");
    let mut cfg = cmake::Config::new("libcubeb");

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    env::remove_var("DESTDIR");
    let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
        .define("BUILD_TESTS", "OFF")
        .build();

    if windows {
        // TBD
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-search=native={}/lib", dst.display());
    } else if darwin {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        println!("cargo:rustc-link-lib=framework=CoreServices");
        println!("cargo:rustc-link-lib=dylib=c++");
        println!("cargo:rustc-link-search=native={}", dst.display());
    } else {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=dylib=stdc++");
        println!("cargo:rustc-link-search=native={}", dst.display());

        pkg_config::find_library("alsa").unwrap();
        pkg_config::find_library("libpulse").unwrap();
        pkg_config::find_library("jack").unwrap();
    }
}
<commit_msg>cubeb-api: Flesh out build.rs for Windows.<commit_after>extern crate cmake;
extern crate gcc;
extern crate pkg_config;

use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

fn main() {
    if env::var("LIBCUBEB_SYS_USE_PKG_CONFIG").is_ok() {
        if pkg_config::find_library("libcubeb").is_ok() {
            return;
        }
    }

    if !Path::new("libcubeb/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init", "--recursive"])
            .status();
    }

    let target = env::var("TARGET").unwrap();
    //    let host = env::var("HOST").unwrap();
    let windows = target.contains("windows");
    let darwin = target.contains("darwin");
    let mut cfg = cmake::Config::new("libcubeb");

    let _ = fs::remove_dir_all(env::var("OUT_DIR").unwrap());
    t!(fs::create_dir_all(env::var("OUT_DIR").unwrap()));

    env::remove_var("DESTDIR");
    let dst = cfg.define("BUILD_SHARED_LIBS", "OFF")
        .define("BUILD_TESTS", "OFF")
        .build();

    if windows {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-search=native={}", dst.display());
        println!("cargo:rustc-link-lib=dylib=avrt");
        println!("cargo:rustc-link-lib=dylib=ole32");
        println!("cargo:rustc-link-lib=dylib=user32");
        println!("cargo:rustc-link-lib=dylib=winmm");
    } else if darwin {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        println!("cargo:rustc-link-lib=framework=CoreServices");
        println!("cargo:rustc-link-lib=dylib=c++");
        println!("cargo:rustc-link-search=native={}", dst.display());
    } else {
        println!("cargo:rustc-link-lib=static=cubeb");
        println!("cargo:rustc-link-lib=dylib=stdc++");
        println!("cargo:rustc-link-search=native={}", dst.display());

        pkg_config::find_library("alsa").unwrap();
        pkg_config::find_library("libpulse").unwrap();
        pkg_config::find_library("jack").unwrap();
    }
}
<|endoftext|>


<commit_before>pub mod msg;
pub mod helpers;
pub mod error;
pub mod genmsg;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

#[macro_export]
macro_rules! rosmsg_main {
    ($($msg:expr),*)=> {
        fn main() {
            $crate::build_tools::depend_on_messages(&[
            $(
                $msg,
            )*
            ]);
        }
    }
}

#[macro_export]
macro_rules! rosmsg_include {
    () => {include!(concat!(env!("OUT_DIR"), "/msg.rs"));}
}

pub fn depend_on_messages(messages: &[&str]) {
    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or(String::new())
        .split(":")
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or(String::new())
        .split(":")
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(extra_paths.iter())
        .map(|v| v.as_str())
        .collect::<Vec<&str>>();
    let output = genmsg::depend_on_messages(paths.as_slice(), messages).unwrap();
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("msg.rs");
    let mut f = File::create(&dest_path).unwrap();
    write!(f, "{}", output).unwrap();
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(|v| v.to_owned())
}
<commit_msg>Fix missing message files<commit_after>pub mod msg;
pub mod helpers;
pub mod error;
pub mod genmsg;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

#[macro_export]
macro_rules! rosmsg_main {
    ($($msg:expr),*)=> {
        fn main() {
            $crate::build_tools::depend_on_messages(&[
            $(
                $msg,
            )*
            ]);
        }
    }
}

#[macro_export]
macro_rules! rosmsg_include {
    () => {include!(concat!(env!("OUT_DIR"), "/msg.rs"));}
}

pub fn depend_on_messages(messages: &[&str]) {
    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or(String::new())
        .split(":")
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or(String::new())
        .split(":")
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or(String::new())
        .split(":")
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(extra_paths.iter())
        .map(|v| v.as_str())
        .collect::<Vec<&str>>();
    let output = genmsg::depend_on_messages(paths.as_slice(), messages).unwrap();
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("msg.rs");
    let mut f = File::create(&dest_path).unwrap();
    write!(f, "{}", output).unwrap();
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(|v| v.to_owned())
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path).join("..").join("src").to_str().map(|v| {
        v.to_owned()
    })
}
<|endoftext|>


<commit_before><commit_msg>Replace icosahedron with sphere<commit_after><|endoftext|>


<commit_before><commit_msg>Error for unit-test-client.rs<commit_after><|endoftext|>


<commit_before><commit_msg>docs: Clarify when quoting is required for arg<commit_after><|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Object {
    pub title:            String,
    pub obj_type:         ObjectType,
    pub url:              String,

    pub images:           Vec<Image>,
    pub audios:           Vec<Audio>,
    pub videos:           Vec<Video>,

    pub description:      Option<String>,
    pub determiner:       Option<Determiner>,
    pub locale:           Option<String>,
    pub locale_alternate: Option<Vec<String>>,
    pub site_name:        Option<String>,
}

#[derive(Debug)]
pub enum ObjectType {
    // No Vetical
    Article,
    Book,
    Profile,
    Website,
    // Music
    Song,
    Album,
    Playlist,
    RadioStation,
    // Video
    Movie,
    Episode,
    TVShow,
}

#[derive(Debug)]
pub enum Determiner {
    A,
    An,
    The,
    Blank,
    Auto,
}

#[derive(Debug)]
pub struct Image {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

#[derive(Debug)]
pub struct Video {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

#[derive(Debug)]
pub struct Audio {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
}

<commit_msg>Impl ToJson for open_graph::Object<commit_after>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};

#[derive(Debug)]
pub struct Object {
    pub title:            String,
    pub obj_type:         ObjectType,
    pub url:              String,

    pub images:           Vec<Image>,
    pub audios:           Vec<Audio>,
    pub videos:           Vec<Video>,

    pub description:      Option<String>,
    pub determiner:       Option<Determiner>,
    pub locale:           Option<String>,
    pub locale_alternate: Option<Vec<String>>,
    pub site_name:        Option<String>,
}

impl ToJson for Object {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("title".to_string()           , self.title.to_json());
        d.insert("type".to_string()            , self.obj_type.to_json());
        d.insert("url".to_string()             , self.url.to_json());

        d.insert("images".to_string(),
                 Json::Array(self.images.iter().map(|x| x.to_json()).collect()));
        d.insert("audios".to_string(),
                 Json::Array(self.audios.iter().map(|x| x.to_json()).collect()));
        d.insert("videos".to_string(),
                 Json::Array(self.videos.iter().map(|x| x.to_json()).collect()));

        d.insert("description".to_string()     , self.description.to_json());
        d.insert("determiner".to_string()      , self.determiner.to_json());
        d.insert("locale".to_string()          , self.locale.to_json());
        d.insert("locale_alternate".to_string(), self.locale.to_json());
        d.insert("site_name".to_string()       , self.locale.to_json());

        Json::Object(d)
    }
}

#[derive(Debug)]
pub enum ObjectType {
    // No Vetical
    Article,
    Book,
    Profile,
    Website,
    // Music
    Song,
    Album,
    Playlist,
    RadioStation,
    // Video
    Movie,
    Episode,
    TVShow,
    VideoOther,
}

impl ObjectType {
    fn to_string(&self) -> String {
        match *self {
            ObjectType::Article      => "article",
            ObjectType::Book         => "book",
            ObjectType::Profile      => "profile",
            ObjectType::Website      => "website",
            ObjectType::Song         => "music.song",
            ObjectType::Album        => "music.album",
            ObjectType::Playlist     => "music.playlist",
            ObjectType::RadioStation => "music.radio_station",
            ObjectType::Movie        => "video.movie",
            ObjectType::Episode      => "video.episode",
            ObjectType::TVShow       => "video.tv_show",
            ObjectType::VideoOther   => "video.other"
        }.to_string()
    }
    pub fn new(str: String) -> ObjectType {
        match str.as_ref() {
            "article"             => ObjectType::Article,
            "book"                => ObjectType::Book,
            "profile"             => ObjectType::Profile,
            "website"             => ObjectType::Website,
            "music.song"          => ObjectType::Song,
            "music.album"         => ObjectType::Album,
            "music.playlist"      => ObjectType::Playlist,
            "music.radio_station" => ObjectType::RadioStation,
            "video.movie"         => ObjectType::Movie,
            "video.episode"       => ObjectType::Episode,
            "video.tv_show"       => ObjectType::TVShow,
            "video.other"         => ObjectType::VideoOther,
            _                     => ObjectType::Website,
        }
    }
}

impl ToJson for ObjectType {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

#[derive(Debug)]
pub enum Determiner {
    A,
    An,
    The,
    Blank,
    Auto,
}

impl Determiner {
    fn to_string(&self) -> String {
        match *self {
            Determiner::A     => "a",
            Determiner::An    => "an",
            Determiner::The   => "the",
            Determiner::Blank => "",
            Determiner::Auto  => "auto",
        }.to_string()
    }
    pub fn new(str: String) -> Determiner {
        match str.as_ref() {
            "a"     => Determiner::A,
            "an"    => Determiner::An,
            "the"   => Determiner::The,
            "auto"  => Determiner::Auto,
            _       => Determiner::Blank,
        }
    }
}

impl ToJson for Determiner {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

#[derive(Debug)]
pub struct Image {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

impl ToJson for Image {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string()       , self.url.to_json());
        d.insert("secure_url".to_string(), self.secure_url.to_json());
        d.insert("type".to_string()      , self.obj_type.to_json());
        d.insert("width".to_string()     , self.width.to_json());
        d.insert("height".to_string()    , self.height.to_json());
        Json::Object(d)
    }
}

#[derive(Debug)]
pub struct Video {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

impl ToJson for Video {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string()       , self.url.to_json());
        d.insert("secure_url".to_string(), self.secure_url.to_json());
        d.insert("type".to_string()      , self.obj_type.to_json());
        d.insert("width".to_string()     , self.width.to_json());
        d.insert("height".to_string()    , self.height.to_json());
        Json::Object(d)
    }
}

#[derive(Debug)]
pub struct Audio {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
}

impl ToJson for Audio {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string()       , self.url.to_json());
        d.insert("secure_url".to_string(), self.secure_url.to_json());
        d.insert("type".to_string()      , self.obj_type.to_json());
        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>fn main() {
    // all the type annotations are superfluous
    let x: int = 5;

    let y: int = {
        // assignment statements are allowed inside blocks
        let x_squared = x * x;
        let x_cube = x_squared * x;

        // this expression will be assigned to y
        x_cube + x_squared + x
    };

    let z: () = {
        // the semicolon suppresses this expression, and `()` is assigned to z
        2 * x;
    };

    println!("x is {}", x);
    println!("y is {}", y);
    println!("z is {}", z);
}
<commit_msg>expression: keep lines under 75 chars<commit_after>fn main() {
    // all the type annotations are superfluous
    let x: int = 5;

    let y: int = {
        // assignment statements are allowed inside blocks
        let x_squared = x * x;
        let x_cube = x_squared * x;

        // this expression will be assigned to y
        x_cube + x_squared + x
    };

    let z: () = {
        // the semicolon suppresses this expression,
        // and `()` is assigned to z
        2 * x;
    };

    println!("x is {}", x);
    println!("y is {}", y);
    println!("z is {}", z);
}
<|endoftext|>


<commit_before>// http://dev.w3.org/csswg/css3-syntax/#tree-construction
//
// The input to the tree construction stage is a sequence of tokens
// from the tokenization stage.
// The output is a tree of items with a stylesheet at the root
// and all other nodes being at-rules, style rules, or declarations.

use tokens;

#[deriving_eq]
enum Primitive {
    // Preserved tokens. Same as in the tokenizer.
    Ident(~str),
    AtKeyword(~str),
    Hash(~str),
    String(~str),
    URL(~str),
    Delim(char),
    Number(NumericValue, ~str),  // value, representation
    Percentage(NumericValue, ~str),  // value, representation
    Dimension(NumericValue, ~str, ~str),  // value, representation, unit
    UnicodeRange(char, char),  // start, end
    EmptyUnicodeRange,
    WhiteSpace,
    Comment,
    CDO,  // <!--
    CDC,  // -->
    Colon,  // :
    Semicolon,  // ;
    CloseBraket, // ]
    CloseParen, // )
    CloseBrace, // }

    // Function
    Function(~str, ~[~[Primitive]]),  // name, arguments

    // Simple block
    BraketBlock(~[Primitive]),  // […]
    ParenBlock(~[Primitive]),  // (…)
    BraceBlock(~[Primitive]),  // {…}
}

struct Declaration {
    name: ~str,
    value: ~[Primitive],
    important: bool,
}

struct StyleRule {
    selector: ~[Primitive],
    value: ~[DeclarationListItem],
}

struct AtRule {
    name: ~str,
    selector: ~[Primitive],
    value: AtRuleValue,
}

enum AtRuleValue {
    EmptyAtRule,  // @foo…;
    DeclarationFilled(~[DeclarationListItem]),
    RuleFilled(~[RuleListItem]),
}

enum DeclarationListItem {
    Declaration(Declaration),
    // A better idea for a name that means "at-rule" but is not "AtRule"?
    Decl_AtRule(AtRule),
}

enum RuleListItem {
    StyleRule(StyleRule),
    AtRule(AtRule),
}

pub struct Parser {
    priv tokenizer: ~tokens::Tokenizer,
    priv quirks_mode: bool,
    priv mut current_token: Option<tokens::Token>,
    priv mut errors: ~[~str],
}

impl Parser {
    static fn from_tokenizer(
            tokenizer: ~tokens::Tokenizer, quirks_mode: bool) -> ~Parser {
        ~Parser {
            tokenizer: tokenizer,
            quirks_mode: quirks_mode,
            current_token: None,
            errors: ~[],
        }
    }
    static fn from_str(input: &str, transform_function_whitespace: bool,
                      quirks_mode: bool) -> ~Parser {
        Parser::from_tokenizer(
            tokens::Tokenizer::from_str(input, transform_function_whitespace),
            quirks_mode)
    }
}

// Consume the whole input and return a list of primitives.
// Could be used for parsing eg. a stand-alone media query.
// This is similar to consume_simple_block(), but there is no ending token.
fn consume_primitive_list(parser: &Parser) -> ~[Primitive] {
    let mut primitives: ~[Primitive] = ~[];
    for parser.each_token |token| {
        parser.reconsume_token(token);
        primitives.push(consume_primitive(parser))
    }
    primitives
}

//  ***********  End of public API  ***********

impl Parser {
    priv fn consume_token(&self) -> tokens::Token {
        let mut current_token = None;
        current_token <-> self.current_token;
        match current_token {
            Some(token) => token,
            None => {
                let (token, err) = self.tokenizer.next_token();
                match err {
                    Some(ParseError{message: message}) =>
                        // TODO more contextual error handling?
                        self.errors.push(message),
                    None => ()
                }
                token
            }
        }
    }

    // Skips comments
    priv fn each_token(&self, it: fn(token: tokens::Token) -> bool) {
        loop {
            match self.consume_token() {
                tokens::Comment => (),
                tokens::EOF => break,
                token => if !it(token) { break },
            }
        }
    }

    // Fail if the is already a "current token".
    // The easiest way to ensure this does not fail it to call it only once
    // just after calling parser.consume_token()
    priv fn reconsume_token(&self, token: tokens::Token) {
        assert self.current_token.is_none();
        self.current_token = Some(token)
    }
}

// Convert a token from the tokenizer to a primitive.
// Fails if it is not a preserved token. XXX do something else.
fn preserved_token_to_primitive(token: tokens::Token) -> Primitive {
    match token {
        tokens::Ident(string) => Ident(string),
        tokens::AtKeyword(string) => AtKeyword(string),
        tokens::Hash(string) => Hash(string),
        tokens::String(string) => String(string),
        tokens::URL(string) => URL(string),
        tokens::Delim(ch) => Delim(ch),
        tokens::Number(value, repr) => Number(value, repr),
        tokens::Percentage(value, repr) => Percentage(value, repr),
        tokens::Dimension(value, repr, unit) => Dimension(value, repr, unit),
        tokens::UnicodeRange(start, end) => UnicodeRange(start, end),
        tokens::EmptyUnicodeRange => EmptyUnicodeRange,
        tokens::WhiteSpace => WhiteSpace,
        tokens::Colon => Colon,
        tokens::Semicolon => Semicolon,
        _ => fail,   // XXX
        // These are special-cased in consume_primitive()
//        tokens::Function(string) => fail,
//        tokens::OpenBraket => fail,
//        tokens::OpenParen => fail,
//        tokens::OpenBrace => fail,

        // These still need to be dealt with somehow.
//        tokens::BadString => fail,
//        tokens::BadURL => fail,
//        tokens::Comment => fail,
//        tokens::CDO => fail,
//        tokens::CDC => fail,
//        tokens::CloseBraket => fail,
//        tokens::CloseParen => fail,
//        tokens::CloseBrace => fail,
//        tokens::EOF => fail,
    }
}

// 3.5.15. Consume a primitive
fn consume_primitive(parser: &Parser) -> Primitive {
    match parser.consume_token() {
        tokens::OpenBraket =>
            BraketBlock(consume_simple_block(parser, tokens::CloseBraket)),
        tokens::OpenParen =>
            ParenBlock(consume_simple_block(parser, tokens::CloseParen)),
        tokens::OpenBrace =>
            BraceBlock(consume_simple_block(parser, tokens::CloseBrace)),
        tokens::Function(string) => consume_function(parser, string),
        token => preserved_token_to_primitive(token),
    }
}

// 3.5.18. Consume a simple block  (kind of)
fn consume_simple_block(parser: &Parser, ending_token: tokens::Token)
        -> ~[Primitive] {
    let mut value: ~[Primitive] = ~[];
    for parser.each_token |token| {
        if token == ending_token { break }
        else {
            parser.reconsume_token(token);
            value.push(consume_primitive(parser))
        }
    }
    value
}

// 3.5.19. Consume a function
fn consume_function(parser: &Parser, name: ~str)
        -> Primitive {
    let mut current_argument: ~[Primitive] = ~[];
    let mut arguments: ~[~[Primitive]] = ~[];
    for parser.each_token |token| {
        match token {
            tokens::CloseParen => break,
            tokens::Delim(',') => {
                let mut arg: ~[Primitive] = ~[];
                arg <-> current_argument;
                arguments.push(arg);
            },
            tokens::Number(value, repr) => current_argument.push(
                if parser.quirks_mode && ascii_lower(name) == ~"rect" {
                    // 3.5.17. Consume a primitive
                    // with the unitless length quirk
                    Dimension(value, repr, ~"px")
                } else {
                    Number(value, repr)
                }
            ),
            token => {
                parser.reconsume_token(token);
                current_argument.push(consume_primitive(parser))
            }
        }
    }
    arguments.push(current_argument);
    Function(name, arguments)
}

#[test]
fn test_primitives() {
    fn assert_primitives(input: &str, expected_primitives: &[Primitive],
                         expected_errors: &[~str]) {
        assert_primitives_flags(
            input, expected_primitives, expected_errors, false)
    }
    fn assert_primitives_flags(input: &str, expected_primitives: &[Primitive],
                               expected_errors: &[~str], quirks_mode: bool) {
        let parser = Parser::from_str(input, false, quirks_mode);
        let primitives: &[Primitive] = consume_primitive_list(parser);
        let errors: &[~str] = parser.errors;
        if primitives != expected_primitives {
            fail fmt!("%?\n!=\n%?", primitives, expected_primitives);
        }
        if errors != expected_errors {
            fail fmt!("%?\n!=\n%?", errors, expected_errors);
        }
    }

    assert_primitives("", [], []);
    assert_primitives("42 foo([aa ()b], -){\n  }", [
        Number(Integer(42), ~"42"), WhiteSpace,
        Function(~"foo", ~[
            ~[BraketBlock(~[
                Ident(~"aa"), WhiteSpace, ParenBlock(~[]), Ident(~"b")])],
            ~[WhiteSpace, Delim('-')]]),
        BraceBlock(~[
            WhiteSpace])], [])
}
<commit_msg>Have consume_primitive() take a token parameter.<commit_after>// http://dev.w3.org/csswg/css3-syntax/#tree-construction
//
// The input to the tree construction stage is a sequence of tokens
// from the tokenization stage.
// The output is a tree of items with a stylesheet at the root
// and all other nodes being at-rules, style rules, or declarations.

use tokens;

#[deriving_eq]
enum Primitive {
    // Preserved tokens. Same as in the tokenizer.
    Ident(~str),
    AtKeyword(~str),
    Hash(~str),
    String(~str),
    URL(~str),
    Delim(char),
    Number(NumericValue, ~str),  // value, representation
    Percentage(NumericValue, ~str),  // value, representation
    Dimension(NumericValue, ~str, ~str),  // value, representation, unit
    UnicodeRange(char, char),  // start, end
    EmptyUnicodeRange,
    WhiteSpace,
    Comment,
    CDO,  // <!--
    CDC,  // -->
    Colon,  // :
    Semicolon,  // ;
    CloseBraket, // ]
    CloseParen, // )
    CloseBrace, // }

    // Function
    Function(~str, ~[~[Primitive]]),  // name, arguments

    // Simple block
    BraketBlock(~[Primitive]),  // […]
    ParenBlock(~[Primitive]),  // (…)
    BraceBlock(~[Primitive]),  // {…}
}

struct Declaration {
    name: ~str,
    value: ~[Primitive],
    important: bool,
}

struct StyleRule {
    selector: ~[Primitive],
    value: ~[DeclarationListItem],
}

struct AtRule {
    name: ~str,
    selector: ~[Primitive],
    value: AtRuleValue,
}

enum AtRuleValue {
    EmptyAtRule,  // @foo…;
    DeclarationFilled(~[DeclarationListItem]),
    RuleFilled(~[RuleListItem]),
}

enum DeclarationListItem {
    Declaration(Declaration),
    // A better idea for a name that means "at-rule" but is not "AtRule"?
    Decl_AtRule(AtRule),
}

enum RuleListItem {
    StyleRule(StyleRule),
    AtRule(AtRule),
}

pub struct Parser {
    priv tokenizer: ~tokens::Tokenizer,
    priv quirks_mode: bool,
    priv mut current_token: Option<tokens::Token>,
    priv mut errors: ~[~str],
}

impl Parser {
    static fn from_tokenizer(
            tokenizer: ~tokens::Tokenizer, quirks_mode: bool) -> ~Parser {
        ~Parser {
            tokenizer: tokenizer,
            quirks_mode: quirks_mode,
            current_token: None,
            errors: ~[],
        }
    }
    static fn from_str(input: &str, transform_function_whitespace: bool,
                      quirks_mode: bool) -> ~Parser {
        Parser::from_tokenizer(
            tokens::Tokenizer::from_str(input, transform_function_whitespace),
            quirks_mode)
    }
}

// Consume the whole input and return a list of primitives.
// Could be used for parsing eg. a stand-alone media query.
// This is similar to consume_simple_block(), but there is no ending token.
fn consume_primitive_list(parser: &Parser) -> ~[Primitive] {
    let mut primitives: ~[Primitive] = ~[];
    for parser.each_token |token| {
        primitives.push(consume_primitive(parser, token))
    }
    primitives
}

//  ***********  End of public API  ***********

impl Parser {
    priv fn consume_token(&self) -> tokens::Token {
        let mut current_token = None;
        current_token <-> self.current_token;
        match current_token {
            Some(token) => token,
            None => {
                let (token, err) = self.tokenizer.next_token();
                match err {
                    Some(ParseError{message: message}) =>
                        // TODO more contextual error handling?
                        self.errors.push(message),
                    None => ()
                }
                token
            }
        }
    }

    // Skips comments
    priv fn each_token(&self, it: fn(token: tokens::Token) -> bool) {
        loop {
            match self.consume_token() {
                tokens::Comment => (),
                tokens::EOF => break,
                token => if !it(token) { break },
            }
        }
    }

    // Fail if the is already a "current token".
    // The easiest way to ensure this does not fail it to call it only once
    // just after calling parser.consume_token()
    priv fn reconsume_token(&self, token: tokens::Token) {
        assert self.current_token.is_none();
        self.current_token = Some(token)
    }
}

// 3.5.15. Consume a primitive
fn consume_primitive(parser: &Parser, first_token: tokens::Token)
        -> Primitive {
    match first_token {
        // Preserved tokens
        tokens::Ident(string) => Ident(string),
        tokens::AtKeyword(string) => AtKeyword(string),
        tokens::Hash(string) => Hash(string),
        tokens::String(string) => String(string),
        tokens::URL(string) => URL(string),
        tokens::Delim(ch) => Delim(ch),
        tokens::Number(value, repr) => Number(value, repr),
        tokens::Percentage(value, repr) => Percentage(value, repr),
        tokens::Dimension(value, repr, unit) => Dimension(value, repr, unit),
        tokens::UnicodeRange(start, end) => UnicodeRange(start, end),
        tokens::EmptyUnicodeRange => EmptyUnicodeRange,
        tokens::WhiteSpace => WhiteSpace,
        tokens::Colon => Colon,
        tokens::Semicolon => Semicolon,

        // Simple blocks
        tokens::OpenBraket =>
            BraketBlock(consume_simple_block(parser, tokens::CloseBraket)),
        tokens::OpenParen =>
            ParenBlock(consume_simple_block(parser, tokens::CloseParen)),
        tokens::OpenBrace =>
            BraceBlock(consume_simple_block(parser, tokens::CloseBrace)),

        // Functions
        tokens::Function(string) => consume_function(parser, string),

        // Non-preserved tokens
        // TODO These still need to be dealt with somehow.
        tokens::BadString | tokens::BadURL | tokens::CDO | tokens::CDC
            | tokens::CloseBraket | tokens::CloseParen | tokens::CloseBrace
            => fail,

        // Getting here is a  programming error.
        tokens::Comment | tokens::EOF => fail,
    }
}

// 3.5.18. Consume a simple block  (kind of)
fn consume_simple_block(parser: &Parser, ending_token: tokens::Token)
        -> ~[Primitive] {
    let mut value: ~[Primitive] = ~[];
    for parser.each_token |token| {
        if token == ending_token { break }
        else { value.push(consume_primitive(parser, token)) }
    }
    value
}

// 3.5.19. Consume a function
fn consume_function(parser: &Parser, name: ~str)
        -> Primitive {
    let mut current_argument: ~[Primitive] = ~[];
    let mut arguments: ~[~[Primitive]] = ~[];
    for parser.each_token |token| {
        match token {
            tokens::CloseParen => break,
            tokens::Delim(',') => {
                let mut arg: ~[Primitive] = ~[];
                arg <-> current_argument;
                arguments.push(arg);
            },
            tokens::Number(value, repr) => current_argument.push(
                if parser.quirks_mode && ascii_lower(name) == ~"rect" {
                    // 3.5.17. Consume a primitive
                    // with the unitless length quirk
                    Dimension(value, repr, ~"px")
                } else {
                    Number(value, repr)
                }
            ),
            token => current_argument.push(consume_primitive(parser, token)),
        }
    }
    arguments.push(current_argument);
    Function(name, arguments)
}

#[test]
fn test_primitives() {
    fn assert_primitives(input: &str, expected_primitives: &[Primitive],
                         expected_errors: &[~str]) {
        assert_primitives_flags(
            input, expected_primitives, expected_errors, false)
    }
    fn assert_primitives_flags(input: &str, expected_primitives: &[Primitive],
                               expected_errors: &[~str], quirks_mode: bool) {
        let parser = Parser::from_str(input, false, quirks_mode);
        let primitives: &[Primitive] = consume_primitive_list(parser);
        let errors: &[~str] = parser.errors;
        if primitives != expected_primitives {
            fail fmt!("%?\n!=\n%?", primitives, expected_primitives);
        }
        if errors != expected_errors {
            fail fmt!("%?\n!=\n%?", errors, expected_errors);
        }
    }

    assert_primitives("", [], []);
    assert_primitives("42 foo([aa ()b], -){\n  }", [
        Number(Integer(42), ~"42"), WhiteSpace,
        Function(~"foo", ~[
            ~[BraketBlock(~[
                Ident(~"aa"), WhiteSpace, ParenBlock(~[]), Ident(~"b")])],
            ~[WhiteSpace, Delim('-')]]),
        BraceBlock(~[
            WhiteSpace])], [])
}
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::RefCell;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;

use base::Event;
use sync::Mutex;

use super::INTERRUPT_STATUS_CONFIG_CHANGED;
use super::INTERRUPT_STATUS_USED_RING;
use super::VIRTIO_MSI_NO_VECTOR;
use crate::irq_event::IrqLevelEvent;
use crate::pci::MsixConfig;

pub trait SignalableInterrupt {
    /// Writes to the irqfd to VMM to deliver virtual interrupt to the guest.
    fn signal(&self, vector: u16, interrupt_status_mask: u32);

    /// Notify the driver that buffers have been placed in the used queue.
    fn signal_used_queue(&self, vector: u16) {
        self.signal(vector, INTERRUPT_STATUS_USED_RING)
    }

    /// Notify the driver that the device configuration has changed.
    fn signal_config_changed(&self);

    /// Get the event to signal resampling is needed if it exists.
    fn get_resample_evt(&self) -> Option<&Event>;

    /// Reads the status and writes to the interrupt event. Doesn't read the resample event, it
    /// assumes the resample has been requested.
    fn do_interrupt_resample(&self);
}

struct TransportPci {
    irq_evt_lvl: IrqLevelEvent,
    msix_config: Option<Arc<Mutex<MsixConfig>>>,
    config_msix_vector: u16,
}

enum Transport {
    Pci { pci: TransportPci },
}

pub struct Interrupt {
    interrupt_status: Arc<AtomicUsize>,
    transport: Transport,
}

impl SignalableInterrupt for Interrupt {
    /// Virtqueue Interrupts From The Device
    ///
    /// If MSI-X is enabled in this device, MSI-X interrupt is preferred.
    /// Write to the irqfd to VMM to deliver virtual interrupt to the guest
    fn signal(&self, vector: u16, interrupt_status_mask: u32) {
        // Don't need to set ISR for MSI-X interrupts
        match &self.transport {
            Transport::Pci { pci } => {
                if let Some(msix_config) = &pci.msix_config {
                    let mut msix_config = msix_config.lock();
                    if msix_config.enabled() {
                        if vector != VIRTIO_MSI_NO_VECTOR {
                            msix_config.trigger(vector);
                        }
                        return;
                    }
                }
            }
        }

        // Set bit in ISR and inject the interrupt if it was not already pending.
        // Don't need to inject the interrupt if the guest hasn't processed it.
        if self
            .interrupt_status
            .fetch_or(interrupt_status_mask as usize, Ordering::SeqCst)
            == 0
        {
            // Write to irqfd to inject INTx interrupt
            match &self.transport {
                Transport::Pci { pci } => pci.irq_evt_lvl.trigger().unwrap(),
            }
        }
    }

    fn signal_config_changed(&self) {
        let vector = match &self.transport {
            Transport::Pci { pci } => pci.config_msix_vector,
        };
        self.signal(vector, INTERRUPT_STATUS_CONFIG_CHANGED)
    }

    fn get_resample_evt(&self) -> Option<&Event> {
        match &self.transport {
            Transport::Pci { pci } => Some(pci.irq_evt_lvl.get_resample()),
        }
    }

    fn do_interrupt_resample(&self) {
        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
            match &self.transport {
                Transport::Pci { pci } => pci.irq_evt_lvl.trigger().unwrap(),
            }
        }
    }
}

impl<I: SignalableInterrupt> SignalableInterrupt for Arc<Mutex<I>> {
    fn signal(&self, vector: u16, interrupt_status_mask: u32) {
        self.lock().signal(vector, interrupt_status_mask);
    }

    fn signal_used_queue(&self, vector: u16) {
        self.lock().signal_used_queue(vector);
    }

    fn signal_config_changed(&self) {
        self.lock().signal_config_changed();
    }

    fn get_resample_evt(&self) -> Option<&Event> {
        // Cannot get resample event from a borrowed item.
        None
    }

    fn do_interrupt_resample(&self) {}
}

impl<I: SignalableInterrupt> SignalableInterrupt for Rc<RefCell<I>> {
    fn signal(&self, vector: u16, interrupt_status_mask: u32) {
        self.borrow().signal(vector, interrupt_status_mask);
    }

    fn signal_used_queue(&self, vector: u16) {
        self.borrow().signal_used_queue(vector);
    }

    fn signal_config_changed(&self) {
        self.borrow().signal_config_changed();
    }

    fn get_resample_evt(&self) -> Option<&Event> {
        // Cannot get resample event from a borrowed item.
        None
    }

    fn do_interrupt_resample(&self) {}
}

impl Interrupt {
    pub fn new(
        interrupt_status: Arc<AtomicUsize>,
        irq_evt_lvl: IrqLevelEvent,
        msix_config: Option<Arc<Mutex<MsixConfig>>>,
        config_msix_vector: u16,
    ) -> Interrupt {
        Interrupt {
            interrupt_status,
            transport: Transport::Pci {
                pci: TransportPci {
                    irq_evt_lvl,
                    msix_config,
                    config_msix_vector,
                },
            },
        }
    }

    /// Get a reference to the interrupt event.
    pub fn get_interrupt_evt(&self) -> &Event {
        match &self.transport {
            Transport::Pci { pci } => pci.irq_evt_lvl.get_trigger(),
        }
    }

    /// Handle interrupt resampling event, reading the value from the event and doing the resample.
    pub fn interrupt_resample(&self) {
        match &self.transport {
            Transport::Pci { pci } => {
                pci.irq_evt_lvl.clear_resample();
                self.do_interrupt_resample();
            }
        }
    }

    /// Get a reference to the msix configuration
    pub fn get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>> {
        match &self.transport {
            Transport::Pci { pci } => &pci.msix_config,
        }
    }
}
<commit_msg>devices: virtio: Support interrupt configuration for MMIO transport type<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cell::RefCell;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Arc;

use base::Event;
use sync::Mutex;

use super::INTERRUPT_STATUS_CONFIG_CHANGED;
use super::INTERRUPT_STATUS_USED_RING;
use super::VIRTIO_MSI_NO_VECTOR;
use crate::irq_event::IrqEdgeEvent;
use crate::irq_event::IrqLevelEvent;
use crate::pci::MsixConfig;

pub trait SignalableInterrupt {
    /// Writes to the irqfd to VMM to deliver virtual interrupt to the guest.
    fn signal(&self, vector: u16, interrupt_status_mask: u32);

    /// Notify the driver that buffers have been placed in the used queue.
    fn signal_used_queue(&self, vector: u16) {
        self.signal(vector, INTERRUPT_STATUS_USED_RING)
    }

    /// Notify the driver that the device configuration has changed.
    fn signal_config_changed(&self);

    /// Get the event to signal resampling is needed if it exists.
    fn get_resample_evt(&self) -> Option<&Event>;

    /// Reads the status and writes to the interrupt event. Doesn't read the resample event, it
    /// assumes the resample has been requested.
    fn do_interrupt_resample(&self);
}

struct TransportPci {
    irq_evt_lvl: IrqLevelEvent,
    msix_config: Option<Arc<Mutex<MsixConfig>>>,
    config_msix_vector: u16,
}

enum Transport {
    Pci { pci: TransportPci },
    Mmio { irq_evt_edge: IrqEdgeEvent },
}

pub struct Interrupt {
    interrupt_status: Arc<AtomicUsize>,
    transport: Transport,
}

impl SignalableInterrupt for Interrupt {
    /// Virtqueue Interrupts From The Device
    ///
    /// If MSI-X is enabled in this device, MSI-X interrupt is preferred.
    /// Write to the irqfd to VMM to deliver virtual interrupt to the guest
    fn signal(&self, vector: u16, interrupt_status_mask: u32) {
        // Don't need to set ISR for MSI-X interrupts
        if let Transport::Pci { pci } = &self.transport {
            if let Some(msix_config) = &pci.msix_config {
                let mut msix_config = msix_config.lock();
                if msix_config.enabled() {
                    if vector != VIRTIO_MSI_NO_VECTOR {
                        msix_config.trigger(vector);
                    }
                    return;
                }
            }
        }

        // Set bit in ISR and inject the interrupt if it was not already pending.
        // Don't need to inject the interrupt if the guest hasn't processed it.
        if self
            .interrupt_status
            .fetch_or(interrupt_status_mask as usize, Ordering::SeqCst)
            == 0
        {
            // Write to irqfd to inject PCI INTx or MMIO interrupt
            match &self.transport {
                Transport::Pci { pci } => pci.irq_evt_lvl.trigger().unwrap(),
                Transport::Mmio { irq_evt_edge } => irq_evt_edge.trigger().unwrap(),
            }
        }
    }

    fn signal_config_changed(&self) {
        let vector = match &self.transport {
            Transport::Pci { pci } => pci.config_msix_vector,
            _ => VIRTIO_MSI_NO_VECTOR,
        };
        self.signal(vector, INTERRUPT_STATUS_CONFIG_CHANGED)
    }

    fn get_resample_evt(&self) -> Option<&Event> {
        match &self.transport {
            Transport::Pci { pci } => Some(pci.irq_evt_lvl.get_resample()),
            _ => None,
        }
    }

    fn do_interrupt_resample(&self) {
        if self.interrupt_status.load(Ordering::SeqCst) != 0 {
            match &self.transport {
                Transport::Pci { pci } => pci.irq_evt_lvl.trigger().unwrap(),
                _ => panic!("do_interrupt_resample() not supported"),
            }
        }
    }
}

impl<I: SignalableInterrupt> SignalableInterrupt for Arc<Mutex<I>> {
    fn signal(&self, vector: u16, interrupt_status_mask: u32) {
        self.lock().signal(vector, interrupt_status_mask);
    }

    fn signal_used_queue(&self, vector: u16) {
        self.lock().signal_used_queue(vector);
    }

    fn signal_config_changed(&self) {
        self.lock().signal_config_changed();
    }

    fn get_resample_evt(&self) -> Option<&Event> {
        // Cannot get resample event from a borrowed item.
        None
    }

    fn do_interrupt_resample(&self) {}
}

impl<I: SignalableInterrupt> SignalableInterrupt for Rc<RefCell<I>> {
    fn signal(&self, vector: u16, interrupt_status_mask: u32) {
        self.borrow().signal(vector, interrupt_status_mask);
    }

    fn signal_used_queue(&self, vector: u16) {
        self.borrow().signal_used_queue(vector);
    }

    fn signal_config_changed(&self) {
        self.borrow().signal_config_changed();
    }

    fn get_resample_evt(&self) -> Option<&Event> {
        // Cannot get resample event from a borrowed item.
        None
    }

    fn do_interrupt_resample(&self) {}
}

impl Interrupt {
    pub fn new(
        interrupt_status: Arc<AtomicUsize>,
        irq_evt_lvl: IrqLevelEvent,
        msix_config: Option<Arc<Mutex<MsixConfig>>>,
        config_msix_vector: u16,
    ) -> Interrupt {
        Interrupt {
            interrupt_status,
            transport: Transport::Pci {
                pci: TransportPci {
                    irq_evt_lvl,
                    msix_config,
                    config_msix_vector,
                },
            },
        }
    }

    pub fn new_mmio(interrupt_status: Arc<AtomicUsize>, irq_evt_edge: IrqEdgeEvent) -> Interrupt {
        Interrupt {
            interrupt_status,
            transport: Transport::Mmio { irq_evt_edge },
        }
    }

    /// Get a reference to the interrupt event.
    pub fn get_interrupt_evt(&self) -> &Event {
        match &self.transport {
            Transport::Pci { pci } => pci.irq_evt_lvl.get_trigger(),
            Transport::Mmio { irq_evt_edge } => irq_evt_edge.get_trigger(),
        }
    }

    /// Handle interrupt resampling event, reading the value from the event and doing the resample.
    pub fn interrupt_resample(&self) {
        match &self.transport {
            Transport::Pci { pci } => {
                pci.irq_evt_lvl.clear_resample();
                self.do_interrupt_resample();
            }
            _ => panic!("interrupt_resample() not supported"),
        }
    }

    /// Get a reference to the msix configuration
    pub fn get_msix_config(&self) -> &Option<Arc<Mutex<MsixConfig>>> {
        match &self.transport {
            Transport::Pci { pci } => &pci.msix_config,
            _ => &None,
        }
    }
}
<|endoftext|>