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

//! Overlap: No two impls for the same trait are implemented for the
//! same type.

use metadata::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
use middle::traits;
use middle::ty;
use middle::infer::{self, new_infer_ctxt};
use syntax::ast;
use syntax::codemap::Span;
use rustc_front::hir;
use rustc_front::visit;
use util::nodemap::DefIdMap;

pub fn check(tcx: &ty::ctxt) {
    let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() };
    overlap.check_for_overlapping_impls();

    // this secondary walk specifically checks for some other cases,
    // like defaulted traits, for which additional overlap rules exist
    visit::walk_crate(&mut overlap, tcx.map.krate());
}

struct OverlapChecker<'cx, 'tcx:'cx> {
    tcx: &'cx ty::ctxt<'tcx>,

    // maps from a trait def-id to an impl id
    default_impls: DefIdMap<ast::NodeId>,
}

impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
    fn check_for_overlapping_impls(&self) {
        debug!("check_for_overlapping_impls");

        // Collect this into a vector to avoid holding the
        // refcell-lock during the
        // check_for_overlapping_impls_of_trait() check, since that
        // check can populate this table further with impls from other
        // crates.
        let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect();

        for trait_def in trait_defs {
            self.tcx.populate_implementations_for_trait_if_necessary(trait_def.trait_ref.def_id);
            self.check_for_overlapping_impls_of_trait(trait_def);
        }
    }

    fn check_for_overlapping_impls_of_trait(&self,
                                            trait_def: &'tcx ty::TraitDef<'tcx>)
    {
        debug!("check_for_overlapping_impls_of_trait(trait_def={:?})",
               trait_def);

        // We should already know all impls of this trait, so these
        // borrows are safe.
        let blanket_impls = trait_def.blanket_impls.borrow();
        let nonblanket_impls = trait_def.nonblanket_impls.borrow();
        let trait_def_id = trait_def.trait_ref.def_id;

        // Conflicts can only occur between a blanket impl and another impl,
        // or between 2 non-blanket impls of the same kind.

        for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
            for &impl2_def_id in &blanket_impls[(i+1)..] {
                self.check_if_impls_overlap(trait_def_id,
                                            impl1_def_id,
                                            impl2_def_id);
            }

            for v in nonblanket_impls.values() {
                for &impl2_def_id in v {
                    self.check_if_impls_overlap(trait_def_id,
                                                impl1_def_id,
                                                impl2_def_id);
                }
            }
        }

        for impl_group in nonblanket_impls.values() {
            for (i, &impl1_def_id) in impl_group.iter().enumerate() {
                for &impl2_def_id in &impl_group[(i+1)..] {
                    self.check_if_impls_overlap(trait_def_id,
                                                impl1_def_id,
                                                impl2_def_id);
                }
            }
        }
    }

    // We need to coherently pick which impl will be displayed
    // as causing the error message, and it must be the in the current
    // crate. Just pick the smaller impl in the file.
    fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
            -> Option<(DefId, DefId)> {
        if impl1_def_id.krate != LOCAL_CRATE {
            if impl2_def_id.krate != LOCAL_CRATE {
                // we don't need to check impls if both are external;
                // that's the other crate's job.
                None
            } else {
                Some((impl2_def_id, impl1_def_id))
            }
        } else if impl2_def_id.krate != LOCAL_CRATE {
            Some((impl1_def_id, impl2_def_id))
        } else if impl1_def_id < impl2_def_id {
            Some((impl1_def_id, impl2_def_id))
        } else {
            Some((impl2_def_id, impl1_def_id))
        }
    }

    fn check_if_impls_overlap(&self,
                              trait_def_id: DefId,
                              impl1_def_id: DefId,
                              impl2_def_id: DefId)
    {
        if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
            impl1_def_id, impl2_def_id)
        {
            debug!("check_if_impls_overlap({:?}, {:?}, {:?})",
                   trait_def_id,
                   impl1_def_id,
                   impl2_def_id);

            let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
            if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
                self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id);
            }
        }
    }

    fn report_overlap_error(&self, trait_def_id: DefId,
                            impl1: DefId, impl2: DefId) {

        span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
                  "conflicting implementations for trait `{}`",
                  self.tcx.item_path_str(trait_def_id));

        self.report_overlap_note(impl1, impl2);
    }

    fn report_overlap_note(&self, impl1: DefId, impl2: DefId) {

        if impl2.is_local() {
            span_note!(self.tcx.sess, self.span_of_impl(impl2),
                       "note conflicting implementation here");
        } else {
            let crate_store = &self.tcx.sess.cstore;
            let cdata = crate_store.get_crate_data(impl2.krate);
            span_note!(self.tcx.sess, self.span_of_impl(impl1),
                       "conflicting implementation in crate `{}`",
                       cdata.name);
        }
    }

    fn span_of_impl(&self, impl_did: DefId) -> Span {
        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
        self.tcx.map.span(node_id)
    }
}

impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemDefaultImpl(_, _) => {
                // look for another default impl; note that due to the
                // general orphan/coherence rules, it must always be
                // in this crate.
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
                match prev_default_impl {
                    Some(prev_id) => {
                        self.report_overlap_error(trait_ref.def_id,
                                                  impl_def_id,
                                                  self.tcx.map.local_def_id(prev_id));
                    }
                    None => { }
                }
            }
            hir::ItemImpl(_, _, _, Some(_), ref self_ty, _) => {
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let trait_def_id = trait_ref.def_id;
                match trait_ref.self_ty().sty {
                    ty::TyTrait(ref data) => {
                        // This is something like impl Trait1 for Trait2. Illegal
                        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.

                        if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
                            // FIXME(#27579). This just means the
                            // self-ty is illegal; WF will report this
                            // error. But it will do so as a warning
                            // for a release or two.  For backwards
                            // compat reasons, then, we continue to
                            // report it here so that things which
                            // were errors remain errors.
                            span_err!(self.tcx.sess, self_ty.span, E0372,
                                      "the trait `{}` cannot be made into an object",
                                      self.tcx.item_path_str(data.principal_def_id()));
                        } else {
                            let mut supertrait_def_ids =
                                traits::supertrait_def_ids(self.tcx, data.principal_def_id());
                            if supertrait_def_ids.any(|d| d == trait_def_id) {
                                span_err!(self.tcx.sess, item.span, E0371,
                                          "the object type `{}` automatically \
                                           implements the trait `{}`",
                                          trait_ref.self_ty(),
                                          self.tcx.item_path_str(trait_def_id));
                            }
                        }
                    }
                    _ => { }
                }
            }
            _ => {
            }
        }
        visit::walk_item(self, item);
    }
}
<commit_msg>Don't print the same impl twice on ext. overlap<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Overlap: No two impls for the same trait are implemented for the
//! same type.

use metadata::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
use middle::traits;
use middle::ty;
use middle::infer::{self, new_infer_ctxt};
use syntax::ast;
use syntax::codemap::Span;
use rustc_front::hir;
use rustc_front::visit;
use util::nodemap::DefIdMap;

pub fn check(tcx: &ty::ctxt) {
    let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() };
    overlap.check_for_overlapping_impls();

    // this secondary walk specifically checks for some other cases,
    // like defaulted traits, for which additional overlap rules exist
    visit::walk_crate(&mut overlap, tcx.map.krate());
}

struct OverlapChecker<'cx, 'tcx:'cx> {
    tcx: &'cx ty::ctxt<'tcx>,

    // maps from a trait def-id to an impl id
    default_impls: DefIdMap<ast::NodeId>,
}

impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
    fn check_for_overlapping_impls(&self) {
        debug!("check_for_overlapping_impls");

        // Collect this into a vector to avoid holding the
        // refcell-lock during the
        // check_for_overlapping_impls_of_trait() check, since that
        // check can populate this table further with impls from other
        // crates.
        let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect();

        for trait_def in trait_defs {
            self.tcx.populate_implementations_for_trait_if_necessary(trait_def.trait_ref.def_id);
            self.check_for_overlapping_impls_of_trait(trait_def);
        }
    }

    fn check_for_overlapping_impls_of_trait(&self,
                                            trait_def: &'tcx ty::TraitDef<'tcx>)
    {
        debug!("check_for_overlapping_impls_of_trait(trait_def={:?})",
               trait_def);

        // We should already know all impls of this trait, so these
        // borrows are safe.
        let blanket_impls = trait_def.blanket_impls.borrow();
        let nonblanket_impls = trait_def.nonblanket_impls.borrow();
        let trait_def_id = trait_def.trait_ref.def_id;

        // Conflicts can only occur between a blanket impl and another impl,
        // or between 2 non-blanket impls of the same kind.

        for (i, &impl1_def_id) in blanket_impls.iter().enumerate() {
            for &impl2_def_id in &blanket_impls[(i+1)..] {
                self.check_if_impls_overlap(trait_def_id,
                                            impl1_def_id,
                                            impl2_def_id);
            }

            for v in nonblanket_impls.values() {
                for &impl2_def_id in v {
                    self.check_if_impls_overlap(trait_def_id,
                                                impl1_def_id,
                                                impl2_def_id);
                }
            }
        }

        for impl_group in nonblanket_impls.values() {
            for (i, &impl1_def_id) in impl_group.iter().enumerate() {
                for &impl2_def_id in &impl_group[(i+1)..] {
                    self.check_if_impls_overlap(trait_def_id,
                                                impl1_def_id,
                                                impl2_def_id);
                }
            }
        }
    }

    // We need to coherently pick which impl will be displayed
    // as causing the error message, and it must be the in the current
    // crate. Just pick the smaller impl in the file.
    fn order_impls(&self, impl1_def_id: DefId, impl2_def_id: DefId)
            -> Option<(DefId, DefId)> {
        if impl1_def_id.krate != LOCAL_CRATE {
            if impl2_def_id.krate != LOCAL_CRATE {
                // we don't need to check impls if both are external;
                // that's the other crate's job.
                None
            } else {
                Some((impl2_def_id, impl1_def_id))
            }
        } else if impl2_def_id.krate != LOCAL_CRATE {
            Some((impl1_def_id, impl2_def_id))
        } else if impl1_def_id < impl2_def_id {
            Some((impl1_def_id, impl2_def_id))
        } else {
            Some((impl2_def_id, impl1_def_id))
        }
    }

    fn check_if_impls_overlap(&self,
                              trait_def_id: DefId,
                              impl1_def_id: DefId,
                              impl2_def_id: DefId)
    {
        if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
            impl1_def_id, impl2_def_id)
        {
            debug!("check_if_impls_overlap({:?}, {:?}, {:?})",
                   trait_def_id,
                   impl1_def_id,
                   impl2_def_id);

            let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
            if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
                self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id);
            }
        }
    }

    fn report_overlap_error(&self, trait_def_id: DefId,
                            impl1: DefId, impl2: DefId) {

        span_err!(self.tcx.sess, self.span_of_impl(impl1), E0119,
                  "conflicting implementations for trait `{}`",
                  self.tcx.item_path_str(trait_def_id));

        self.report_overlap_note(impl2);
    }

    fn report_overlap_note(&self, impl2: DefId) {

        if impl2.is_local() {
            span_note!(self.tcx.sess, self.span_of_impl(impl2),
                       "note conflicting implementation here");
        } else {
            let crate_store = &self.tcx.sess.cstore;
            let cdata = crate_store.get_crate_data(impl2.krate);
            self.tcx.sess.note(&format!("conflicting implementation in crate `{}`", cdata.name));
        }
    }

    fn span_of_impl(&self, impl_did: DefId) -> Span {
        let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
        self.tcx.map.span(node_id)
    }
}

impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemDefaultImpl(_, _) => {
                // look for another default impl; note that due to the
                // general orphan/coherence rules, it must always be
                // in this crate.
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
                match prev_default_impl {
                    Some(prev_id) => {
                        self.report_overlap_error(trait_ref.def_id,
                                                  impl_def_id,
                                                  self.tcx.map.local_def_id(prev_id));
                    }
                    None => { }
                }
            }
            hir::ItemImpl(_, _, _, Some(_), ref self_ty, _) => {
                let impl_def_id = self.tcx.map.local_def_id(item.id);
                let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                let trait_def_id = trait_ref.def_id;
                match trait_ref.self_ty().sty {
                    ty::TyTrait(ref data) => {
                        // This is something like impl Trait1 for Trait2. Illegal
                        // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.

                        if !traits::is_object_safe(self.tcx, data.principal_def_id()) {
                            // FIXME(#27579). This just means the
                            // self-ty is illegal; WF will report this
                            // error. But it will do so as a warning
                            // for a release or two.  For backwards
                            // compat reasons, then, we continue to
                            // report it here so that things which
                            // were errors remain errors.
                            span_err!(self.tcx.sess, self_ty.span, E0372,
                                      "the trait `{}` cannot be made into an object",
                                      self.tcx.item_path_str(data.principal_def_id()));
                        } else {
                            let mut supertrait_def_ids =
                                traits::supertrait_def_ids(self.tcx, data.principal_def_id());
                            if supertrait_def_ids.any(|d| d == trait_def_id) {
                                span_err!(self.tcx.sess, item.span, E0371,
                                          "the object type `{}` automatically \
                                           implements the trait `{}`",
                                          trait_ref.self_ty(),
                                          self.tcx.item_path_str(trait_def_id));
                            }
                        }
                    }
                    _ => { }
                }
            }
            _ => {
            }
        }
        visit::walk_item(self, item);
    }
}
<|endoftext|>


<commit_before>//! Describe flash areas.

use flash::{Flash, Sector};
use std::marker::PhantomData;
use std::ptr;

/// Structure to build up the boot area table.
#[derive(Debug)]
pub struct AreaDesc {
    areas: Vec<Vec<FlashArea>>,
    whole: Vec<FlashArea>,
    sectors: Vec<Sector>,
}

impl AreaDesc {
    pub fn new(flash: &Flash) -> AreaDesc {
        AreaDesc {
            areas: vec![],
            whole: vec![],
            sectors: flash.sector_iter().collect(),
        }
    }

    /// Add a slot to the image.  The slot must align with erasable units in the flash device.
    /// Panics if the description is not valid.  There are also bootloader assumptions that the
    /// slots are SLOT0, SLOT1, and SCRATCH in that order.
    pub fn add_image(&mut self, base: usize, len: usize, id: FlashId) {
        let nid = id as usize;
        let orig_base = base;
        let orig_len = len;
        let mut base = base;
        let mut len = len;

        while nid > self.areas.len() {
            self.areas.push(vec![]);
            self.whole.push(Default::default());
        }

        if nid != self.areas.len() {
            panic!("Flash areas not added in order");
        }

        let mut area = vec![];

        for sector in &self.sectors {
            if len == 0 {
                break;
            };
            if base > sector.base + sector.size - 1 {
                continue;
            }
            if sector.base != base {
                panic!("Image does not start on a sector boundary");
            }

            area.push(FlashArea {
                flash_id: id,
                device_id: 42,
                pad16: 0,
                off: sector.base as u32,
                size: sector.size as u32,
            });

            base += sector.size;
            len -= sector.size;
        }

        if len != 0 {
            panic!("Image goes past end of device");
        }

        self.areas.push(area);
        self.whole.push(FlashArea {
            flash_id: id,
            device_id: 42,
            pad16: 0,
            off: orig_base as u32,
            size: orig_len as u32,
        });
    }

