<commit_before>use crate::{
    transform::{MirPass, MirSource},
    util::patch::MirPatch,
};
use rustc_middle::mir::*;
use rustc_middle::ty::{Ty, TyCtxt};
use std::{borrow::Cow, fmt::Debug};

/// This pass optimizes something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// match (x,y) {
///     (Some(_), Some(_)) => {0},
///     _ => {1}
/// }
/// ```
/// into something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// let discriminant_x = // get discriminant of x
/// let discriminant_y = // get discriminant of x
/// if discriminant_x != discriminant_y {1} else {0}
/// ```
pub struct EarlyOtherwiseBranch;

impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
        if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
            return;
        }
        trace!("running EarlyOtherwiseBranch on {:?}", source);
        // we are only interested in this bb if the terminator is a switchInt
        let bbs_with_switch =
            body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));

        let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
            .flat_map(|(bb_idx, bb)| {
                let switch = bb.terminator();
                let helper = Helper { body, tcx };
                let infos = helper.go(bb, switch)?;
                Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
            })
            .collect();

        for opt_to_apply in opts_to_apply {
            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);
            // create the patch using MirPatch
            let mut patch = MirPatch::new(body);

            // create temp to store second discriminant in
            let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
            let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
            let temp = patch.new_temp(discr_type, discr_span);
            let statements_before =
                body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
            let end_of_block_location = Location {
                block: opt_to_apply.basic_block_first_switch,
                statement_index: statements_before,
            };
            patch.add_statement(end_of_block_location, StatementKind::StorageLive(temp));

            // create assignment of discriminant
            let place_of_adt_to_get_discriminant_of =
                opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
            patch.add_assign(
                end_of_block_location,
                Place::from(temp),
                Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
            );

            // create temp to store NotEqual comparison between the two discriminants
            let not_equal = BinOp::Ne;
            let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
            let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
            patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));

            // create NotEqual comparison between the two discriminants
            let first_descriminant_place =
                opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
            let not_equal_rvalue = Rvalue::BinaryOp(
                not_equal,
                Operand::Copy(Place::from(temp)),
                Operand::Copy(Place::from(first_descriminant_place)),
            );
            patch.add_statement(
                end_of_block_location,
                StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
            );

            let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply
                .infos
                .iter()
                .flat_map(|x| x.second_switch_info.targets_with_values.iter())
                .cloned()
                .unzip();

            // add otherwise case in the end
            targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb);
            // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
            let new_switch_data = BasicBlockData::new(Some(Terminator {
                source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
                kind: TerminatorKind::SwitchInt {
                    // the first and second discriminants are equal, so just pick one
                    discr: Operand::Copy(first_descriminant_place),
                    switch_ty: discr_type,
                    values: Cow::from(values_to_jump_to),
                    targets: targets_to_jump_to,
                },
            }));

            let new_switch_bb = patch.new_block(new_switch_data);

            // switch on the NotEqual. If true, then jump to the `otherwise` case.
            // If false, then jump to a basic block that then jumps to the correct disciminant case
            let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
            let false_case = new_switch_bb;
            patch.patch_terminator(
                opt_to_apply.basic_block_first_switch,
                TerminatorKind::if_(
                    tcx,
                    Operand::Move(Place::from(not_equal_temp)),
                    true_case,
                    false_case,
                ),
            );

            // generate StorageDead for the temp not in use anymore. We use the not_equal_temp in the switch, so we can't mark that dead
            patch.add_statement(end_of_block_location, StatementKind::StorageDead(temp));

            patch.apply(body);
        }
    }
}

fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
    match terminator.kind {
        TerminatorKind::SwitchInt { .. } => true,
        _ => false,
    }
}

struct Helper<'a, 'tcx> {
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
}

#[derive(Debug, Clone)]
struct SwitchDiscriminantInfo<'tcx> {
    /// Type of the discriminant being switched on
    discr_ty: Ty<'tcx>,
    /// The basic block that the otherwise branch points to
    otherwise_bb: BasicBlock,
    /// Target along with the value being branched from. Otherwise is not included
    targets_with_values: Vec<(BasicBlock, u128)>,
    discr_source_info: SourceInfo,
    /// The place of the discriminant used in the switch
    discr_used_in_switch: Place<'tcx>,
    /// The place of the adt that has its discriminant read
    place_of_adt_discr_read: Place<'tcx>,
    /// The type of the adt that has its discriminant read
    type_adt_matched_on: Ty<'tcx>,
}

#[derive(Debug)]
struct OptimizationToApply<'tcx> {
    infos: Vec<OptimizationInfo<'tcx>>,
    /// Basic block of the original first switch
    basic_block_first_switch: BasicBlock,
}

#[derive(Debug)]
struct OptimizationInfo<'tcx> {
    /// Info about the first switch and discriminant
    first_switch_info: SwitchDiscriminantInfo<'tcx>,
    /// Info about the second switch and discriminant
    second_switch_info: SwitchDiscriminantInfo<'tcx>,
}

impl<'a, 'tcx> Helper<'a, 'tcx> {
    pub fn go(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<Vec<OptimizationInfo<'tcx>>> {
        // try to find the statement that defines the discriminant that is used for the switch
        let discr = self.find_switch_discriminant_info(bb, switch)?;

        // go through each target, finding a discriminant read, and a switch
        let results = discr.targets_with_values.iter().map(|(target, value)| {
            self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone())
        });

        // if the optimization did not apply for one of the targets, then abort
        if results.clone().any(|x| x.is_none()) || results.len() == 0 {
            trace!("NO: not all of the targets matched the pattern for optimization");
            return None;
        }

        Some(results.flatten().collect())
    }

    fn find_discriminant_switch_pairing(
        &self,
        discr_info: &SwitchDiscriminantInfo<'tcx>,
        target: BasicBlock,
        value: u128,
    ) -> Option<OptimizationInfo<'tcx>> {
        let bb = &self.body.basic_blocks()[target];
        // find switch
        let terminator = bb.terminator();
        if is_switch(terminator) {
            let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;

            // the types of the two adts matched on have to be equalfor this optimization to apply
            if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
                trace!(
                    "NO: types do not match. LHS: {:?}, RHS: {:?}",
                    discr_info.type_adt_matched_on,
                    this_bb_discr_info.type_adt_matched_on
                );
                return None;
            }

            // the otherwise branch of the two switches have to point to the same bb
            if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
                trace!("NO: otherwise target is not the same");
                return None;
            }

            // check that the value being matched on is the same. The
            if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() {
                trace!("NO: values being matched on are not the same");
                return None;
            }

            // only allow optimization if the left and right of the tuple being matched are the same variants.
            // so the following should not optimize
            //  ```rust
            // let x: Option<()>;
            // let y: Option<()>;
            // match (x,y) {
            //     (Some(_), None) => {},
            //     _ => {}
            // }
            //  ```
            // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
            if !(this_bb_discr_info.targets_with_values.len() == 1
                && this_bb_discr_info.targets_with_values[0].1 == value)
            {
                trace!(
                    "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
                );
                return None;
            }

            // if we reach this point, the optimization applies, and we should be able to optimize this case
            // store the info that is needed to apply the optimization

            Some(OptimizationInfo {
                first_switch_info: discr_info.clone(),
                second_switch_info: this_bb_discr_info,
            })
        } else {
            None
        }
    }

    fn find_switch_discriminant_info(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<SwitchDiscriminantInfo<'tcx>> {
        match &switch.kind {
            TerminatorKind::SwitchInt { discr, targets, values, .. } => {
                let discr_local = discr.place()?.as_local()?;
                // the declaration of the discriminant read. Place of this read is being used in the switch
                let discr_decl = &self.body.local_decls()[discr_local];
                let discr_ty = discr_decl.ty;
                // the otherwise target lies as the last element
                let otherwise_bb = targets.get(values.len())?.clone();
                let targets_with_values = targets
                    .iter()
                    .zip(values.iter())
                    .map(|(t, v)| (t.clone(), v.clone()))
                    .collect();

                // find the place of the adt where the discriminant is being read from
                // assume this is the last statement of the block
                let place_of_adt_discr_read = match bb.statements.last()?.kind {
                    StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
                        Some(adt_place)
                    }
                    _ => None,
                }?;

                let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;

                Some(SwitchDiscriminantInfo {
                    discr_used_in_switch: discr.place()?,
                    discr_ty,
                    otherwise_bb,
                    targets_with_values,
                    discr_source_info: discr_decl.source_info,
                    place_of_adt_discr_read,
                    type_adt_matched_on,
                })
            }
            _ => unreachable!("must only be passed terminator that is a switch"),
        }
    }
}
<commit_msg>Update src/librustc_mir/transform/early_otherwise_branch.rs<commit_after>use crate::{
    transform::{MirPass, MirSource},
    util::patch::MirPatch,
};
use rustc_middle::mir::*;
use rustc_middle::ty::{Ty, TyCtxt};
use std::{borrow::Cow, fmt::Debug};

/// This pass optimizes something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// match (x,y) {
///     (Some(_), Some(_)) => {0},
///     _ => {1}
/// }
/// ```
/// into something like
/// ```text
/// let x: Option<()>;
/// let y: Option<()>;
/// let discriminant_x = // get discriminant of x
/// let discriminant_y = // get discriminant of y
/// if discriminant_x != discriminant_y {1} else {0}
/// ```
pub struct EarlyOtherwiseBranch;

impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
        if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
            return;
        }
        trace!("running EarlyOtherwiseBranch on {:?}", source);
        // we are only interested in this bb if the terminator is a switchInt
        let bbs_with_switch =
            body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));

        let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
            .flat_map(|(bb_idx, bb)| {
                let switch = bb.terminator();
                let helper = Helper { body, tcx };
                let infos = helper.go(bb, switch)?;
                Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
            })
            .collect();

        for opt_to_apply in opts_to_apply {
            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);
            // create the patch using MirPatch
            let mut patch = MirPatch::new(body);

            // create temp to store second discriminant in
            let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
            let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
            let temp = patch.new_temp(discr_type, discr_span);
            let statements_before =
                body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
            let end_of_block_location = Location {
                block: opt_to_apply.basic_block_first_switch,
                statement_index: statements_before,
            };
            patch.add_statement(end_of_block_location, StatementKind::StorageLive(temp));

            // create assignment of discriminant
            let place_of_adt_to_get_discriminant_of =
                opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
            patch.add_assign(
                end_of_block_location,
                Place::from(temp),
                Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
            );

            // create temp to store NotEqual comparison between the two discriminants
            let not_equal = BinOp::Ne;
            let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
            let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
            patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));

            // create NotEqual comparison between the two discriminants
            let first_descriminant_place =
                opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
            let not_equal_rvalue = Rvalue::BinaryOp(
                not_equal,
                Operand::Copy(Place::from(temp)),
                Operand::Copy(Place::from(first_descriminant_place)),
            );
            patch.add_statement(
                end_of_block_location,
                StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
            );

            let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply
                .infos
                .iter()
                .flat_map(|x| x.second_switch_info.targets_with_values.iter())
                .cloned()
                .unzip();

            // add otherwise case in the end
            targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb);
            // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
            let new_switch_data = BasicBlockData::new(Some(Terminator {
                source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
                kind: TerminatorKind::SwitchInt {
                    // the first and second discriminants are equal, so just pick one
                    discr: Operand::Copy(first_descriminant_place),
                    switch_ty: discr_type,
                    values: Cow::from(values_to_jump_to),
                    targets: targets_to_jump_to,
                },
            }));

            let new_switch_bb = patch.new_block(new_switch_data);

            // switch on the NotEqual. If true, then jump to the `otherwise` case.
            // If false, then jump to a basic block that then jumps to the correct disciminant case
            let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
            let false_case = new_switch_bb;
            patch.patch_terminator(
                opt_to_apply.basic_block_first_switch,
                TerminatorKind::if_(
                    tcx,
                    Operand::Move(Place::from(not_equal_temp)),
                    true_case,
                    false_case,
                ),
            );

            // generate StorageDead for the temp not in use anymore. We use the not_equal_temp in the switch, so we can't mark that dead
            patch.add_statement(end_of_block_location, StatementKind::StorageDead(temp));

            patch.apply(body);
        }
    }
}

fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
    match terminator.kind {
        TerminatorKind::SwitchInt { .. } => true,
        _ => false,
    }
}

struct Helper<'a, 'tcx> {
    body: &'a Body<'tcx>,
    tcx: TyCtxt<'tcx>,
}

#[derive(Debug, Clone)]
struct SwitchDiscriminantInfo<'tcx> {
    /// Type of the discriminant being switched on
    discr_ty: Ty<'tcx>,
    /// The basic block that the otherwise branch points to
    otherwise_bb: BasicBlock,
    /// Target along with the value being branched from. Otherwise is not included
    targets_with_values: Vec<(BasicBlock, u128)>,
    discr_source_info: SourceInfo,
    /// The place of the discriminant used in the switch
    discr_used_in_switch: Place<'tcx>,
    /// The place of the adt that has its discriminant read
    place_of_adt_discr_read: Place<'tcx>,
    /// The type of the adt that has its discriminant read
    type_adt_matched_on: Ty<'tcx>,
}

#[derive(Debug)]
struct OptimizationToApply<'tcx> {
    infos: Vec<OptimizationInfo<'tcx>>,
    /// Basic block of the original first switch
    basic_block_first_switch: BasicBlock,
}

#[derive(Debug)]
struct OptimizationInfo<'tcx> {
    /// Info about the first switch and discriminant
    first_switch_info: SwitchDiscriminantInfo<'tcx>,
    /// Info about the second switch and discriminant
    second_switch_info: SwitchDiscriminantInfo<'tcx>,
}

impl<'a, 'tcx> Helper<'a, 'tcx> {
    pub fn go(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<Vec<OptimizationInfo<'tcx>>> {
        // try to find the statement that defines the discriminant that is used for the switch
        let discr = self.find_switch_discriminant_info(bb, switch)?;

        // go through each target, finding a discriminant read, and a switch
        let results = discr.targets_with_values.iter().map(|(target, value)| {
            self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone())
        });

        // if the optimization did not apply for one of the targets, then abort
        if results.clone().any(|x| x.is_none()) || results.len() == 0 {
            trace!("NO: not all of the targets matched the pattern for optimization");
            return None;
        }

        Some(results.flatten().collect())
    }

    fn find_discriminant_switch_pairing(
        &self,
        discr_info: &SwitchDiscriminantInfo<'tcx>,
        target: BasicBlock,
        value: u128,
    ) -> Option<OptimizationInfo<'tcx>> {
        let bb = &self.body.basic_blocks()[target];
        // find switch
        let terminator = bb.terminator();
        if is_switch(terminator) {
            let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;

            // the types of the two adts matched on have to be equalfor this optimization to apply
            if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
                trace!(
                    "NO: types do not match. LHS: {:?}, RHS: {:?}",
                    discr_info.type_adt_matched_on,
                    this_bb_discr_info.type_adt_matched_on
                );
                return None;
            }

            // the otherwise branch of the two switches have to point to the same bb
            if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
                trace!("NO: otherwise target is not the same");
                return None;
            }

            // check that the value being matched on is the same. The
            if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() {
                trace!("NO: values being matched on are not the same");
                return None;
            }

            // only allow optimization if the left and right of the tuple being matched are the same variants.
            // so the following should not optimize
            //  ```rust
            // let x: Option<()>;
            // let y: Option<()>;
            // match (x,y) {
            //     (Some(_), None) => {},
            //     _ => {}
            // }
            //  ```
            // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
            if !(this_bb_discr_info.targets_with_values.len() == 1
                && this_bb_discr_info.targets_with_values[0].1 == value)
            {
                trace!(
                    "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
                );
                return None;
            }

            // if we reach this point, the optimization applies, and we should be able to optimize this case
            // store the info that is needed to apply the optimization

            Some(OptimizationInfo {
                first_switch_info: discr_info.clone(),
                second_switch_info: this_bb_discr_info,
            })
        } else {
            None
        }
    }

    fn find_switch_discriminant_info(
        &self,
        bb: &BasicBlockData<'tcx>,
        switch: &Terminator<'tcx>,
    ) -> Option<SwitchDiscriminantInfo<'tcx>> {
        match &switch.kind {
            TerminatorKind::SwitchInt { discr, targets, values, .. } => {
                let discr_local = discr.place()?.as_local()?;
                // the declaration of the discriminant read. Place of this read is being used in the switch
                let discr_decl = &self.body.local_decls()[discr_local];
                let discr_ty = discr_decl.ty;
                // the otherwise target lies as the last element
                let otherwise_bb = targets.get(values.len())?.clone();
                let targets_with_values = targets
                    .iter()
                    .zip(values.iter())
                    .map(|(t, v)| (t.clone(), v.clone()))
                    .collect();

                // find the place of the adt where the discriminant is being read from
                // assume this is the last statement of the block
                let place_of_adt_discr_read = match bb.statements.last()?.kind {
                    StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
                        Some(adt_place)
                    }
                    _ => None,
                }?;

                let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;

                Some(SwitchDiscriminantInfo {
                    discr_used_in_switch: discr.place()?,
                    discr_ty,
                    otherwise_bb,
                    targets_with_values,
                    discr_source_info: discr_decl.source_info,
                    place_of_adt_discr_read,
                    type_adt_matched_on,
                })
            }
            _ => unreachable!("must only be passed terminator that is a switch"),
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::atomics::AtomicBool;
use std::ptr;
use {Event, WindowBuilder};

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

mod event;
mod ffi;
mod init;
mod monitor;

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: ffi::HWND,

    /// This represents a "draw context" for the surface of the window.
    hdc: ffi::HDC,

    /// OpenGL context.
    context: ffi::HGLRC,

    /// Binded to `opengl32.dll`.
    ///
    /// `wglGetProcAddress` returns null for GL 1.1 functions because they are
    ///  already defined by the system. This module contains them.
    gl_library: ffi::HMODULE,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// True if a `Closed` event has been received.
    is_closed: AtomicBool,
}

impl Window {
    /// See the docs if the crate root file.
    pub fn new(builder: WindowBuilder) -> Result<Window, String> {
        init::new_window(builder)
    }

    /// See the docs if the crate root file.
    pub fn is_closed(&self) -> bool {
        use std::sync::atomics::Relaxed;
        self.is_closed.load(Relaxed)
    }

    /// See the docs if the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        unsafe {
            ffi::SetWindowTextW(self.window,
                text.utf16_units().collect::<Vec<u16>>().append_one(0).as_ptr() as ffi::LPCWSTR);
        }
    }

    /// See the docs if the crate root file.
    pub fn get_position(&self) -> Option<(int, int)> {
        use std::mem;

        let mut placement: ffi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<ffi::WINDOWPLACEMENT>() as ffi::UINT;

        if unsafe { ffi::GetWindowPlacement(self.window, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as int, rect.top as int))
    }

    /// See the docs if the crate root file.
    pub fn set_position(&self, x: int, y: int) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), x as libc::c_int, y as libc::c_int,
                0, 0, ffi::SWP_NOZORDER | ffi::SWP_NOSIZE);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs if the crate root file.
    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetClientRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs if the crate root file.
    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetWindowRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs if the crate root file.
    pub fn set_inner_size(&self, x: uint, y: uint) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), 0, 0, x as libc::c_int,
                y as libc::c_int, ffi::SWP_NOZORDER | ffi::SWP_NOREPOSITION);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs if the crate root file.
    // TODO: return iterator
    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();
        loop {
            match self.events_receiver.try_recv() {
                Ok(ev) => events.push(ev),
                Err(_) => break
            }
        }

        // if one of the received events is `Closed`, setting `is_closed` to true
        if events.iter().find(|e| match e { &&::Closed => true, _ => false }).is_some() {
            use std::sync::atomics::Relaxed;
            self.is_closed.store(true, Relaxed);
        }

        events
    }

    /// See the docs if the crate root file.
    // TODO: return iterator
    pub fn wait_events(&self) -> Vec<Event> {
        match self.events_receiver.recv_opt() {
            Ok(ev) => {
                // if the received event is `Closed`, setting `is_closed` to true
                match ev {
                    ::Closed => {
                        use std::sync::atomics::Relaxed;
                        self.is_closed.store(true, Relaxed);
                    },
                    _ => ()
                };

                // looing for other possible events in the queue
                let mut result = self.poll_events();
                result.insert(0, ev);
                result
            },

            Err(_) => {
                use std::sync::atomics::Relaxed;
                self.is_closed.store(true, Relaxed);
                vec![]
            }
        }
    }

    /// See the docs if the crate root file.
    pub unsafe fn make_current(&self) {
        ffi::wglMakeCurrent(self.hdc, self.context)
    }

    /// See the docs if the crate root file.
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        use std::c_str::ToCStr;

        unsafe {
            addr.with_c_str(|s| {
                let p = ffi::wglGetProcAddress(s) as *const ();
                if !p.is_null() { return p; }
                ffi::GetProcAddress(self.gl_library, s) as *const ()
            })
        }
    }

    /// See the docs if the crate root file.
    pub fn swap_buffers(&self) {
        unsafe {
            ffi::glFlush();
            ffi::SwapBuffers(self.hdc);
        }
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;
        unsafe { ffi::wglMakeCurrent(ptr::mut_null(), ptr::mut_null()); }
        unsafe { ffi::wglDeleteContext(self.context); }
        unsafe { ffi::DestroyWindow(self.window); }
    }
}
<commit_msg>Fix & add some comments for win32<commit_after>use std::sync::atomics::AtomicBool;
use std::ptr;
use {Event, WindowBuilder};

pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};

mod event;
mod ffi;
mod init;
mod monitor;

/// The Win32 implementation of the main `Window` object.
pub struct Window {
    /// Main handle for the window.
    window: ffi::HWND,

    /// This represents a "draw context" for the surface of the window.
    hdc: ffi::HDC,

    /// OpenGL context.
    context: ffi::HGLRC,

    /// Binded to `opengl32.dll`.
    ///
    /// `wglGetProcAddress` returns null for GL 1.1 functions because they are
    ///  already defined by the system. This module contains them.
    gl_library: ffi::HMODULE,

    /// Receiver for the events dispatched by the window callback.
    events_receiver: Receiver<Event>,

    /// True if a `Closed` event has been received.
    is_closed: AtomicBool,
}

impl Window {
    /// See the docs in the crate root file.
    pub fn new(builder: WindowBuilder) -> Result<Window, String> {
        init::new_window(builder)
    }

    /// See the docs in the crate root file.
    pub fn is_closed(&self) -> bool {
        use std::sync::atomics::Relaxed;
        self.is_closed.load(Relaxed)
    }

    /// See the docs in the crate root file.
    ///
    /// Calls SetWindowText on the HWND.
    pub fn set_title(&self, text: &str) {
        unsafe {
            ffi::SetWindowTextW(self.window,
                text.utf16_units().collect::<Vec<u16>>().append_one(0).as_ptr() as ffi::LPCWSTR);
        }
    }

    /// See the docs in the crate root file.
    pub fn get_position(&self) -> Option<(int, int)> {
        use std::mem;

        let mut placement: ffi::WINDOWPLACEMENT = unsafe { mem::zeroed() };
        placement.length = mem::size_of::<ffi::WINDOWPLACEMENT>() as ffi::UINT;

        if unsafe { ffi::GetWindowPlacement(self.window, &mut placement) } == 0 {
            return None
        }

        let ref rect = placement.rcNormalPosition;
        Some((rect.left as int, rect.top as int))
    }

    /// See the docs in the crate root file.
    pub fn set_position(&self, x: int, y: int) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), x as libc::c_int, y as libc::c_int,
                0, 0, ffi::SWP_NOZORDER | ffi::SWP_NOSIZE);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs in the crate root file.
    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetClientRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs in the crate root file.
    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        use std::mem;
        let mut rect: ffi::RECT = unsafe { mem::uninitialized() };

        if unsafe { ffi::GetWindowRect(self.window, &mut rect) } == 0 {
            return None
        }

        Some((
            (rect.right - rect.left) as uint,
            (rect.bottom - rect.top) as uint
        ))
    }

    /// See the docs in the crate root file.
    pub fn set_inner_size(&self, x: uint, y: uint) {
        use libc;

        unsafe {
            ffi::SetWindowPos(self.window, ptr::mut_null(), 0, 0, x as libc::c_int,
                y as libc::c_int, ffi::SWP_NOZORDER | ffi::SWP_NOREPOSITION);
            ffi::UpdateWindow(self.window);
        }
    }

    /// See the docs in the crate root file.
    // TODO: return iterator
    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();
        loop {
            match self.events_receiver.try_recv() {
                Ok(ev) => events.push(ev),
                Err(_) => break
            }
        }

        // if one of the received events is `Closed`, setting `is_closed` to true
        if events.iter().find(|e| match e { &&::Closed => true, _ => false }).is_some() {
            use std::sync::atomics::Relaxed;
            self.is_closed.store(true, Relaxed);
        }

        events
    }

    /// See the docs in the crate root file.
    // TODO: return iterator
    pub fn wait_events(&self) -> Vec<Event> {
        match self.events_receiver.recv_opt() {
            Ok(ev) => {
                // if the received event is `Closed`, setting `is_closed` to true
                match ev {
                    ::Closed => {
                        use std::sync::atomics::Relaxed;
                        self.is_closed.store(true, Relaxed);
                    },
                    _ => ()
                };

                // looing for other possible events in the queue
                let mut result = self.poll_events();
                result.insert(0, ev);
                result
            },

            Err(_) => {
                use std::sync::atomics::Relaxed;
                self.is_closed.store(true, Relaxed);
                vec![]
            }
        }
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        ffi::wglMakeCurrent(self.hdc, self.context)
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, addr: &str) -> *const () {
        use std::c_str::ToCStr;

        unsafe {
            addr.with_c_str(|s| {
                let p = ffi::wglGetProcAddress(s) as *const ();
                if !p.is_null() { return p; }
                ffi::GetProcAddress(self.gl_library, s) as *const ()
            })
        }
    }

    /// See the docs in the crate root file.
    pub fn swap_buffers(&self) {
        unsafe {
            // calling glFlush is necessary on Windows 8
            ffi::glFlush();

            ffi::SwapBuffers(self.hdc);
        }
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;
        unsafe { ffi::wglMakeCurrent(ptr::mut_null(), ptr::mut_null()); }
        unsafe { ffi::wglDeleteContext(self.context); }
        unsafe { ffi::DestroyWindow(self.window); }
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};

fn main() {
    let pb = ProgressBar::new_spinner();
    pb.enable_steady_tick(120);
    pb.set_style(
        ProgressStyle::default_spinner()
            // For more spinners check out the cli-spinners project:
            // https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json
            .tick_strings(&[
                "▹▹▹▹▹",
                "▸▹▹▹▹",
                "▹▸▹▹▹",
                "▹▹▸▹▹",
                "▹▹▹▸▹",
                "▹▹▹▹▸",
                "     ",
            ])
            .template("{spinner:.blue} {msg}"),
    );
    pb.set_message("Calculating...");
    thread::sleep(Duration::from_secs(5));
    pb.finish_with_message("Done");
}
<commit_msg>Improved long-spinner example<commit_after>use std::thread;
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};

fn main() {
    let pb = ProgressBar::new_spinner();
    pb.enable_steady_tick(120);
    pb.set_style(
        ProgressStyle::default_spinner()
            // For more spinners check out the cli-spinners project:
            // https://github.com/sindresorhus/cli-spinners/blob/master/spinners.json
            .tick_strings(&[
                "▹▹▹▹▹",
                "▸▹▹▹▹",
                "▹▸▹▹▹",
                "▹▹▸▹▹",
                "▹▹▹▸▹",
                "▹▹▹▹▸",
                "▪▪▪▪▪",
            ])
            .template("{spinner:.blue} {msg}"),
    );
    pb.set_message("Calculating...");
    thread::sleep(Duration::from_secs(5));
    pb.finish_with_message("Done");
}
<|endoftext|>


<commit_before>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::count_types;
use super::filter_by_type;
use super::get_poi_type_ids;
use super::get_types;
use super::get_value;
use super::get_values;
use super::BragiHandler;
use mimir::{MimirObject, Poi};
use serde_json::json;