    // Add a simple slot to the image.  This ignores the device layout, and just adds the area as a
    // single unit.  It assumes that the image lines up with image boundaries.  This tests
    // configurations where the partition table uses larger sectors than the underlying flash
    // device.
    pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId) {
        let area = vec![FlashArea {
            flash_id: id,
            device_id: 42,
            pad16: 0,
            off: base as u32,
            size: len as u32,
        }];

        self.areas.push(area);
        self.whole.push(FlashArea {
            flash_id: id,
            device_id: 42,
            pad16: 0,
            off: base as u32,
            size: len as u32,
        });
    }

    pub fn get_c(&self) -> CAreaDesc {
        let mut areas: CAreaDesc = Default::default();

        assert_eq!(self.areas.len(), self.whole.len());

        for (i, area) in self.areas.iter().enumerate() {
            if area.len() > 0 {
                areas.slots[i].areas = &area[0];
                areas.slots[i].whole = self.whole[i].clone();
                areas.slots[i].num_areas = area.len() as u32;
                areas.slots[i].id = area[0].flash_id;
            }
        }

        areas.num_slots = self.areas.len() as u32;

        areas
    }
}

/// The area descriptor, C format.
#[repr(C)]
#[derive(Debug, Default)]
pub struct CAreaDesc<'a> {
    slots: [CArea<'a>; 16],
    num_slots: u32,
}

#[repr(C)]
#[derive(Debug)]
pub struct CArea<'a> {
    whole: FlashArea,
    areas: *const FlashArea,
    num_areas: u32,
    id: FlashId,
    phantom: PhantomData<&'a AreaDesc>,
}

impl<'a> Default for CArea<'a> {
    fn default() -> CArea<'a> {
        CArea {
            areas: ptr::null(),
            whole: Default::default(),
            id: FlashId::BootLoader,
            num_areas: 0,
            phantom: PhantomData,
        }
    }
}

/// Flash area map.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(dead_code)]
pub enum FlashId {
    BootLoader = 0,
    Image0 = 1,
    Image1 = 2,
    ImageScratch = 3,
    Nffs = 4,
    Core = 5,
    RebootLog = 6
}

impl Default for FlashId {
    fn default() -> FlashId {
        FlashId::BootLoader
    }
}

#[repr(C)]
#[derive(Debug, Clone, Default)]
pub struct FlashArea {
    flash_id: FlashId,
    device_id: u8,
    pad16: u16,
    off: u32,
    size: u32,
}

<commit_msg>sim: Remove phantom declaration from CAreaDesc<commit_after>//! Describe flash areas.

use flash::{Flash, Sector};
use std::ptr;

/// Structure to build up the boot area table.
#[derive(Debug)]
pub struct AreaDesc {
    areas: Vec<Vec<FlashArea>>,
    whole: Vec<FlashArea>,
    sectors: Vec<Sector>,
}

impl AreaDesc {
    pub fn new(flash: &Flash) -> AreaDesc {
        AreaDesc {
            areas: vec![],
            whole: vec![],
            sectors: flash.sector_iter().collect(),
        }
    }

    /// Add a slot to the image.  The slot must align with erasable units in the flash device.
    /// Panics if the description is not valid.  There are also bootloader assumptions that the
    /// slots are SLOT0, SLOT1, and SCRATCH in that order.
    pub fn add_image(&mut self, base: usize, len: usize, id: FlashId) {
        let nid = id as usize;
        let orig_base = base;
        let orig_len = len;
        let mut base = base;
        let mut len = len;

        while nid > self.areas.len() {
            self.areas.push(vec![]);
            self.whole.push(Default::default());
        }

        if nid != self.areas.len() {
            panic!("Flash areas not added in order");
        }

        let mut area = vec![];

        for sector in &self.sectors {
            if len == 0 {
                break;
            };
            if base > sector.base + sector.size - 1 {
                continue;
            }
            if sector.base != base {
                panic!("Image does not start on a sector boundary");
            }

            area.push(FlashArea {
                flash_id: id,
                device_id: 42,
                pad16: 0,
                off: sector.base as u32,
                size: sector.size as u32,
            });

            base += sector.size;
            len -= sector.size;
        }

        if len != 0 {
            panic!("Image goes past end of device");
        }

        self.areas.push(area);
        self.whole.push(FlashArea {
            flash_id: id,
            device_id: 42,
            pad16: 0,
            off: orig_base as u32,
            size: orig_len as u32,
        });
    }

    // Add a simple slot to the image.  This ignores the device layout, and just adds the area as a
    // single unit.  It assumes that the image lines up with image boundaries.  This tests
    // configurations where the partition table uses larger sectors than the underlying flash
    // device.
    pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId) {
        let area = vec![FlashArea {
            flash_id: id,
            device_id: 42,
            pad16: 0,
            off: base as u32,
            size: len as u32,
        }];

        self.areas.push(area);
        self.whole.push(FlashArea {
            flash_id: id,
            device_id: 42,
            pad16: 0,
            off: base as u32,
            size: len as u32,
        });
    }

    pub fn get_c(&self) -> CAreaDesc {
        let mut areas: CAreaDesc = Default::default();

        assert_eq!(self.areas.len(), self.whole.len());

        for (i, area) in self.areas.iter().enumerate() {
            if area.len() > 0 {
                areas.slots[i].areas = &area[0];
                areas.slots[i].whole = self.whole[i].clone();
                areas.slots[i].num_areas = area.len() as u32;
                areas.slots[i].id = area[0].flash_id;
            }
        }

        areas.num_slots = self.areas.len() as u32;

        areas
    }
}

/// The area descriptor, C format.
#[repr(C)]
#[derive(Debug, Default)]
pub struct CAreaDesc {
    slots: [CArea; 16],
    num_slots: u32,
}

#[repr(C)]
#[derive(Debug)]
pub struct CArea {
    whole: FlashArea,
    areas: *const FlashArea,
    num_areas: u32,
    id: FlashId,
}

impl Default for CArea {
    fn default() -> CArea {
        CArea {
            areas: ptr::null(),
            whole: Default::default(),
            id: FlashId::BootLoader,
            num_areas: 0,
        }
    }
}

/// Flash area map.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(dead_code)]
pub enum FlashId {
    BootLoader = 0,
    Image0 = 1,
    Image1 = 2,
    ImageScratch = 3,
    Nffs = 4,
    Core = 5,
    RebootLog = 6
}

impl Default for FlashId {
    fn default() -> FlashId {
        FlashId::BootLoader
    }
}

#[repr(C)]
#[derive(Debug, Clone, Default)]
pub struct FlashArea {
    flash_id: FlashId,
    device_id: u8,
    pad16: u16,
    off: u32,
    size: u32,
}

<|endoftext|>


<commit_before><commit_msg>Minor sin_cos optimization<commit_after><|endoftext|>


<commit_before><commit_msg>impl generic OR, XOR, AND<commit_after><|endoftext|>


<commit_before>extern crate serialize;

use std::collections::HashMap;
use std::io::process::Command;
use std::io::{File, TempDir};
use std::io::fs;

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create teh apk
    let directory = build_directory(&sdk_path, args.output.filestem_str().unwrap(), &native_shared_libs);

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        fs::copy(path, &directory.path().join("libs").join("armeabi").join(name)).unwrap();
    }

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::io::process::InheritFd(1)).stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to an executable
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-Wl,-E")
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling elfedit to turn our executable into a shared object
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-elfedit"))
        .arg("--output-type").arg("dyn")
        .arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing elfedit");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(std::io::process::InheritFd(2))
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.into_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, Path> {
    let base_path = args.output.dir_path().join("native");
    let mut native_shared_libs: HashMap<String, Path> = HashMap::new();

    fs::walk_dir(&base_path).and_then(|mut dirs| {
        for dir in dirs {
            fs::readdir(&dir).and_then(|paths| {
                for path in paths.iter() {
                    match (path.filename_str(), path.extension_str()) {
                        (Some(filename), Some(ext)) => {
                            if filename.starts_with("lib") && ext == "so" {
                                native_shared_libs.insert(filename.to_string(), path.clone());
                            }
                        }
                        _ => {}
                    }
                }
                Ok(())
            }).ok();
        }
        Ok(())
    }).ok();

    native_shared_libs
}