pub fn bragi_poi_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let mut bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // We load three-cities bano dataset and then the OSM dataset (with the POIs)
    // the current dataset are thus (load order matters):
    // - bano-three_cities
    // - osm_fixture.osm.pbf (including ways and pois)
    // ******************************************
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    crate::launch_and_assert(
        bano2mimir,
        vec![
            "--input=./tests/fixtures/bano-three_cities.csv".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    crate::launch_and_assert(
        osm2mimir,
        vec![
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-admin".into(),
            "--import-way".into(),
            "--import-poi".into(),
            "--level=8".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    poi_admin_address_test(&mut bragi);
    poi_admin_test(&mut bragi);
    poi_zip_code_test(&mut bragi);
    poi_from_osm_test(&mut bragi);
    poi_misspelt_one_word_admin_test(&mut bragi);
    poi_from_osm_with_address_addr_test(&mut bragi);
}

fn poi_admin_address_test(bragi: &mut BragiHandler) {
    let geocodings = bragi.get("/autocomplete?q=Le-Mée-sur-Seine Courtilleraies");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 1);

    // the first element returned should be the poi 'Le-Mée-sur-Seine Courtilleraies'
    let poi = geocodings.first().unwrap();
    let properties = poi
        .get("properties")
        .and_then(|json| json.as_array())
        .unwrap();
    let keys = [
        "addr:postcode",
        "amenity",
        "atm",
        "name",
        "operator",
        "phone",
        "ref:FR:LaPoste",
        "source",
        "wheelchair",
    ];
    for p in properties {
        let key = p["key"].as_str().unwrap();
        assert!(keys.contains(&key));
    }
    assert_eq!(properties.len(), keys.len());
    assert_eq!(get_value(poi, "type"), Poi::doc_type());
    assert_eq!(get_value(poi, "label"), "Le-Mée-sur-Seine Courtilleraies");
    assert_eq!(get_value(poi, "postcode"), "77350");
}

fn poi_admin_test(bragi: &mut BragiHandler) {
    // with this search we should be able to find a poi called Melun Rp
    let geocodings = bragi.get("/autocomplete?q=Melun Rp");
    let types = get_types(&geocodings);
    let count = count_types(&types, Poi::doc_type());
    assert!(count >= 1);

    assert!(get_values(&geocodings, "label").contains(&"Melun Rp (Melun)",));

    // when we search for just 'Melun', we should find some places in melun
    let geocodings = bragi.get("/autocomplete?q=Melun");
    for postcodes in get_values(&geocodings, "postcode") {
        assert!(postcodes.split(';').any(|p| p == "77000"));
    }
    // we should also be able to find the city of melun which will carry more postcodes
    let cities = filter_by_type(&geocodings, "city");
    assert_eq!(cities.len(), 1);
    let melun = &cities.first().unwrap();
    assert_eq!(get_value(melun, "name"), "Melun");
    assert_eq!(get_value(melun, "postcode"), "77000;77003;77008;CP77001");
    assert_eq!(get_value(melun, "label"), "Melun (77000-CP77001)");
}

fn poi_zip_code_test(bragi: &mut BragiHandler) {
    // search by zip code
    let geocodings = bragi.get("/autocomplete?q=77000&limit=15");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 2);
    assert_eq!(count_types(&types, "city"), 3);
    assert_eq!(count_types(&types, "street"), 8);

    // search by zip code and limit is string type
    let geocodings = bragi.get_unchecked_json("/autocomplete?q=77000&limit=ABCD");
    assert_eq!(
        geocodings,
        (
            actix_web::http::StatusCode::BAD_REQUEST,
            json!({
                "short": "validation error",
                "long": "invalid argument: failed with reason: invalid digit found in string",
            })
        )
    );

    // search by zip code and limit < 0
    let geocodings = bragi.get_unchecked_json("/autocomplete?q=77000&limit=-1");
    assert_eq!(
        geocodings,
        (
            actix_web::http::StatusCode::BAD_REQUEST,
            json!({
                "short": "validation error",
                "long": "invalid argument: failed with reason: invalid digit found in string",
            })
        )
    );

    // search by zip code and limit and offset
    let all_20 = bragi.get("/autocomplete?q=77000&limit=10&offset=0");
    assert_eq!(all_20.len(), 10);

    let all_20 = bragi.get("/autocomplete?q=77000&limit=10&offset=10");
    assert_eq!(all_20.len(), 3);
}

fn poi_from_osm_test(bragi: &mut BragiHandler) {
    // search poi: Poi as a relation in osm data
    let geocodings = bragi.get("/autocomplete?q=Parking (Le Coudray-Montceaux)");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 1);
    let first_poi = geocodings
        .iter()
        .find(|e| get_value(e, "type") == Poi::doc_type())
        .unwrap();
    assert_eq!(get_value(first_poi, "citycode"), "91179");
    assert_eq!(get_poi_type_ids(first_poi), &["poi_type:amenity:parking"]);

    // search poi: Poi as a way in osm data
    let geocodings = bragi.get("/autocomplete?q=77000 Hôtel de Ville (Melun)");
    let types = get_types(&geocodings);
    assert!(count_types(&types, Poi::doc_type()) >= 1);
    let poi = geocodings.first().unwrap();
    assert_eq!(get_value(poi, "type"), Poi::doc_type());
    assert_eq!(get_value(poi, "id"), "poi:osm:way:112361498");
    assert_eq!(get_value(poi, "label"), "Hôtel de Ville (Melun)");
    assert_eq!(get_poi_type_ids(poi), &["poi_type:amenity:townhall"]);

    // we search for POIs with a type but an empty name, we should have set the name with the type.
    // for exemple there are parkings without name (but with the tag "anemity" = "Parking"),
    // we should be able to query them
    let geocodings = bragi.get("/autocomplete?q=Parking");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 8);

    // we search for a POI (id = 2561223) with a label but an empty coord
    // (barycenter not computed so far), it should be filtered.
    let geocodings = bragi.get("/autocomplete?q=ENSE3 site Ampère");
    // we can find other results (due to the fuzzy search, but we can't find the 'site Ampère')
    assert!(!get_values(&geocodings, "label").contains(&"ENSE3 site Ampère",));
}

fn poi_misspelt_one_word_admin_test(bragi: &mut BragiHandler) {
    // with this search we should be able to find a poi called "Melun"
    let geocodings = bragi.get("/autocomplete?q=Melun");
    let types = get_types(&geocodings);
    let count = count_types(&types, Poi::doc_type());
    assert!(count >= 1);
    assert!(get_values(&geocodings, "label").contains(&"Melun Rp (Melun)",));

    // when we search for 'Meluuun', we should find some places in melun
    let geocodings = bragi.get("/autocomplete?q=Meluuun");
    for postcodes in get_values(&geocodings, "postcode") {
        assert!(postcodes.split(';').any(|p| p == "77000"));
    }
    // we should also be able to find the city of melun which will carry more postcodes
    let cities = filter_by_type(&geocodings, "city");
    assert_eq!(cities.len(), 1);
    let melun = &cities.first().unwrap();
    assert_eq!(get_value(melun, "name"), "Melun");
}

fn poi_from_osm_with_address_addr_test(bragi: &mut BragiHandler) {
    // search poi: Poi as a way in osm data
    let geocodings = bragi.get("/autocomplete?q=77000 Hôtel de Ville (Melun)");
    let types = get_types(&geocodings);
    assert!(count_types(&types, Poi::doc_type()) >= 1);
    let poi = geocodings.first().unwrap();
    assert_eq!(get_value(poi, "type"), Poi::doc_type());
    assert_eq!(get_value(poi, "id"), "poi:osm:way:112361498");

    assert_eq!(
        poi.get("address").and_then(|a| a.pointer("/housenumber")),
        Some(&json!("2"))
    );
    assert_eq!(
        poi.get("address").and_then(|a| a.pointer("/id")),
        Some(&json!("addr:2.65801;48.53685"))
    );
    assert_eq!(
        poi.get("address").and_then(|a| a.pointer("/label")),
        Some(&json!("2 Rue de la Reine Blanche (Melun)"))
    );
}

// test 'labels' and 'names' fields work with i18n queries
pub fn test_i18n_poi(mut es: crate::ElasticSearchWrapper<'_>) {
    // we define a simple test poi with 2 langs ('it' and 'es')
    let i18n_poi = mimir::Poi {
        id: "".to_string(),
        label: "Colosseo (Roma)".to_string(),
        name: "Colosseo".to_string(),
        coord: mimir::Coord(geo::Coordinate { x: 0.0, y: 0.0 }),
        administrative_regions: vec![],
        weight: 0.0,
        zip_codes: vec![],
        poi_type: mimir::PoiType {
            id: "".to_string(),
            name: "".to_string(),
        },
        properties: vec![],
        address: None,
        names: mimir::I18nProperties(vec![
            mimir::Property {
                key: "fr".to_string(),
                value: "Colisée".to_string(),
            },
            mimir::Property {
                key: "es".to_string(),
                value: "Coliseo".to_string(),
            },
        ]),
        labels: mimir::I18nProperties(vec![
            mimir::Property {
                key: "fr".to_string(),
                value: "Colisée (Rome)".to_string(),
            },
            mimir::Property {
                key: "es".to_string(),
                value: "Coliseo (Roma)".to_string(),
            },
        ]),
        distance: None,
    };

    let index_settings = mimir::rubber::IndexSettings {
        nb_shards: 2,
        nb_replicas: 1,
    };
    // we index the poi above
    let result = es
        .rubber
        .index("munin_poi", &index_settings, std::iter::once(i18n_poi));

    es.refresh();

    let mut bragi = BragiHandler::new(format!("{}/munin", es.host()));

    // We look for the Colisée in spanish
    let poi = bragi.get("/autocomplete?q=Coliseo&lang=es");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Coliseo");
    assert_eq!(result["label"], "Coliseo (Roma)");

    // We look for the Colisée in french
    let poi = bragi.get("/autocomplete?q=Colisée&lang=fr");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Colisée");
    assert_eq!(result["label"], "Colisée (Rome)");

    // We look for the Colisée in italian
    let poi = bragi.get("/autocomplete?q=Colosseo&lang=it");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Colosseo");
    assert_eq!(result["label"], "Colosseo (Roma)");

    // We look for the Colisée in russian: since it has not been
    // indexed in russian we expect the default name and label (ie the
    // local ones: italian).
    let poi = bragi.get("/autocomplete?q=Colisée&lang=ru");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Colosseo");
    assert_eq!(result["label"], "Colosseo (Roma)");
}
<commit_msg>better test doc<commit_after>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use super::count_types;
use super::filter_by_type;
use super::get_poi_type_ids;
use super::get_types;
use super::get_value;
use super::get_values;
use super::BragiHandler;
use mimir::{MimirObject, Poi};
use serde_json::json;