fn build_directory(sdk_dir: &Path, crate_name: &str, libs: &HashMap<String, Path>) -> TempDir {
    use std::io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    let activity_name = if libs.len() > 0 {
        let src_path = build_directory.path().join("src/rust/glutin");
        fs::mkdir_recursive(&src_path, std::io::USER_RWX).unwrap();

        File::create(&src_path.join("MainActivity.java")).unwrap()
            .write_str(java_src(libs).as_slice())
            .unwrap();

        "rust.glutin.MainActivity"
    } else {
        "android.app.NativeActivity"
    };

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest(crate_name, activity_name).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::io::USER_RWX).unwrap();
    }

    build_directory
}

fn java_src(libs: &HashMap<String, Path>) -> String {
    let mut libs_string = "".to_string();

    for (name, _) in libs.iter() {
        // Strip off the 'lib' prefix and ".so" suffix. This is safe since libs only get added
        // to the hash map if they start with lib.
        let line = format!("        System.loadLibrary(\"{}\");\n", name.slice(3, name.len()-3));
        libs_string.push_str(line.as_slice());
    }

    format!(r#"package rust.glutin;

public class MainActivity extends android.app.NativeActivity {{
    static {{
        {0}
    }}
}}"#, libs_string)
}

fn build_manifest(crate_name: &str, activity_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true"></uses-feature>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:label="{0}">
        <activity android:name="{1}"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name, activity_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}
<commit_msg>Remove use of elf edit and instead directly create a shared library for android.<commit_after>extern crate serialize;

use std::collections::HashMap;
use std::io::process::Command;
use std::io::{File, TempDir};
use std::io::fs;

fn main() {
    let (args, passthrough) = parse_arguments();

    // Find all the native shared libraries that exist in the target directory.
    let native_shared_libs = find_native_libs(&args);

    // getting the path from the ANDROID_HOME env
    let sdk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "ANDROID_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the ANDROID_HOME environment variable");

    // hardcoding ndk path
    let ndk_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_HOME")
        .map(|(_, v)| Path::new(v)).expect("Please set the NDK_HOME environment variable");

    // hardcoding ndk path
    let standalone_path = std::os::env().into_iter().find(|&(ref k, _)| k.as_slice() == "NDK_STANDALONE")
        .map(|(_, v)| Path::new(v)).unwrap_or(Path::new("/opt/ndk_standalone"));

    // creating the build directory that will contain all the necessary files to create teh apk
    let directory = build_directory(&sdk_path, args.output.filestem_str().unwrap(), &native_shared_libs);

    // Copy the additional native libs into the libs directory.
    for (name, path) in native_shared_libs.iter() {
        fs::copy(path, &directory.path().join("libs").join("armeabi").join(name)).unwrap();
    }

    // compiling android_native_app_glue.c
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .arg(ndk_path.join("sources").join("android").join("native_app_glue").join("android_native_app_glue.c"))
        .arg("-c")
        .arg("-o").arg(directory.path().join("android_native_app_glue.o"))
        .stdout(std::io::process::InheritFd(1)).stderr(std::io::process::InheritFd(2))
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling gcc to link to a shared object
    if Command::new(standalone_path.join("bin").join("arm-linux-androideabi-gcc"))
        .args(passthrough.as_slice())
        .arg(directory.path().join("android_native_app_glue.o"))
        .arg("-o").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
        .arg("-shared")
        .arg("-Wl,-E")
        .stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2))//.cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing gcc");
        std::os::set_exit_status(1);
        return;
    }

    // calling objdump to make sure that our object has `ANativeActivity_onCreate`
    // TODO: not working
    /*{
        let mut process =
            Command::new(standalone_path.join("bin").join("arm-linux-androideabi-objdump"))
            .arg("-x").arg(directory.path().join("libs").join("armeabi").join("libmain.so"))
            .stderr(std::io::process::InheritFd(2))
            .spawn().unwrap();

        // TODO: use UFCS instead
        fn by_ref<'a, T: Reader>(r: &'a mut T) -> std::io::RefReader<'a, T> { r.by_ref() };

        let stdout = process.stdout.as_mut().unwrap();
        let mut stdout = std::io::BufferedReader::new(by_ref(stdout));

        if stdout.lines().filter_map(|l| l.ok())
            .find(|line| line.as_slice().contains("ANativeActivity_onCreate")).is_none()
        {
            println!("Error: the output file doesn't contain ANativeActivity_onCreate");
            std::os::set_exit_status(1);
            return;
        }
    }*/

    // executing ant
    if Command::new("ant").arg("debug").stdout(std::io::process::InheritFd(1))
        .stderr(std::io::process::InheritFd(2)).cwd(directory.path())
        .status().unwrap() != std::io::process::ExitStatus(0)
    {
        println!("Error while executing ant debug");
        std::os::set_exit_status(1);
        return;
    }

    // copying apk file to the requested output
    fs::copy(&directory.path().join("bin").join("rust-android-debug.apk"),
        &args.output).unwrap();
}

struct Args {
    output: Path,
}

fn parse_arguments() -> (Args, Vec<String>) {
    let mut result_output = None;
    let mut result_passthrough = Vec::new();

    let args = std::os::args();
    let mut args = args.into_iter().skip(1);

    loop {
        let arg = match args.next() {
            None => return (
                Args {
                    output: result_output.expect("Could not find -o argument")
                },
                result_passthrough
            ),
            Some(arg) => arg
        };

        match arg.as_slice() {
            "-o" => {
                result_output = Some(Path::new(args.next().expect("-o must be followed by the output name")));
            },
            _ => result_passthrough.push(arg)
        };
    }
}

fn find_native_libs(args: &Args) -> HashMap<String, Path> {
    let base_path = args.output.dir_path().join("native");
    let mut native_shared_libs: HashMap<String, Path> = HashMap::new();

    fs::walk_dir(&base_path).and_then(|mut dirs| {
        for dir in dirs {
            fs::readdir(&dir).and_then(|paths| {
                for path in paths.iter() {
                    match (path.filename_str(), path.extension_str()) {
                        (Some(filename), Some(ext)) => {
                            if filename.starts_with("lib") && ext == "so" {
                                native_shared_libs.insert(filename.to_string(), path.clone());
                            }
                        }
                        _ => {}
                    }
                }
                Ok(())
            }).ok();
        }
        Ok(())
    }).ok();

    native_shared_libs
}

fn build_directory(sdk_dir: &Path, crate_name: &str, libs: &HashMap<String, Path>) -> TempDir {
    use std::io::fs;

    let build_directory = TempDir::new("android-rs-glue-rust-to-apk")
        .ok().expect("Could not create temporary build directory");

    let activity_name = if libs.len() > 0 {
        let src_path = build_directory.path().join("src/rust/glutin");
        fs::mkdir_recursive(&src_path, std::io::USER_RWX).unwrap();

        File::create(&src_path.join("MainActivity.java")).unwrap()
            .write_str(java_src(libs).as_slice())
            .unwrap();

        "rust.glutin.MainActivity"
    } else {
        "android.app.NativeActivity"
    };

    File::create(&build_directory.path().join("AndroidManifest.xml")).unwrap()
        .write_str(build_manifest(crate_name, activity_name).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("build.xml")).unwrap()
        .write_str(build_build_xml().as_slice())
        .unwrap();

    File::create(&build_directory.path().join("local.properties")).unwrap()
        .write_str(build_local_properties(sdk_dir).as_slice())
        .unwrap();

    File::create(&build_directory.path().join("project.properties")).unwrap()
        .write_str(build_project_properties().as_slice())
        .unwrap();

    {
        let libs_path = build_directory.path().join("libs").join("armeabi");
        fs::mkdir_recursive(&libs_path, std::io::USER_RWX).unwrap();
    }

    build_directory
}

fn java_src(libs: &HashMap<String, Path>) -> String {
    let mut libs_string = "".to_string();

    for (name, _) in libs.iter() {
        // Strip off the 'lib' prefix and ".so" suffix. This is safe since libs only get added
        // to the hash map if they start with lib.
        let line = format!("        System.loadLibrary(\"{}\");\n", name.slice(3, name.len()-3));
        libs_string.push_str(line.as_slice());
    }

    format!(r#"package rust.glutin;

public class MainActivity extends android.app.NativeActivity {{
    static {{
        {0}
    }}
}}"#, libs_string)
}

fn build_manifest(crate_name: &str, activity_name: &str) -> String {
    format!(r#"<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.native_activity"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="9" />

    <uses-feature android:glEsVersion="0x00020000" android:required="true"></uses-feature>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application android:label="{0}">
        <activity android:name="{1}"
                android:label="{0}"
                android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
<!-- END_INCLUDE(manifest) -->
"#, crate_name, activity_name)
}

fn build_build_xml() -> String {
    format!(r#"<?xml version="1.0" encoding="UTF-8"?>
<project name="rust-android" default="help">
    <property file="local.properties" />
    <loadproperties srcFile="project.properties" />
    <import file="custom_rules.xml" optional="true" />
    <import file="${{sdk.dir}}/tools/ant/build.xml" />
</project>
"#)
}

fn build_local_properties(sdk_dir: &Path) -> String {
    use std::os;
    format!(r"sdk.dir={}", os::make_absolute(sdk_dir).display())
}

fn build_project_properties() -> String {
    format!(r"target=android-18")
}
<|endoftext|>


<commit_before>use std;
use servo;

import std::test::{TestOpts, run_tests_console, TestDesc};
import std::getopts::{getopts, reqopt, opt_str, fail_str};
import os::list_dir_path;
import servo::run_pipeline_png;
import servo::image::base::Image;

fn main(args: ~[~str]) {
    let config = parse_config(args);
    let opts = test_options(config);
    let tests = find_tests(config);
    install_rasterize_py(config);
    run_tests_console(opts, tests);
}

struct Config {
    source_dir: ~str;
    work_dir: ~str;
    filter: Option<~str>;
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt(~"source-dir"), reqopt(~"work-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail fail_str(f)
    };

    Config {
        source_dir: opt_str(matches, ~"source-dir"),
        work_dir: opt_str(matches, ~"work-dir"),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some(matches.free.head())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    {
        filter: config.filter,
        run_ignored: false,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDesc] {
    let all_files = list_dir_path(&Path(config.source_dir));
    let html_files = all_files.filter( |file| file.to_str().ends_with(".html") );
    return html_files.map(|file| make_test(config, (*file).to_str()) );
}

fn make_test(config: Config, file: ~str) -> TestDesc {
    let directives = load_test_directives(file);

    {
        name: file,
        fn: fn~() { run_test(config, file) },
        ignore: directives.ignore,
        should_fail: false
    }
}

struct Directives {
    ignore: bool;
}

fn load_test_directives(file: ~str) -> Directives {
    let data = match io::read_whole_file_str(&Path(file)) {
      result::Ok(data) => data,
      result::Err(e) => fail #fmt("unable to load directives for %s: %s", file, e)
    };

    let mut ignore = false;

    for str::lines(data).each |line| {
        if is_comment(line) {
            if line.contains("ignore") {
                ignore = true;
                break;
            }
        }
    }

    fn is_comment(line: ~str) -> bool {
        line.starts_with("<!--")
    }

    return Directives {
        ignore: ignore
    }
}

fn run_test(config: Config, file: ~str) {
    let servo_image = render_servo(config, file);
    let ref_image = render_ref(config, file);

    assert servo_image.width == ref_image.width;
    assert servo_image.height == ref_image.height;
    #debug("image depth: ref: %?, servo: %?", ref_image.depth, servo_image.depth);

    for uint::range(0, servo_image.height) |h| {
        for uint::range(0, servo_image.width) |w| {
            let i = (h * servo_image.width + w) * 4;
            let servo_pixel = (
                servo_image.data[i + 0],
                servo_image.data[i + 1],
                servo_image.data[i + 2],
                servo_image.data[i + 3]
            );
            let ref_pixel = (
                ref_image.data[i + 0],
                ref_image.data[i + 1],
                ref_image.data[i + 2],
                ref_image.data[i + 3]
            );
            #debug("i: %?, x: %?, y: %?, ref: %?, servo: %?", i, w, h, ref_pixel, servo_pixel);

            if servo_pixel != ref_pixel {
                fail #fmt("mismatched pixel. x: %?, y: %?, ref: %?, servo: %?", w, h, ref_pixel, servo_pixel)
            }
        }
    }
}

const WIDTH: uint = 800;
const HEIGHT: uint = 600;

fn render_servo(config: Config, file: ~str) -> Image {
    let infile = ~"file://" + os::make_absolute(&Path(file)).to_str();
    let outfilename = Path(file).filename().get().to_str() + ".png";
    let outfile = Path(config.work_dir).push(outfilename).to_str();
    run_pipeline_png(infile, outfile);
    return sanitize_image(outfile);
}

fn render_ref(config: Config, file: ~str) -> Image {
    let infile = file;
    let outfilename = Path(file).filename().get().to_str() + "ref..png";
    let outfile = Path(config.work_dir).push(outfilename);
    // After we've generated the reference image once, we don't need
    // to keep launching Firefox
    if !os::path_exists(&outfile) {
        let rasterize_path = rasterize_path(config);
        let prog = run::start_program("python", ~[rasterize_path, infile, outfile.to_str()]);
        prog.finish();
    }
    return sanitize_image(outfile.to_str());
}

fn sanitize_image(file: ~str) -> Image {
    let buf = io::read_whole_file(&Path(file)).get();
    let image = servo::image::base::load_from_memory(buf).get();

    // I don't know how to precisely control the rendered height of
    // the Firefox output, so it is larger than we want. Trim it down.
    assert image.width == WIDTH;
    assert image.height >= HEIGHT;
    let data = vec::slice(image.data, 0, image.width * HEIGHT * 4);

    return Image(image.width, HEIGHT, image.depth, data);
}

fn install_rasterize_py(config: Config) {
    import io::WriterUtil;
    let path = rasterize_path(config);
    let writer = io::file_writer(&Path(path), ~[io::Create, io::Truncate]).get();
    writer.write_str(rasterize_py());
}

fn rasterize_path(config: Config) -> ~str {
    Path(config.work_dir).push(~"rasterize.py").to_str()
}

// This is the script that uses phantom.js to render pages
fn rasterize_py() -> ~str { #include_str("rasterize.py") }
<commit_msg>Fix reftest<commit_after>extern mod std;
extern mod servo;

use std::test::{TestOpts, run_tests_console, TestDesc};
use std::getopts::{getopts, reqopt, opt_str, fail_str};
use os::list_dir_path;
use servo::run_pipeline_png;
use servo::image::base::Image;

fn main(args: ~[~str]) {
    let config = parse_config(args);
    let opts = test_options(config);
    let tests = find_tests(config);
    install_rasterize_py(config);
    run_tests_console(opts, tests);
}

struct Config {
    source_dir: ~str,
    work_dir: ~str,
    filter: Option<~str>
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt(~"source-dir"), reqopt(~"work-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail fail_str(f)
    };

    Config {
        source_dir: opt_str(matches, ~"source-dir"),
        work_dir: opt_str(matches, ~"work-dir"),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some(matches.free.head())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    {
        filter: config.filter,
        run_ignored: false,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDesc] {
    let all_files = list_dir_path(&Path(config.source_dir));
    let html_files = all_files.filter( |file| file.to_str().ends_with(".html") );
    return html_files.map(|file| make_test(config, (*file).to_str()) );
}

fn make_test(config: Config, file: ~str) -> TestDesc {
    let directives = load_test_directives(file);

    {
        name: file,
        testfn: fn~() { run_test(config, file) },
        ignore: directives.ignore,
        should_fail: false
    }
}

struct Directives {
    ignore: bool
}

fn load_test_directives(file: ~str) -> Directives {
    let data = match io::read_whole_file_str(&Path(file)) {
      result::Ok(data) => data,
      result::Err(e) => fail #fmt("unable to load directives for %s: %s", file, e)
    };

    let mut ignore = false;

    for str::lines(data).each |line| {
        if is_comment(line) {
            if line.contains("ignore") {
                ignore = true;
                break;
            }
        }
    }

    fn is_comment(line: ~str) -> bool {
        line.starts_with("<!--")
    }

    return Directives {
        ignore: ignore
    }
}

fn run_test(config: Config, file: ~str) {
    let servo_image = render_servo(config, file);
    let ref_image = render_ref(config, file);

    assert servo_image.width == ref_image.width;
    assert servo_image.height == ref_image.height;
    #debug("image depth: ref: %?, servo: %?", ref_image.depth, servo_image.depth);

    for uint::range(0, servo_image.height) |h| {
        for uint::range(0, servo_image.width) |w| {
            let i = (h * servo_image.width + w) * 4;
            let servo_pixel = (
                servo_image.data[i + 0],
                servo_image.data[i + 1],
                servo_image.data[i + 2],
                servo_image.data[i + 3]
            );
            let ref_pixel = (
                ref_image.data[i + 0],
                ref_image.data[i + 1],
                ref_image.data[i + 2],
                ref_image.data[i + 3]
            );
            #debug("i: %?, x: %?, y: %?, ref: %?, servo: %?", i, w, h, ref_pixel, servo_pixel);

            let (sr, sg, sb, sa) = servo_pixel;
            let (rr, rg, rb, ra) = ref_pixel;

            if sr != rr
                || sg != rg
                || sb != rb
                || sa != ra {
                fail #fmt("mismatched pixel. x: %?, y: %?, ref: %?, servo: %?", w, h, ref_pixel, servo_pixel)
            }
        }
    }
}

const WIDTH: uint = 800;
const HEIGHT: uint = 600;

fn render_servo(config: Config, file: ~str) -> Image {
    let infile = ~"file://" + os::make_absolute(&Path(file)).to_str();
    let outfilename = Path(file).filename().get().to_str() + ".png";
    let outfile = Path(config.work_dir).push(outfilename).to_str();
    run_pipeline_png(infile, outfile);
    return sanitize_image(outfile);
}

fn render_ref(config: Config, file: ~str) -> Image {
    let infile = file;
    let outfilename = Path(file).filename().get().to_str() + "ref..png";
    let outfile = Path(config.work_dir).push(outfilename);
    // After we've generated the reference image once, we don't need
    // to keep launching Firefox
    if !os::path_exists(&outfile) {
        let rasterize_path = rasterize_path(config);
        let prog = run::start_program("python", ~[rasterize_path, infile, outfile.to_str()]);
        prog.finish();
    }
    return sanitize_image(outfile.to_str());
}

fn sanitize_image(file: ~str) -> Image {
    let buf = io::read_whole_file(&Path(file)).get();
    let image = servo::image::base::load_from_memory(buf).get();

    // I don't know how to precisely control the rendered height of
    // the Firefox output, so it is larger than we want. Trim it down.
    assert image.width == WIDTH;
    assert image.height >= HEIGHT;
    let data = vec::slice(image.data, 0, image.width * HEIGHT * 4);

    return Image(image.width, HEIGHT, image.depth, data);
}

fn install_rasterize_py(config: Config) {
    use io::WriterUtil;
    let path = rasterize_path(config);
    let writer = io::file_writer(&Path(path), ~[io::Create, io::Truncate]).get();
    writer.write_str(rasterize_py());
}

fn rasterize_path(config: Config) -> ~str {
    Path(config.work_dir).push(~"rasterize.py").to_str()
}

// This is the script that uses phantom.js to render pages
fn rasterize_py() -> ~str { #include_str("rasterize.py") }
<|endoftext|>


<commit_before>mod state;
mod app;
mod access_control;
mod coords;
mod renderer;
mod backend;
mod handlers;
#[cfg(not(any(feature = "test", test)))]
mod event_loop_notifier;
#[cfg(not(any(feature = "test", test)))]
mod main;
mod start;

#[cfg(any(feature = "test", test))]
mod test_event_loop_notifier;
#[cfg(any(feature = "test", test))]
use test_event_loop_notifier as event_loop_notifier;

pub(crate) use app::TurtleId;
pub(crate) use backend::RendererServer;
pub use renderer::export::ExportError;
pub use start::start;

use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use tokio::sync::{mpsc, oneshot, Mutex};

use crate::ipc_protocol::{ServerConnection, ClientRequest};
use crate::renderer_client::ClientId;
use crate::Event;

use app::App;
use access_control::AccessControl;
use renderer::display_list::DisplayList;
use event_loop_notifier::EventLoopNotifier;

/// Serves requests from the client forever
async fn serve(
    conn: ServerConnection,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: mpsc::UnboundedReceiver<Event>,
    mut server_shutdown_receiver: mpsc::Receiver<()>,
) {
    let conn = Arc::new(conn);
    let app_control = Arc::new(AccessControl::new(app).await);
    let events_receiver = Arc::new(Mutex::new(events_receiver));

    loop {
        // This will either receive the next request or end this task
        let (client_id, request) = tokio::select! {
            // If the main thread shuts down successfully, this will receive Some(()).
            // If the main thread panics, this will return None. In either case, this task needs to
            // end immediately.
            _ = server_shutdown_receiver.recv() => break,

            req = conn.recv() => match req {
                Ok(req) => req,
                // Client has disconnected completely, no purpose in continuing this loop
                Err(IpcError::Disconnected) => break,
                Err(err) => panic!("unable to receive request from IPC client: {:?}", err),
            },
        };

        // To preserve the ordering of requests in cases where they can't run concurrently, we use
        // a channel to synchronize that each request
        let (data_req_queued, data_req_queued_receiver) = oneshot::channel();

        // Each incoming request is given its own task configured specifically for each kind of
        // request. Having separate tasks allows requests that can run in parallel to do so.
        tokio::spawn(run_request(
            data_req_queued,
            conn.clone(),
            client_id,
            app_control.clone(),
            display_list.clone(),
            event_loop.clone(),
            events_receiver.clone(),
            request,
        ));

        // Check if we are ready for the next request to be processed
        // Ignoring error because if data_req_queued was dropped, it probably just means that the
        // request didn't need to call AccessControl::get()
        data_req_queued_receiver.await.unwrap_or(());
    }
}

async fn run_request(
    data_req_queued: oneshot::Sender<()>,
    conn: Arc<ServerConnection>,
    client_id: ClientId,
    app_control: Arc<AccessControl>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: Arc<Mutex<mpsc::UnboundedReceiver<Event>>>,
    request: ClientRequest,
) {
    use ClientRequest::*;
    let res = match request {
        CreateTurtle => {
            handlers::create_turtle(&conn, client_id, &app_control, &event_loop).await
        },

        Export(path, format) => {
            handlers::export_drawings(data_req_queued, &conn, client_id, &app_control, &display_list, &path, format).await
        },

        PollEvent => {
            handlers::poll_event(&conn, client_id, &events_receiver).await
        },

        DrawingProp(prop) => {
            handlers::drawing_prop(data_req_queued, &conn, client_id, &app_control, prop).await
        },
        SetDrawingProp(prop_value) => {
            handlers::set_drawing_prop(data_req_queued, &app_control, &event_loop, prop_value).await
        },
        ResetDrawingProp(prop) => {
            handlers::reset_drawing_prop(data_req_queued, &app_control, &event_loop, prop).await
        },

        TurtleProp(id, prop) => {
            handlers::turtle_prop(data_req_queued, &conn, client_id, &app_control, id, prop).await
        },
        SetTurtleProp(id, prop_value) => {
            handlers::set_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop_value).await
        },
        ResetTurtleProp(id, prop) => {
            handlers::reset_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop).await
        },
        ResetTurtle(id) => {
            handlers::reset_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },

        MoveForward(id, distance) => {
            handlers::move_forward(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, distance).await
        },
        MoveTo(id, target_pos) => {
            handlers::move_to(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, target_pos).await
        },
        RotateInPlace(id, angle, direction) => {
            handlers::rotate_in_place(data_req_queued, &conn, client_id, &app_control, &event_loop, id, angle, direction).await
        },

        BeginFill(id) => {
            handlers::begin_fill(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },
        EndFill(id) => {
            handlers::end_fill(data_req_queued, &app_control, id).await
        },

        Clear(id) => match id {
            Some(id) => handlers::clear_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await,
            None => handlers::clear(data_req_queued, &app_control, &display_list, &event_loop).await,
        },
    };

    use handlers::HandlerError::*;
    match res {
        Ok(()) => {},
        Err(IpcChannelError(err)) => panic!("Error while serializing response: {}", err),
        // Task managing window has ended, this task will end soon too.
        //TODO: This potentially leaves the turtle/drawing state in an inconsistent state. Should
        // we deal with that somehow? Panicking doesn't seem appropriate since this probably isn't
        // an error, but we should definitely stop processing commands and make sure the process
        // ends shortly after.
        Err(EventLoopClosed(_)) => {},
    }
}
<commit_msg>Added a note about how polling for events from multiple places does not guarantee any ordering<commit_after>mod state;
mod app;
mod access_control;
mod coords;
mod renderer;
mod backend;
mod handlers;
#[cfg(not(any(feature = "test", test)))]
mod event_loop_notifier;
#[cfg(not(any(feature = "test", test)))]
mod main;
mod start;

#[cfg(any(feature = "test", test))]
mod test_event_loop_notifier;
#[cfg(any(feature = "test", test))]
use test_event_loop_notifier as event_loop_notifier;

pub(crate) use app::TurtleId;
pub(crate) use backend::RendererServer;
pub use renderer::export::ExportError;
pub use start::start;

use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use tokio::sync::{mpsc, oneshot, Mutex};

use crate::ipc_protocol::{ServerConnection, ClientRequest};
use crate::renderer_client::ClientId;
use crate::Event;

use app::App;
use access_control::AccessControl;
use renderer::display_list::DisplayList;
use event_loop_notifier::EventLoopNotifier;

/// Serves requests from the client forever
async fn serve(
    conn: ServerConnection,
    app: Arc<App>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: mpsc::UnboundedReceiver<Event>,
    mut server_shutdown_receiver: mpsc::Receiver<()>,
) {
    let conn = Arc::new(conn);
    let app_control = Arc::new(AccessControl::new(app).await);
    let events_receiver = Arc::new(Mutex::new(events_receiver));

    loop {
        // This will either receive the next request or end this task
        let (client_id, request) = tokio::select! {
            // If the main thread shuts down successfully, this will receive Some(()).
            // If the main thread panics, this will return None. In either case, this task needs to
            // end immediately.
            _ = server_shutdown_receiver.recv() => break,

            req = conn.recv() => match req {
                Ok(req) => req,
                // Client has disconnected completely, no purpose in continuing this loop
                Err(IpcError::Disconnected) => break,
                Err(err) => panic!("unable to receive request from IPC client: {:?}", err),
            },
        };

        // To preserve the ordering of requests in cases where they can't run concurrently, we use
        // a channel to synchronize that each request
        let (data_req_queued, data_req_queued_receiver) = oneshot::channel();

        // Each incoming request is given its own task configured specifically for each kind of
        // request. Having separate tasks allows requests that can run in parallel to do so.
        tokio::spawn(run_request(
            data_req_queued,
            conn.clone(),
            client_id,
            app_control.clone(),
            display_list.clone(),
            event_loop.clone(),
            events_receiver.clone(),
            request,
        ));

        // Check if we are ready for the next request to be processed
        // Ignoring error because if data_req_queued was dropped, it probably just means that the
        // request didn't need to call AccessControl::get()
        data_req_queued_receiver.await.unwrap_or(());
    }
}

async fn run_request(
    data_req_queued: oneshot::Sender<()>,
    conn: Arc<ServerConnection>,
    client_id: ClientId,
    app_control: Arc<AccessControl>,
    display_list: Arc<Mutex<DisplayList>>,
    event_loop: Arc<EventLoopNotifier>,
    events_receiver: Arc<Mutex<mpsc::UnboundedReceiver<Event>>>,
    request: ClientRequest,
) {
    use ClientRequest::*;
    let res = match request {
        CreateTurtle => {
            handlers::create_turtle(&conn, client_id, &app_control, &event_loop).await
        },

        Export(path, format) => {
            handlers::export_drawings(data_req_queued, &conn, client_id, &app_control, &display_list, &path, format).await
        },

        PollEvent => {
            // NOTE: Technically, because this does not send to `data_req_queued`, it is possible
            // to have several callers of `poll_event` race to get the next event. This appears to
            // be fine though because we don't guarantee the ordering of events if they are polled
            // from multiple threads/tasks. Having events follow the order of requests doesn't
            // really matter if strict ordering isn't necessary.
            handlers::poll_event(&conn, client_id, &events_receiver).await
        },

        DrawingProp(prop) => {
            handlers::drawing_prop(data_req_queued, &conn, client_id, &app_control, prop).await
        },
        SetDrawingProp(prop_value) => {
            handlers::set_drawing_prop(data_req_queued, &app_control, &event_loop, prop_value).await
        },
        ResetDrawingProp(prop) => {
            handlers::reset_drawing_prop(data_req_queued, &app_control, &event_loop, prop).await
        },

        TurtleProp(id, prop) => {
            handlers::turtle_prop(data_req_queued, &conn, client_id, &app_control, id, prop).await
        },
        SetTurtleProp(id, prop_value) => {
            handlers::set_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop_value).await
        },
        ResetTurtleProp(id, prop) => {
            handlers::reset_turtle_prop(data_req_queued, &app_control, &display_list, &event_loop, id, prop).await
        },
        ResetTurtle(id) => {
            handlers::reset_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },

        MoveForward(id, distance) => {
            handlers::move_forward(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, distance).await
        },
        MoveTo(id, target_pos) => {
            handlers::move_to(data_req_queued, &conn, client_id, &app_control, &display_list, &event_loop, id, target_pos).await
        },
        RotateInPlace(id, angle, direction) => {
            handlers::rotate_in_place(data_req_queued, &conn, client_id, &app_control, &event_loop, id, angle, direction).await
        },

        BeginFill(id) => {
            handlers::begin_fill(data_req_queued, &app_control, &display_list, &event_loop, id).await
        },
        EndFill(id) => {
            handlers::end_fill(data_req_queued, &app_control, id).await
        },

        Clear(id) => match id {
            Some(id) => handlers::clear_turtle(data_req_queued, &app_control, &display_list, &event_loop, id).await,
            None => handlers::clear(data_req_queued, &app_control, &display_list, &event_loop).await,
        },
    };

    use handlers::HandlerError::*;
    match res {
        Ok(()) => {},
        Err(IpcChannelError(err)) => panic!("Error while serializing response: {}", err),
        // Task managing window has ended, this task will end soon too.
        //TODO: This potentially leaves the turtle/drawing state in an inconsistent state. Should
        // we deal with that somehow? Panicking doesn't seem appropriate since this probably isn't
        // an error, but we should definitely stop processing commands and make sure the process
        // ends shortly after.
        Err(EventLoopClosed(_)) => {},
    }
}
<|endoftext|>


<commit_before>// content-type: application/octet-stream
// status: 204 No Content
// ratelimit-limit: 1200
// ratelimit-remaining: 771
// ratelimit-reset: 1415984218

use std::borrow::Cow;
use std::fmt;

use hyper::client::response::Response;
use hyper::header;

use response::NamedResponse;
use response;

#[derive(Deserialize)]
pub struct HeaderOnly {
    #[serde(rename="content-type")]
    pub content_type: String,
    pub status: String,
    #[serde(rename="ratelimit-limit")]
    pub ratelimit_limit: f64,
    #[serde(rename="ratelimit-remaining")]
    pub ratelimit_remaining: f64,
    #[serde(rename="ratelimit-reset")]
    pub ratelimit_reset: f64,
}

impl response::NotArray for HeaderOnly {}

impl HeaderOnly {
    pub fn from_response(r: Response) -> Result<HeaderOnly, String> {
        let c_type = match r.headers.get::<header::ContentType>() {
            Some(c) => c,
            None => return Err("No content-type provided".to_owned()),
        };
        let raw_status = r.status_raw();
        let status = format!("{} {}", raw_status.0, raw_status.1);
        let rl_limit_raw = match r.headers.get_raw("ratelimit-limit") {
            Some(c) => c,
            None => return Err("No ratelimit-limit provided".to_owned()),
        };
        let rl_remain_raw = match r.headers.get_raw("ratelimit-remaining") {
            Some(c) => c,
            None => return Err("No ratelimit-remaining provided".to_owned()),
        };
        let rl_reset_raw = match r.headers.get_raw("ratelimit-reset") {
            Some(c) => c,
            None => return Err("No ratelimit-reset provided".to_owned()),
        };
        let rl_limit_str = String::from_utf8_lossy(&rl_limit_raw[0][..]);
        let rl_remain_str = String::from_utf8_lossy(&rl_remain_raw[0][..]);
        let rl_reset_str = String::from_utf8_lossy(&rl_reset_raw[0][..]);
        let rl_limit = match rl_limit_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_remain = match rl_remain_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_reset = match rl_reset_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        Ok(HeaderOnly {
            content_type: c_type.to_string(),
            status: status,
            ratelimit_limit: rl_limit,
            ratelimit_remaining: rl_remain,
            ratelimit_reset: rl_reset,
        })
    }
}

impl NamedResponse for HeaderOnly {
    fn name<'a>() -> Cow<'a, str> {
        "header".into()
    }
}

impl fmt::Display for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Status: {}\n\
                   Request Limit: {:.0}\n\
                   Requests Remaining: {:.0}\n\
                   Time to Reset: {:.0}\n",
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}

impl fmt::Debug for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "content-type: {:?}\n\
                   status: {:?}\n\
                   ratelimit-limit: {:.0}\n\
                   ratelimit-remaining: {:.0}\n\
                   ratelimit_reset: {:.0}\n",
               self.content_type,
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}
<commit_msg>fix: permit an absent content-type<commit_after>// content-type: application/octet-stream
// status: 204 No Content
// ratelimit-limit: 1200
// ratelimit-remaining: 771
// ratelimit-reset: 1415984218

use std::borrow::Cow;
use std::fmt;

use hyper::client::response::Response;
use hyper::header;

use response::NamedResponse;
use response;

#[derive(Deserialize)]
pub struct HeaderOnly {
    #[serde(rename="content-type")]
    pub content_type: String,
    pub status: String,
    #[serde(rename="ratelimit-limit")]
    pub ratelimit_limit: f64,
    #[serde(rename="ratelimit-remaining")]
    pub ratelimit_remaining: f64,
    #[serde(rename="ratelimit-reset")]
    pub ratelimit_reset: f64,
}

impl response::NotArray for HeaderOnly {}

impl HeaderOnly {
    pub fn from_response(r: Response) -> Result<HeaderOnly, String> {
        let c_type = match r.headers.get::<header::ContentType>() {
            Some(c) => c.to_string(),
            None => String::new(),
        };
        let raw_status = r.status_raw();
        let status = format!("{} {}", raw_status.0, raw_status.1);
        let rl_limit_raw = match r.headers.get_raw("ratelimit-limit") {
            Some(c) => c,
            None => return Err("No ratelimit-limit provided".to_owned()),
        };
        let rl_remain_raw = match r.headers.get_raw("ratelimit-remaining") {
            Some(c) => c,
            None => return Err("No ratelimit-remaining provided".to_owned()),
        };
        let rl_reset_raw = match r.headers.get_raw("ratelimit-reset") {
            Some(c) => c,
            None => return Err("No ratelimit-reset provided".to_owned()),
        };
        let rl_limit_str = String::from_utf8_lossy(&rl_limit_raw[0][..]);
        let rl_remain_str = String::from_utf8_lossy(&rl_remain_raw[0][..]);
        let rl_reset_str = String::from_utf8_lossy(&rl_reset_raw[0][..]);
        let rl_limit = match rl_limit_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_remain = match rl_remain_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        let rl_reset = match rl_reset_str.as_ref().parse::<f64>() {
            Ok(n) => n,
            Err(e) => return Err(e.to_string()),
        };
        Ok(HeaderOnly {
            content_type: c_type,
            status: status,
            ratelimit_limit: rl_limit,
            ratelimit_remaining: rl_remain,
            ratelimit_reset: rl_reset,
        })
    }
}

impl NamedResponse for HeaderOnly {
    fn name<'a>() -> Cow<'a, str> {
        "header".into()
    }
}

impl fmt::Display for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Status: {}\n\
                   Request Limit: {:.0}\n\
                   Requests Remaining: {:.0}\n\
                   Time to Reset: {:.0}\n",
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}

impl fmt::Debug for HeaderOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "content-type: {:?}\n\
                   status: {:?}\n\
                   ratelimit-limit: {:.0}\n\
                   ratelimit-remaining: {:.0}\n\
                   ratelimit_reset: {:.0}\n",
               self.content_type,
               self.status,
               self.ratelimit_limit,
               self.ratelimit_remaining,
               self.ratelimit_reset)
    }
}
<|endoftext|>


<commit_before><commit_msg>Made test compile and added note regarding Borrow/AsRef<commit_after><|endoftext|>


<commit_before>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn run_mode(dir: &'static str, mode: &'static str, sysroot: &str) {
    // Disable rustc's new error fomatting. It breaks these tests.
    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = mode.parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from(format!("tests/{}", dir));
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn for_all_targets<F: Fn(String)>(sysroot: &str, f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.file_name().into_string().unwrap();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    run_mode("compile-fail", "compile-fail", &sysroot);
    for_all_targets(&sysroot, |target| {
        for file in std::fs::read_dir("tests/run-pass").unwrap() {
            let file = file.unwrap();
            if !file.metadata().unwrap().is_file() {
                continue;
            }
            let file = file.path();
            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ", file.to_str().unwrap()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(file);
            cmd.arg(format!("--sysroot={}", sysroot));
            cmd.arg("-Dwarnings");
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);
            match cmd.output() {
                Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
                Ok(output) => {
                    writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
                    writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                    writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
                }
                Err(e) => writeln!(stderr.lock(), "FAILED: {}", e).unwrap(),
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "").unwrap();
    })
}
<commit_msg>error out if a run-pass test fails<commit_after>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn run_mode(dir: &'static str, mode: &'static str, sysroot: &str) {
    // Disable rustc's new error fomatting. It breaks these tests.
    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = mode.parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from(format!("tests/{}", dir));
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn for_all_targets<F: Fn(String)>(sysroot: &str, f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.file_name().into_string().unwrap();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    let mut failed = false;
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    run_mode("compile-fail", "compile-fail", &sysroot);
    for_all_targets(&sysroot, |target| {
        for file in std::fs::read_dir("tests/run-pass").unwrap() {
            let file = file.unwrap();
            if !file.metadata().unwrap().is_file() {
                continue;
            }
            let file = file.path();
            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ", file.to_str().unwrap()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(file);
            cmd.arg(format!("--sysroot={}", sysroot));
            cmd.arg("-Dwarnings");
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);
            match cmd.output() {
                Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
                Ok(output) => {
                    failed = true;
                    writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
                    writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                    writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
                }
                Err(e) => {
                    failed = true;
                    writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
                },
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "").unwrap();
    })
    if failed {
        panic!("some tests failed");
    }
}
<|endoftext|>


<commit_before><commit_msg>Refactor tutil::screen::unix slightly<commit_after><|endoftext|>