pub fn bragi_poi_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let mut bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // We load three-cities bano dataset and then the OSM dataset (with the POIs)
    // the current dataset are thus (load order matters):
    // - bano-three_cities
    // - osm_fixture.osm.pbf (including ways and pois)
    // ******************************************
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    crate::launch_and_assert(
        bano2mimir,
        vec![
            "--input=./tests/fixtures/bano-three_cities.csv".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    crate::launch_and_assert(
        osm2mimir,
        vec![
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-admin".into(),
            "--import-way".into(),
            "--import-poi".into(),
            "--level=8".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    poi_admin_address_test(&mut bragi);
    poi_admin_test(&mut bragi);
    poi_zip_code_test(&mut bragi);
    poi_from_osm_test(&mut bragi);
    poi_misspelt_one_word_admin_test(&mut bragi);
    poi_from_osm_with_address_addr_test(&mut bragi);
}

fn poi_admin_address_test(bragi: &mut BragiHandler) {
    let geocodings = bragi.get("/autocomplete?q=Le-Mée-sur-Seine Courtilleraies");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 1);

    // the first element returned should be the poi 'Le-Mée-sur-Seine Courtilleraies'
    let poi = geocodings.first().unwrap();
    let properties = poi
        .get("properties")
        .and_then(|json| json.as_array())
        .unwrap();
    let keys = [
        "addr:postcode",
        "amenity",
        "atm",
        "name",
        "operator",
        "phone",
        "ref:FR:LaPoste",
        "source",
        "wheelchair",
    ];
    for p in properties {
        let key = p["key"].as_str().unwrap();
        assert!(keys.contains(&key));
    }
    assert_eq!(properties.len(), keys.len());
    assert_eq!(get_value(poi, "type"), Poi::doc_type());
    assert_eq!(get_value(poi, "label"), "Le-Mée-sur-Seine Courtilleraies");
    assert_eq!(get_value(poi, "postcode"), "77350");
}

fn poi_admin_test(bragi: &mut BragiHandler) {
    // with this search we should be able to find a poi called Melun Rp
    let geocodings = bragi.get("/autocomplete?q=Melun Rp");
    let types = get_types(&geocodings);
    let count = count_types(&types, Poi::doc_type());
    assert!(count >= 1);

    assert!(get_values(&geocodings, "label").contains(&"Melun Rp (Melun)",));

    // when we search for just 'Melun', we should find some places in melun
    let geocodings = bragi.get("/autocomplete?q=Melun");
    for postcodes in get_values(&geocodings, "postcode") {
        assert!(postcodes.split(';').any(|p| p == "77000"));
    }
    // we should also be able to find the city of melun which will carry more postcodes
    let cities = filter_by_type(&geocodings, "city");
    assert_eq!(cities.len(), 1);
    let melun = &cities.first().unwrap();
    assert_eq!(get_value(melun, "name"), "Melun");
    assert_eq!(get_value(melun, "postcode"), "77000;77003;77008;CP77001");
    assert_eq!(get_value(melun, "label"), "Melun (77000-CP77001)");
}

fn poi_zip_code_test(bragi: &mut BragiHandler) {
    // search by zip code
    let geocodings = bragi.get("/autocomplete?q=77000&limit=15");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 2);
    assert_eq!(count_types(&types, "city"), 3);
    assert_eq!(count_types(&types, "street"), 8);

    // search by zip code and limit is string type
    let geocodings = bragi.get_unchecked_json("/autocomplete?q=77000&limit=ABCD");
    assert_eq!(
        geocodings,
        (
            actix_web::http::StatusCode::BAD_REQUEST,
            json!({
                "short": "validation error",
                "long": "invalid argument: failed with reason: invalid digit found in string",
            })
        )
    );

    // search by zip code and limit < 0
    let geocodings = bragi.get_unchecked_json("/autocomplete?q=77000&limit=-1");
    assert_eq!(
        geocodings,
        (
            actix_web::http::StatusCode::BAD_REQUEST,
            json!({
                "short": "validation error",
                "long": "invalid argument: failed with reason: invalid digit found in string",
            })
        )
    );

    // search by zip code and limit and offset
    let all_20 = bragi.get("/autocomplete?q=77000&limit=10&offset=0");
    assert_eq!(all_20.len(), 10);

    let all_20 = bragi.get("/autocomplete?q=77000&limit=10&offset=10");
    assert_eq!(all_20.len(), 3);
}

fn poi_from_osm_test(bragi: &mut BragiHandler) {
    // search poi: Poi as a relation in osm data
    let geocodings = bragi.get("/autocomplete?q=Parking (Le Coudray-Montceaux)");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 1);
    let first_poi = geocodings
        .iter()
        .find(|e| get_value(e, "type") == Poi::doc_type())
        .unwrap();
    assert_eq!(get_value(first_poi, "citycode"), "91179");
    assert_eq!(get_poi_type_ids(first_poi), &["poi_type:amenity:parking"]);

    // search poi: Poi as a way in osm data
    let geocodings = bragi.get("/autocomplete?q=77000 Hôtel de Ville (Melun)");
    let types = get_types(&geocodings);
    assert!(count_types(&types, Poi::doc_type()) >= 1);
    let poi = geocodings.first().unwrap();
    assert_eq!(get_value(poi, "type"), Poi::doc_type());
    assert_eq!(get_value(poi, "id"), "poi:osm:way:112361498");
    assert_eq!(get_value(poi, "label"), "Hôtel de Ville (Melun)");
    assert_eq!(get_poi_type_ids(poi), &["poi_type:amenity:townhall"]);

    // we search for POIs with a type but an empty name, we should have set the name with the type.
    // for exemple there are parkings without name (but with the tag "anemity" = "Parking"),
    // we should be able to query them
    let geocodings = bragi.get("/autocomplete?q=Parking");
    let types = get_types(&geocodings);
    assert_eq!(count_types(&types, Poi::doc_type()), 8);

    // we search for a POI (id = 2561223) with a label but an empty coord
    // (barycenter not computed so far), it should be filtered.
    let geocodings = bragi.get("/autocomplete?q=ENSE3 site Ampère");
    // we can find other results (due to the fuzzy search, but we can't find the 'site Ampère')
    assert!(!get_values(&geocodings, "label").contains(&"ENSE3 site Ampère",));
}

fn poi_misspelt_one_word_admin_test(bragi: &mut BragiHandler) {
    // with this search we should be able to find a poi called "Melun"
    let geocodings = bragi.get("/autocomplete?q=Melun");
    let types = get_types(&geocodings);
    let count = count_types(&types, Poi::doc_type());
    assert!(count >= 1);
    assert!(get_values(&geocodings, "label").contains(&"Melun Rp (Melun)",));

    // when we search for 'Meluuun', we should find some places in melun
    let geocodings = bragi.get("/autocomplete?q=Meluuun");
    for postcodes in get_values(&geocodings, "postcode") {
        assert!(postcodes.split(';').any(|p| p == "77000"));
    }
    // we should also be able to find the city of melun which will carry more postcodes
    let cities = filter_by_type(&geocodings, "city");
    assert_eq!(cities.len(), 1);
    let melun = &cities.first().unwrap();
    assert_eq!(get_value(melun, "name"), "Melun");
}

fn poi_from_osm_with_address_addr_test(bragi: &mut BragiHandler) {
    // search poi: Poi as a way in osm data
    let geocodings = bragi.get("/autocomplete?q=77000 Hôtel de Ville (Melun)");
    let types = get_types(&geocodings);
    assert!(count_types(&types, Poi::doc_type()) >= 1);
    let poi = geocodings.first().unwrap();
    assert_eq!(get_value(poi, "type"), Poi::doc_type());
    assert_eq!(get_value(poi, "id"), "poi:osm:way:112361498");

    assert_eq!(
        poi.get("address").and_then(|a| a.pointer("/housenumber")),
        Some(&json!("2"))
    );
    assert_eq!(
        poi.get("address").and_then(|a| a.pointer("/id")),
        Some(&json!("addr:2.65801;48.53685"))
    );
    assert_eq!(
        poi.get("address").and_then(|a| a.pointer("/label")),
        Some(&json!("2 Rue de la Reine Blanche (Melun)"))
    );
}

// test 'labels' and 'names' fields work with i18n queries
pub fn test_i18n_poi(mut es: crate::ElasticSearchWrapper<'_>) {
    // we define a simple test italian poi (the 'Colosseo'
    // with 2 langs for labels and names fields ('fr' and 'es')
    let colosseo = mimir::Poi {
        id: "".to_string(),
        label: "Colosseo (Roma)".to_string(),
        name: "Colosseo".to_string(),
        coord: mimir::Coord(geo::Coordinate { x: 0.0, y: 0.0 }),
        administrative_regions: vec![],
        weight: 0.0,
        zip_codes: vec![],
        poi_type: mimir::PoiType {
            id: "".to_string(),
            name: "".to_string(),
        },
        properties: vec![],
        address: None,
        names: mimir::I18nProperties(vec![
            mimir::Property {
                key: "fr".to_string(),
                value: "Colisée".to_string(),
            },
            mimir::Property {
                key: "es".to_string(),
                value: "Coliseo".to_string(),
            },
        ]),
        labels: mimir::I18nProperties(vec![
            mimir::Property {
                key: "fr".to_string(),
                value: "Colisée (Rome)".to_string(),
            },
            mimir::Property {
                key: "es".to_string(),
                value: "Coliseo (Roma)".to_string(),
            },
        ]),
        distance: None,
    };

    let index_settings = mimir::rubber::IndexSettings {
        nb_shards: 2,
        nb_replicas: 1,
    };
    // we index the poi above
    let result = es
        .rubber
        .index("munin_poi", &index_settings, std::iter::once(colosseo));

    es.refresh();

    let mut bragi = BragiHandler::new(format!("{}/munin", es.host()));

    // We look for the Colisée in spanish
    let poi = bragi.get("/autocomplete?q=Coliseo&lang=es");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Coliseo");
    assert_eq!(result["label"], "Coliseo (Roma)");

    // We look for the Colisée in french
    let poi = bragi.get("/autocomplete?q=Colisée&lang=fr");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Colisée");
    assert_eq!(result["label"], "Colisée (Rome)");

    // We look for the Colisée in italian: since it has not been
    // indexed in russian we expect the default name and label (ie the
    // local ones: italian).
    let poi = bragi.get("/autocomplete?q=Colosseo&lang=it");
    let result = poi.first().unwrap();
    assert_eq!(result["name"], "Colosseo");
    assert_eq!(result["label"], "Colosseo (Roma)");
}
<|endoftext|>


<commit_before>extern crate tempdir;

use self::tempdir::TempDir;
use super::mpd;
use std::fs::{File, create_dir};
use std::io::{Write, Read};
use std::os::unix::net::UnixStream;
use std::path::{Path, PathBuf};
use std::process::{Command, Child, Stdio};

struct MpdConfig {
    db_file: PathBuf,
    music_directory: PathBuf,
    playlist_directory: PathBuf,
    sticker_file: PathBuf,
    config_path: PathBuf,
    sock_path: PathBuf,
}

impl MpdConfig {
    pub fn new<P>(base: P) -> MpdConfig
        where P: AsRef<Path>
    {
        let base = base.as_ref();
        MpdConfig {
            db_file: base.join("db"),
            music_directory: base.join("music"),
            playlist_directory: base.join("playlists"),
            sticker_file: base.join("sticker_file"),
            config_path: base.join("config"),
            sock_path: base.join("sock"),
        }
    }

    fn config_text(&self) -> String {
        format!(r#"
db_file "{db_file}"
log_file "/dev/null"
music_directory "{music_directory}"
playlist_directory "{playlist_directory}"
sticker_file "{sticker_file}"
bind_to_address "{sock_path}"
audio_output {{
    type "null"
    name "null"
}}
"#,
            db_file=self.db_file.display(),
            music_directory=self.music_directory.display(),
            playlist_directory=self.playlist_directory.display(),
            sticker_file=self.sticker_file.display(),
            sock_path=self.sock_path.display(),
        )
    }

    fn generate(&self) {
        create_dir(&self.music_directory).expect("Could not create music directory.");
        create_dir(&self.playlist_directory).expect("Could not create playlist directory.");
        let mut file = File::create(&self.config_path).expect("Could not create config file.");
        file.write_all(self.config_text().as_bytes()).expect("Could not write config file.");
    }
}

pub struct Daemon {
    // Saved here so it gets dropped when this does.
    _temp_dir: TempDir,
    config: MpdConfig,
    process: Child,
}

impl Drop for Daemon {
    fn drop(&mut self) {
        self.process.kill().expect("Could not kill mpd daemon.");
        self.process.wait().expect("Could not wait for mpd daemon to shutdown.");
        if let Some(ref mut stderr) = self.process.stderr {
            let mut output = String::new();
            stderr.read_to_string(&mut output).expect("Could not collect output from mpd.");
            println!{"Output from mpd:"}
            println!{"{}", output};
        }
    }
}

fn sleep() {
    use std::{thread, time};
    let ten_millis = time::Duration::from_millis(10);
    thread::sleep(ten_millis);
}

static EMPTY_FLAC_BYTES: &'static [u8] = include_bytes!("../data/empty.flac");

impl Daemon {
    pub fn start() -> Daemon {
        let temp_dir = TempDir::new("mpd-test").unwrap();
        let config = MpdConfig::new(&temp_dir);
        config.generate();

        File::create(config.music_directory.join("empty.flac"))
            .unwrap()
            .write_all(EMPTY_FLAC_BYTES)
            .unwrap();

        let process = Command::new("mpd")
            .arg("--no-daemon")
            .arg(&config.config_path)
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::piped())
            .spawn()
            .expect("Could not create mpd daemon.");

        let daemon = Daemon {
            _temp_dir: temp_dir,
            config: config,
            process: process,
        };

        // Wait until we can connect to the daemon
        let mut client;
        loop {
            if let Ok(c) = daemon.maybe_connect() {
                client = c;
                break;
            }
            sleep()
        }
        while let Some(_) = client.status().expect("Couldn't get status.").updating_db {
            sleep()
        }

        daemon
    }

    fn maybe_connect(&self) -> Result<mpd::Client<UnixStream>, mpd::error::Error> {
        let stream = UnixStream::connect(&self.config.sock_path)?;
        mpd::Client::new(stream)
    }

    pub fn connect(&self) -> mpd::Client<UnixStream> {
        self.maybe_connect().expect("Could not connect to daemon.")
    }
}
<commit_msg>Add a TODO.<commit_after>extern crate tempdir;

use self::tempdir::TempDir;
use super::mpd;
use std::fs::{File, create_dir};
use std::io::{Write, Read};
use std::os::unix::net::UnixStream;
use std::path::{Path, PathBuf};
use std::process::{Command, Child, Stdio};

struct MpdConfig {
    db_file: PathBuf,
    music_directory: PathBuf,
    playlist_directory: PathBuf,
    sticker_file: PathBuf,
    config_path: PathBuf,
    sock_path: PathBuf,
}

impl MpdConfig {
    pub fn new<P>(base: P) -> MpdConfig
        where P: AsRef<Path>
    {
        let base = base.as_ref();
        MpdConfig {
            db_file: base.join("db"),
            music_directory: base.join("music"),
            playlist_directory: base.join("playlists"),
            sticker_file: base.join("sticker_file"),
            config_path: base.join("config"),
            sock_path: base.join("sock"),
        }
    }

    fn config_text(&self) -> String {
        format!(r#"
db_file "{db_file}"
log_file "/dev/null"
music_directory "{music_directory}"
playlist_directory "{playlist_directory}"
sticker_file "{sticker_file}"
bind_to_address "{sock_path}"
audio_output {{
    type "null"
    name "null"
}}
"#,
            db_file=self.db_file.display(),
            music_directory=self.music_directory.display(),
            playlist_directory=self.playlist_directory.display(),
            sticker_file=self.sticker_file.display(),
            sock_path=self.sock_path.display(),
        )
    }

    fn generate(&self) {
        create_dir(&self.music_directory).expect("Could not create music directory.");
        create_dir(&self.playlist_directory).expect("Could not create playlist directory.");
        let mut file = File::create(&self.config_path).expect("Could not create config file.");
        file.write_all(self.config_text().as_bytes()).expect("Could not write config file.");
    }
}

pub struct Daemon {
    // Saved here so it gets dropped when this does.
    _temp_dir: TempDir,
    config: MpdConfig,
    process: Child,
}

impl Drop for Daemon {
    fn drop(&mut self) {
        self.process.kill().expect("Could not kill mpd daemon.");
        self.process.wait().expect("Could not wait for mpd daemon to shutdown.");
        if let Some(ref mut stderr) = self.process.stderr {
            let mut output = String::new();
            stderr.read_to_string(&mut output).expect("Could not collect output from mpd.");
            println!{"Output from mpd:"}
            println!{"{}", output};
        }
    }
}

fn sleep() {
    use std::{thread, time};
    let ten_millis = time::Duration::from_millis(10);
    thread::sleep(ten_millis);
}

static EMPTY_FLAC_BYTES: &'static [u8] = include_bytes!("../data/empty.flac");

impl Daemon {
    pub fn start() -> Daemon {
        let temp_dir = TempDir::new("mpd-test").unwrap();
        let config = MpdConfig::new(&temp_dir);
        config.generate();

        // TODO: Factor out putting files in the music directory.
        File::create(config.music_directory.join("empty.flac"))
            .unwrap()
            .write_all(EMPTY_FLAC_BYTES)
            .unwrap();

        let process = Command::new("mpd")
            .arg("--no-daemon")
            .arg(&config.config_path)
            .stdin(Stdio::null())
            .stdout(Stdio::null())
            .stderr(Stdio::piped())
            .spawn()
            .expect("Could not create mpd daemon.");

        let daemon = Daemon {
            _temp_dir: temp_dir,
            config: config,
            process: process,
        };

        // Wait until we can connect to the daemon
        let mut client;
        loop {
            if let Ok(c) = daemon.maybe_connect() {
                client = c;
                break;
            }
            sleep()
        }
        while let Some(_) = client.status().expect("Couldn't get status.").updating_db {
            sleep()
        }

        daemon
    }

    fn maybe_connect(&self) -> Result<mpd::Client<UnixStream>, mpd::error::Error> {
        let stream = UnixStream::connect(&self.config.sock_path)?;
        mpd::Client::new(stream)
    }

    pub fn connect(&self) -> mpd::Client<UnixStream> {
        self.maybe_connect().expect("Could not connect to daemon.")
    }
}
<|endoftext|>


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

//! An example of using perlin noise

extern crate noise;

use noise::{Perlin, Seedable};

mod debug;

fn main() {
    debug::render_noise_module("perlin.png", Perlin::new(), 1024, 1024, 50);
    debug::render_noise_module("perlin.png", Perlin::new().set_seed(1), 1024, 1024, 50);
}
<commit_msg>Rename result images in Perlin example<commit_after>// Copyright 2015 The Noise-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An example of using perlin noise

extern crate noise;

use noise::{Perlin, Seedable};

mod debug;

fn main() {
    debug::render_noise_module("perlin1.png", Perlin::new(), 1024, 1024, 50);
    debug::render_noise_module("perlin2.png", Perlin::new().set_seed(1), 1024, 1024, 50);
}
<|endoftext|>


<commit_before>#![feature(io, path, fs)]
extern crate env_logger;
extern crate handlebars;
extern crate "rustc-serialize" as serialize;

use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::Path;
use std::collections::BTreeMap;

use handlebars::{Handlebars, RenderError, RenderContext, Helper, Context};
use serialize::json::{Json, ToJson};

fn format_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
    let param = h.params().get(0).unwrap();
    Ok(format!("{} pts", c.navigate(rc.get_path(), param)))
}

fn load_template(name: &str) -> io::Result<String> {
    let path = Path::new(name);

    let mut file = try!(File::open(path));
    let mut s = String::new();
    try!(file.read_to_string(&mut s));
    Ok(s)
}

fn make_data () -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let mut teams = Vec::new();

    for v in vec![("Jiangsu", 43u16), ("Beijing", 27u16), ("Guangzhou", 22u16), ("Shandong", 12u16)].iter() {
        let (name, score) = *v;
        let mut t = BTreeMap::new();
        t.insert("name".to_string(), name.to_json());
        t.insert("score".to_string(), score.to_json());
        teams.push(t)
    }

    data.insert("teams".to_string(), teams.to_json());
    data
}

fn main() {
    env_logger::init().unwrap();
    let mut handlebars = Handlebars::new();

    let t = load_template("./examples/template.hbs").ok().unwrap();
    handlebars.register_template_string("table", t)
        .ok().expect("template creation failed");

    handlebars.register_helper("format", Box::new(format_helper));
//    handlebars.register_helper("format", Box::new(FORMAT_HELPER));

    let data = make_data();
    println!("{}", handlebars.render("table", &data).ok().unwrap());
}
<commit_msg>(fix) rustup<commit_after>#![feature(io, path)]
extern crate env_logger;
extern crate handlebars;
extern crate "rustc-serialize" as serialize;

use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::Path;
use std::collections::BTreeMap;

use handlebars::{Handlebars, RenderError, RenderContext, Helper, Context};
use serialize::json::{Json, ToJson};

fn format_helper (c: &Context, h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<String, RenderError> {
    let param = h.params().get(0).unwrap();
    Ok(format!("{} pts", c.navigate(rc.get_path(), param)))
}

fn load_template(name: &str) -> io::Result<String> {
    let path = Path::new(name);

    let mut file = try!(File::open(path));
    let mut s = String::new();
    try!(file.read_to_string(&mut s));
    Ok(s)
}

fn make_data () -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let mut teams = Vec::new();

    for v in vec![("Jiangsu", 43u16), ("Beijing", 27u16), ("Guangzhou", 22u16), ("Shandong", 12u16)].iter() {
        let (name, score) = *v;
        let mut t = BTreeMap::new();
        t.insert("name".to_string(), name.to_json());
        t.insert("score".to_string(), score.to_json());
        teams.push(t)
    }

    data.insert("teams".to_string(), teams.to_json());
    data
}

fn main() {
    env_logger::init().unwrap();
    let mut handlebars = Handlebars::new();

    let t = load_template("./examples/template.hbs").ok().unwrap();
    handlebars.register_template_string("table", t)
        .ok().expect("template creation failed");

    handlebars.register_helper("format", Box::new(format_helper));
//    handlebars.register_helper("format", Box::new(FORMAT_HELPER));

    let data = make_data();
    println!("{}", handlebars.render("table", &data).ok().unwrap());
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate harfbuzz_rs;
extern crate image as piston_image;
extern crate rusttype;
extern crate glfw_window;

use harfbuzz_rs::{Face, UnicodeBuffer};
use harfbuzz_rs::rusttype::{rusttype_font_from_face, rusttype_scale_from_hb_font};

use piston_window::*;
use piston_image::{ImageBuffer, Rgba};
use glfw_window::GlfwWindow;

fn main() {
    let mut window: PistonWindow<GlfwWindow> = WindowSettings::new("Hello World!", [512; 2])
        .build()
        .unwrap();

    window.set_swap_buffers(true);
    let glyphs = shape(&mut window);

    println!("window size {:?}", window.window.size());
    println!("window draw size {:?}", window.draw_size());
    println!("render target view dimensions {:?}",
             window.output_color.get_dimensions());

    while let Some(e) = window.next() {
        window.draw_2d(&e, |c, g| {
            clear([1.0, 1.0, 1.0, 1.0], g);
            for &(image, ref texture) in &glyphs {
                image.draw(texture, &DrawState::default(), c.transform, g);
            }
        });
    }
}

fn shape<T: Window>(win: &mut PistonWindow<T>) -> Vec<(Image, G2dTexture)> {
    let index = 0;
    let path = "testfiles/Optima.ttc";
    let mut font = Face::from_file(path, index)
        .expect("Error reading font file.")
        .create_font();

    let s_factor: f64 = 0.5;
    let fontsize = 30.0 / s_factor;
    font.set_scale(fontsize as i32 * 64, fontsize as i32 * 64);
    font.set_ppem(96 * 64, 96 * 64);

    let rt_font = rusttype_font_from_face(&font.face());
    let scale = rusttype_scale_from_hb_font(&font);

    // Create a buffer with some text and shape it...
    let result = UnicodeBuffer::new().add_str("Hello World! fi fl ff").shape(&font, &[]);

    // ... and get the results.
    let positions = result.get_glyph_positions();
    let infos = result.get_glyph_infos();

    let mut cursor = (0, 0);
    let mut vec = Vec::with_capacity(result.len());
    // iterate over the shaped glyphs
    for (position, info) in positions.iter().zip(infos) {
        let gid = info.codepoint;
        let x_advance = position.x_advance;
        let x_offset = position.x_offset;
        let y_offset = position.y_offset;

        let x_pos: f64 = (cursor.0 + x_offset) as f64 / 64.0;
        let y_pos: f64 = (cursor.1 + y_offset) as f64 / 64.0;

        cursor.0 += x_advance;

        let glyph = match rt_font.glyph(rusttype::GlyphId(gid)) {
            Some(glyph) => glyph,
            None => continue,
        };

        let glyph = glyph.scaled(scale).positioned(rusttype::Point {
            x: x_pos as f32,
            y: y_pos as f32,
        });
        let bbox = match glyph.pixel_bounding_box() {
            Some(bbox) => bbox,
            None => continue,
        };

        let image_buffer = draw_glyph(&glyph);

        let x_origin = bbox.min.x as f64 * s_factor;
        let y_origin = (100.0 + bbox.min.y as f64) * s_factor;
        let width = (bbox.max.x - bbox.min.x) as f64 * s_factor;
        let height = (bbox.max.y - bbox.min.y) as f64 * s_factor;
        let image = Image::new().rect([x_origin, y_origin, width, height]);

        let texture = Texture::from_image(&mut win.factory, &image_buffer, &TextureSettings::new())
            .unwrap();

        vec.push((image, texture));
    }

    vec
}

fn draw_glyph(glyph: &rusttype::PositionedGlyph) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
    let bbox = glyph.pixel_bounding_box().unwrap();
    let mut image_buffer = ImageBuffer::new((bbox.max.x - bbox.min.x) as u32,
                                            (bbox.max.y - bbox.min.y) as u32);
    glyph.draw(|x, y, v| {
        let v = (255.0 * v).round() as u8;
        image_buffer.put_pixel(x, y, Rgba { data: [0, 0, 0, v] })
    });
    image_buffer
}
<commit_msg>Emphasize subpixel positioning<commit_after>extern crate piston_window;
extern crate harfbuzz_rs;
extern crate image as piston_image;
extern crate rusttype;
extern crate glfw_window;

use harfbuzz_rs::{Face, UnicodeBuffer};
use harfbuzz_rs::rusttype::{rusttype_font_from_face, rusttype_scale_from_hb_font};

use piston_window::*;
use piston_image::{ImageBuffer, Rgba};
use glfw_window::GlfwWindow;

fn main() {
    let mut window: PistonWindow<GlfwWindow> = WindowSettings::new("Hello World!", [512; 2])
        .build()
        .unwrap();

    window.set_swap_buffers(true);
    let glyphs = shape(&mut window);

    println!("window size {:?}", window.window.size());
    println!("window draw size {:?}", window.draw_size());
    println!("render target view dimensions {:?}",
             window.output_color.get_dimensions());

    while let Some(e) = window.next() {
        window.draw_2d(&e, |c, g| {
            clear([1.0, 1.0, 1.0, 1.0], g);
            for &(image, ref texture) in &glyphs {
                image.draw(texture, &DrawState::default(), c.transform, g);
            }
        });
    }
}

fn shape<T: Window>(win: &mut PistonWindow<T>) -> Vec<(Image, G2dTexture)> {
    let index = 0;
    let path = "testfiles/Optima.ttc";
    let mut font = Face::from_file(path, index)
        .expect("Error reading font file.")
        .create_font();

    let s_factor: f64 = 0.5;
    let fontsize = 80.0;
    font.set_scale(fontsize as i32 * 64, fontsize as i32 * 64);
    font.set_ppem(96 * 64, 96 * 64);

    let rt_font = rusttype_font_from_face(&font.face());
    let scale = rusttype_scale_from_hb_font(&font);

    // Create a buffer with some text and shape it...
    let result = UnicodeBuffer::new().add_str("Hello World! iiiiiiiiiiiiiiiiii").shape(&font, &[]);

    // ... and get the results.
    let positions = result.get_glyph_positions();
    let infos = result.get_glyph_infos();

    let mut cursor = (10*64, 100*64);
    let mut vec = Vec::with_capacity(result.len());
    // iterate over the shaped glyphs
    for (position, info) in positions.iter().zip(infos) {
        let gid = info.codepoint;
        let x_advance = position.x_advance;
        let x_offset = position.x_offset;
        let y_offset = position.y_offset;

        let x_pos: f64 = (cursor.0 + x_offset) as f64 / 64.0;
        let y_pos: f64 = (cursor.1 + y_offset) as f64 / 64.0;

        // separate x_pos and y_pos into integral an fractional parts for subpixel positioning.
        let x_pos_int = x_pos.trunc();
        let x_pos_frac = x_pos.fract();
        let y_pos_int = y_pos.trunc();
        let y_pos_frac = y_pos.fract();

        // no metrics hinting
        cursor.0 += x_advance;

        let glyph = match rt_font.glyph(rusttype::GlyphId(gid)) {
            Some(glyph) => glyph,
            None => continue,
        };

        let glyph = glyph.scaled(scale).positioned(rusttype::Point {
            x: x_pos_frac as f32,
            y: y_pos_frac as f32,
        });
        let bbox = match glyph.pixel_bounding_box() {
            Some(bbox) => bbox,
            None => continue,
        };
        let image_buffer = draw_glyph(&glyph);

        let x_origin = (x_pos_int + bbox.min.x as f64) * s_factor;
        let y_origin = (y_pos_int + bbox.min.y as f64) * s_factor;
        let width = (bbox.max.x - bbox.min.x) as f64 * s_factor;
        let height = (bbox.max.y - bbox.min.y) as f64 * s_factor;
        let image = Image::new().rect([x_origin, y_origin, width, height]);

        let texture = Texture::from_image(&mut win.factory, &image_buffer, &TextureSettings::new())
            .unwrap();

        vec.push((image, texture));
    }

    vec
}

fn draw_glyph(glyph: &rusttype::PositionedGlyph) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
    let bbox = glyph.pixel_bounding_box().unwrap();
    let mut image_buffer = ImageBuffer::new((bbox.max.x - bbox.min.x) as u32,
                                            (bbox.max.y - bbox.min.y) as u32);
    glyph.draw(|x, y, v| {
        let v = (255.0 * v).round() as u8;
        image_buffer.put_pixel(x, y, Rgba { data: [0, 0, 0, v] })
    });
    image_buffer
}
<|endoftext|>


<commit_before>//! A chat server that broadcasts a message to all connections.
//!
//! This is a simple line-based server which accepts WebSocket connections,
//! reads lines from those connections, and broadcasts the lines to all other
//! connected clients.
//!
//! You can test this out by running:
//!
//!     cargo run --example server 127.0.0.1:12345
//!
//! And then in another window run:
//!
//!     cargo run --example client ws://127.0.0.1:12345/
//!
//! You can run the second command in multiple windows and then chat between the
//! two, seeing the messages from the other client as they're received. For all
//! connected clients they'll all join the same room and see everyone else's
//! messages.

use std::env;
use std::io::Error;

use futures::channel::mpsc::UnboundedSender;
use futures::stream::SplitStream;
use futures::{SinkExt, StreamExt};
use log::*;
use std::collections::HashMap;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::{Arc, Mutex};
use tokio::net::{TcpListener, TcpStream};
use tungstenite::protocol::Message;

type Tx = UnboundedSender<Message>;

type WsRx = SplitStream<tokio_tungstenite::WebSocketStream<TcpStream>>;

type PeerMap = Arc<Mutex<HashMap<SocketAddr, Tx>>>;

async fn handle_message(addr: SocketAddr, peer_map: PeerMap, ws_rx: WsRx) {
    let mut ws_rx = ws_rx;
    while let Some(msg) = ws_rx.next().await {
        let msg = msg.expect("Failed to get response");
        info!(
            "Received a message from {}: {}",
            addr,
            msg.to_text().unwrap()
        );

        for peer in peer_map.lock().unwrap().iter_mut() {
            let _ = peer.1.unbounded_send(msg.clone());
        }
    }
}

async fn accept_connection(peer_map: PeerMap, raw_stream: TcpStream) {
    let addr = raw_stream
        .peer_addr()
        .expect("connected streams should have a peer address");
    info!("Peer address: {}", addr);

    let ws_stream = tokio_tungstenite::accept_async(raw_stream)
        .await
        .expect("Error during the websocket handshake occurred");

    info!("New WebSocket connection: {}", addr);

    let (mut ws_tx, ws_rx) = ws_stream.split();
    let (msg_tx, mut msg_rx) = futures::channel::mpsc::unbounded();

    //We want to be able to send data to a specific peer, use this tx.
    peer_map.lock().unwrap().insert(addr, msg_tx);

    //Handle incoming messages
    tokio::spawn(handle_message(addr, peer_map.clone(), ws_rx));

    //If msg_rx get's some data, send it on the websocket.
    while let Some(msg) = msg_rx.next().await {
        info!("Sending message to {}", addr);
        ws_tx.send(msg).await.expect("Failed to send request");
    }
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let _ = env_logger::try_init();
    let addr = env::args().nth(1).unwrap_or_else(|| "127.0.0.1:8080".to_string());
    let addr = addr
        .to_socket_addrs()
        .expect("Not a valid address")
        .next()
        .expect("Not a socket address");

    let hm: HashMap<SocketAddr, Tx> = HashMap::new();
    let state = PeerMap::new(Mutex::new(hm));

    // Create the event loop and TCP listener we'll accept connections on.
    let try_socket = TcpListener::bind(&addr).await;
    let mut listener = try_socket.expect("Failed to bind");
    info!("Listening on: {}", addr);

    while let Ok((stream, _)) = listener.accept().await {
        tokio::spawn(accept_connection(state.clone(), stream));
    }

    Ok(())
}
<commit_msg>Use tokio::net::ToSocketAddrs instead of sync version from std in the new server example<commit_after>//! A chat server that broadcasts a message to all connections.
//!
//! This is a simple line-based server which accepts WebSocket connections,
//! reads lines from those connections, and broadcasts the lines to all other
//! connected clients.
//!
//! You can test this out by running:
//!
//!     cargo run --example server 127.0.0.1:12345
//!
//! And then in another window run:
//!
//!     cargo run --example client ws://127.0.0.1:12345/
//!
//! You can run the second command in multiple windows and then chat between the
//! two, seeing the messages from the other client as they're received. For all
//! connected clients they'll all join the same room and see everyone else's
//! messages.

use std::env;
use std::io::Error;

use futures::channel::mpsc::UnboundedSender;
use futures::stream::SplitStream;
use futures::{SinkExt, StreamExt};
use log::*;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};
use tokio::net::{TcpListener, TcpStream};
use tungstenite::protocol::Message;

type Tx = UnboundedSender<Message>;

type WsRx = SplitStream<tokio_tungstenite::WebSocketStream<TcpStream>>;

type PeerMap = Arc<Mutex<HashMap<SocketAddr, Tx>>>;

async fn handle_message(addr: SocketAddr, peer_map: PeerMap, ws_rx: WsRx) {
    let mut ws_rx = ws_rx;
    while let Some(msg) = ws_rx.next().await {
        let msg = msg.expect("Failed to get response");
        info!(
            "Received a message from {}: {}",
            addr,
            msg.to_text().unwrap()
        );

        for peer in peer_map.lock().unwrap().iter_mut() {
            let _ = peer.1.unbounded_send(msg.clone());
        }
    }
}

async fn accept_connection(peer_map: PeerMap, raw_stream: TcpStream) {
    let addr = raw_stream
        .peer_addr()
        .expect("connected streams should have a peer address");
    info!("Peer address: {}", addr);

    let ws_stream = tokio_tungstenite::accept_async(raw_stream)
        .await
        .expect("Error during the websocket handshake occurred");

    info!("New WebSocket connection: {}", addr);

    let (mut ws_tx, ws_rx) = ws_stream.split();
    let (msg_tx, mut msg_rx) = futures::channel::mpsc::unbounded();

    //We want to be able to send data to a specific peer, use this tx.
    peer_map.lock().unwrap().insert(addr, msg_tx);

    //Handle incoming messages
    tokio::spawn(handle_message(addr, peer_map.clone(), ws_rx));

    //If msg_rx get's some data, send it on the websocket.
    while let Some(msg) = msg_rx.next().await {
        info!("Sending message to {}", addr);
        ws_tx.send(msg).await.expect("Failed to send request");
    }
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let _ = env_logger::try_init();
    let addr = env::args()
        .nth(1)
        .unwrap_or_else(|| "127.0.0.1:8080".to_string());

    let hm: HashMap<SocketAddr, Tx> = HashMap::new();
    let state = PeerMap::new(Mutex::new(hm));

    // Create the event loop and TCP listener we'll accept connections on.
    let try_socket = TcpListener::bind(&addr).await;
    let mut listener = try_socket.expect("Failed to bind");
    info!("Listening on: {}", addr);

    while let Ok((stream, _)) = listener.accept().await {
        tokio::spawn(accept_connection(state.clone(), stream));
    }

    Ok(())
}
<|endoftext|>