<commit_before>// Copyright 2017 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.

use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::lint;
use rustc::traits::{self, Reveal};
use rustc::ty::{self, TyCtxt};

use syntax::ast;
use syntax_pos::Span;

struct InherentCollect<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>
}

impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        let (unsafety, ty) = match item.node {
            hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
            _ => return
        };

        match unsafety {
            hir::Unsafety::Normal => {
                // OK
            }
            hir::Unsafety::Unsafe => {
                span_err!(self.tcx.sess,
                          item.span,
                          E0197,
                          "inherent impls cannot be declared as unsafe");
            }
        }

        let def_id = self.tcx.hir.local_def_id(item.id);
        let self_ty = self.tcx.item_type(def_id);
        match self_ty.sty {
            ty::TyAdt(def, _) => {
                self.check_def_id(item, def.did);
            }
            ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
                self.check_def_id(item, data.principal().unwrap().def_id());
            }
            ty::TyChar => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.char_impl(),
                                          "char",
                                          "char",
                                          item.span);
            }
            ty::TyStr => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.str_impl(),
                                          "str",
                                          "str",
                                          item.span);
            }
            ty::TySlice(_) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.slice_impl(),
                                          "slice",
                                          "[T]",
                                          item.span);
            }
            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.const_ptr_impl(),
                                          "const_ptr",
                                          "*const T",
                                          item.span);
            }
            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.mut_ptr_impl(),
                                          "mut_ptr",
                                          "*mut T",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I8) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i8_impl(),
                                          "i8",
                                          "i8",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I16) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i16_impl(),
                                          "i16",
                                          "i16",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I32) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i32_impl(),
                                          "i32",
                                          "i32",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I64) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i64_impl(),
                                          "i64",
                                          "i64",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I128) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i128_impl(),
                                          "i128",
                                          "i128",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::Is) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.isize_impl(),
                                          "isize",
                                          "isize",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U8) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u8_impl(),
                                          "u8",
                                          "u8",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U16) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u16_impl(),
                                          "u16",
                                          "u16",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U32) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u32_impl(),
                                          "u32",
                                          "u32",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U64) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u64_impl(),
                                          "u64",
                                          "u64",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U128) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u128_impl(),
                                          "u128",
                                          "u128",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::Us) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.usize_impl(),
                                          "usize",
                                          "usize",
                                          item.span);
            }
            ty::TyFloat(ast::FloatTy::F32) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.f32_impl(),
                                          "f32",
                                          "f32",
                                          item.span);
            }
            ty::TyFloat(ast::FloatTy::F64) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.f64_impl(),
                                          "f64",
                                          "f64",
                                          item.span);
            }
            ty::TyError => {
                return;
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 ty.span,
                                 E0118,
                                 "no base type found for inherent implementation")
                    .span_label(ty.span, &format!("impl requires a base type"))
                    .note(&format!("either implement a trait on it or create a newtype \
                                    to wrap it instead"))
                    .emit();
                return;
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
    fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
        if def_id.is_local() {
            // Add the implementation to the mapping from implementation to base
            // type def ID, if there is a base type for this implementation and
            // the implementation does not have any associated traits.
            let impl_def_id = self.tcx.hir.local_def_id(item.id);

            // Subtle: it'd be better to collect these into a local map
            // and then write the vector only once all items are known,
            // but that leads to degenerate dep-graphs. The problem is
            // that the write of that big vector winds up having reads
            // from *all* impls in the krate, since we've lost the
            // precision basically.  This would be ok in the firewall
            // model so once we've made progess towards that we can modify
            // the strategy here. In the meantime, using `push` is ok
            // because we are doing this as a pre-pass before anyone
            // actually reads from `inherent_impls` -- and we know this is
            // true beacuse we hold the refcell lock.
            self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
        } else {
            struct_span_err!(self.tcx.sess,
                             item.span,
                             E0116,
                             "cannot define inherent `impl` for a type outside of the crate \
                              where the type is defined")
                .span_label(item.span,
                            &format!("impl for type defined outside of crate."))
                .note("define and implement a trait or new type instead")
                .emit();
        }
    }

    fn check_primitive_impl(&self,
                            impl_def_id: DefId,
                            lang_def_id: Option<DefId>,
                            lang: &str,
                            ty: &str,
                            span: Span) {
        match lang_def_id {
            Some(lang_def_id) if lang_def_id == impl_def_id => {
                // OK
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 span,
                                 E0390,
                                 "only a single inherent implementation marked with `#[lang = \
                                  \"{}\"]` is allowed for the `{}` primitive",
                                 lang,
                                 ty)
                    .span_help(span, "consider using a trait to implement these methods")
                    .emit();
            }
        }
    }
}

struct InherentOverlapChecker<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>
}

impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
        #[derive(Copy, Clone, PartialEq)]
        enum Namespace {
            Type,
            Value,
        }

        let name_and_namespace = |def_id| {
            let item = self.tcx.associated_item(def_id);
            (item.name, match item.kind {
                ty::AssociatedKind::Type => Namespace::Type,
                ty::AssociatedKind::Const |
                ty::AssociatedKind::Method => Namespace::Value,
            })
        };

        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
        let impl_items2 = self.tcx.associated_item_def_ids(impl2);

        for &item1 in &impl_items1[..] {
            let (name, namespace) = name_and_namespace(item1);

            for &item2 in &impl_items2[..] {
                if (name, namespace) == name_and_namespace(item2) {
                    let msg = format!("duplicate definitions with name `{}`", name);
                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
                                           node_id,
                                           self.tcx.span_of_impl(item1).unwrap(),
                                           msg);
                }
            }
        }
    }

    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));

        let inherent_impls = self.tcx.maps.inherent_impls.borrow();
        let impls = match inherent_impls.get(&ty_def_id) {
            Some(impls) => impls,
            None => return,
        };

        for (i, &impl1_def_id) in impls.iter().enumerate() {
            for &impl2_def_id in &impls[(i + 1)..] {
                self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
                    if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
                    }
                });
            }
        }
    }
}

impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemEnum(..) |
            hir::ItemStruct(..) |
            hir::ItemTrait(..) |
            hir::ItemUnion(..) => {
                let type_def_id = self.tcx.hir.local_def_id(item.id);
                self.check_for_overlapping_inherent_impls(type_def_id);
            }
            _ => {}
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
                                      &mut InherentCollect { tcx });
    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
                                      &mut InherentOverlapChecker { tcx });
}
<commit_msg>move `check` to the top of the file, where I would expect to find it<commit_after>// Copyright 2017 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.

use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::lint;
use rustc::traits::{self, Reveal};
use rustc::ty::{self, TyCtxt};

use syntax::ast;
use syntax_pos::Span;

pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
                                      &mut InherentCollect { tcx });
    tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
                                      &mut InherentOverlapChecker { tcx });
}

struct InherentCollect<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>
}

impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        let (unsafety, ty) = match item.node {
            hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
            _ => return
        };

        match unsafety {
            hir::Unsafety::Normal => {
                // OK
            }
            hir::Unsafety::Unsafe => {
                span_err!(self.tcx.sess,
                          item.span,
                          E0197,
                          "inherent impls cannot be declared as unsafe");
            }
        }

        let def_id = self.tcx.hir.local_def_id(item.id);
        let self_ty = self.tcx.item_type(def_id);
        match self_ty.sty {
            ty::TyAdt(def, _) => {
                self.check_def_id(item, def.did);
            }
            ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
                self.check_def_id(item, data.principal().unwrap().def_id());
            }
            ty::TyChar => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.char_impl(),
                                          "char",
                                          "char",
                                          item.span);
            }
            ty::TyStr => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.str_impl(),
                                          "str",
                                          "str",
                                          item.span);
            }
            ty::TySlice(_) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.slice_impl(),
                                          "slice",
                                          "[T]",
                                          item.span);
            }
            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.const_ptr_impl(),
                                          "const_ptr",
                                          "*const T",
                                          item.span);
            }
            ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.mut_ptr_impl(),
                                          "mut_ptr",
                                          "*mut T",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I8) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i8_impl(),
                                          "i8",
                                          "i8",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I16) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i16_impl(),
                                          "i16",
                                          "i16",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I32) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i32_impl(),
                                          "i32",
                                          "i32",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I64) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i64_impl(),
                                          "i64",
                                          "i64",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::I128) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.i128_impl(),
                                          "i128",
                                          "i128",
                                          item.span);
            }
            ty::TyInt(ast::IntTy::Is) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.isize_impl(),
                                          "isize",
                                          "isize",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U8) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u8_impl(),
                                          "u8",
                                          "u8",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U16) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u16_impl(),
                                          "u16",
                                          "u16",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U32) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u32_impl(),
                                          "u32",
                                          "u32",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U64) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u64_impl(),
                                          "u64",
                                          "u64",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::U128) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.u128_impl(),
                                          "u128",
                                          "u128",
                                          item.span);
            }
            ty::TyUint(ast::UintTy::Us) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.usize_impl(),
                                          "usize",
                                          "usize",
                                          item.span);
            }
            ty::TyFloat(ast::FloatTy::F32) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.f32_impl(),
                                          "f32",
                                          "f32",
                                          item.span);
            }
            ty::TyFloat(ast::FloatTy::F64) => {
                self.check_primitive_impl(def_id,
                                          self.tcx.lang_items.f64_impl(),
                                          "f64",
                                          "f64",
                                          item.span);
            }
            ty::TyError => {
                return;
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 ty.span,
                                 E0118,
                                 "no base type found for inherent implementation")
                    .span_label(ty.span, &format!("impl requires a base type"))
                    .note(&format!("either implement a trait on it or create a newtype \
                                    to wrap it instead"))
                    .emit();
                return;
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
    fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
        if def_id.is_local() {
            // Add the implementation to the mapping from implementation to base
            // type def ID, if there is a base type for this implementation and
            // the implementation does not have any associated traits.
            let impl_def_id = self.tcx.hir.local_def_id(item.id);

            // Subtle: it'd be better to collect these into a local map
            // and then write the vector only once all items are known,
            // but that leads to degenerate dep-graphs. The problem is
            // that the write of that big vector winds up having reads
            // from *all* impls in the krate, since we've lost the
            // precision basically.  This would be ok in the firewall
            // model so once we've made progess towards that we can modify
            // the strategy here. In the meantime, using `push` is ok
            // because we are doing this as a pre-pass before anyone
            // actually reads from `inherent_impls` -- and we know this is
            // true beacuse we hold the refcell lock.
            self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
        } else {
            struct_span_err!(self.tcx.sess,
                             item.span,
                             E0116,
                             "cannot define inherent `impl` for a type outside of the crate \
                              where the type is defined")
                .span_label(item.span,
                            &format!("impl for type defined outside of crate."))
                .note("define and implement a trait or new type instead")
                .emit();
        }
    }

    fn check_primitive_impl(&self,
                            impl_def_id: DefId,
                            lang_def_id: Option<DefId>,
                            lang: &str,
                            ty: &str,
                            span: Span) {
        match lang_def_id {
            Some(lang_def_id) if lang_def_id == impl_def_id => {
                // OK
            }
            _ => {
                struct_span_err!(self.tcx.sess,
                                 span,
                                 E0390,
                                 "only a single inherent implementation marked with `#[lang = \
                                  \"{}\"]` is allowed for the `{}` primitive",
                                 lang,
                                 ty)
                    .span_help(span, "consider using a trait to implement these methods")
                    .emit();
            }
        }
    }
}

struct InherentOverlapChecker<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>
}

impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
        #[derive(Copy, Clone, PartialEq)]
        enum Namespace {
            Type,
            Value,
        }

        let name_and_namespace = |def_id| {
            let item = self.tcx.associated_item(def_id);
            (item.name, match item.kind {
                ty::AssociatedKind::Type => Namespace::Type,
                ty::AssociatedKind::Const |
                ty::AssociatedKind::Method => Namespace::Value,
            })
        };

        let impl_items1 = self.tcx.associated_item_def_ids(impl1);
        let impl_items2 = self.tcx.associated_item_def_ids(impl2);

        for &item1 in &impl_items1[..] {
            let (name, namespace) = name_and_namespace(item1);

            for &item2 in &impl_items2[..] {
                if (name, namespace) == name_and_namespace(item2) {
                    let msg = format!("duplicate definitions with name `{}`", name);
                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
                                           node_id,
                                           self.tcx.span_of_impl(item1).unwrap(),
                                           msg);
                }
            }
        }
    }

    fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
        let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));

        let inherent_impls = self.tcx.maps.inherent_impls.borrow();
        let impls = match inherent_impls.get(&ty_def_id) {
            Some(impls) => impls,
            None => return,
        };

        for (i, &impl1_def_id) in impls.iter().enumerate() {
            for &impl2_def_id in &impls[(i + 1)..] {
                self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
                    if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
                        self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
                    }
                });
            }
        }
    }
}

impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
    fn visit_item(&mut self, item: &'v hir::Item) {
        match item.node {
            hir::ItemEnum(..) |
            hir::ItemStruct(..) |
            hir::ItemTrait(..) |
            hir::ItemUnion(..) => {
                let type_def_id = self.tcx.hir.local_def_id(item.id);
                self.check_for_overlapping_inherent_impls(type_def_id);
            }
            _ => {}
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
    }
}

<|endoftext|>


<commit_before>extern crate getopts;
use getopts::Options;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;

fn pointer_size() -> usize {
    let tmp = 0u8;
    let boxed = Box::new(tmp);
    mem::size_of_val(&boxed)
}

fn read_blend_file(inp: &str) -> io::Result<()> {
    // open file
    let mut file = File::open(inp).unwrap();
    // read 12 bytes from the Blender file
    let mut buf = [0u8; 12];
    file.read(&mut buf).unwrap();
    let mut header = String::new();
    for e in buf.iter() {
        header.push(*e as char);
    }
    println!("header = \"{}\"", header);
    // compare first 7 chars to "BLENDER"
    if header.len() >= 7 {
        // create copy of header without moving value
        let mut blender = String::new();
        blender = blender + &header;
        blender.truncate(7); // first 7 chars
        if blender == "BLENDER" {
            println!("starts with \"BLENDER\" ...");
            // switch to byte copy of String representation
            let bytes = header.into_bytes();
            // check 8th char of header
            println!("8th char of header = '{}'", bytes[7] as char);
            // check for 32-bit pointers vs. 64-bit pointers
            let ptr_size = pointer_size();
            println!("size of pointer in bytes: {}", ptr_size);
            let mut ptr_size_differs = false;
            if bytes[7] as char == '_' {
                // 32-bit pointers expected
                if ptr_size != 4 {
                    ptr_size_differs = true;
                }
                println!("32-bit pointers in file, pointer size differs? {}",
                         ptr_size_differs);
            } else {
                // 64-bit pointers expected
                if ptr_size != 8 {
                    ptr_size_differs = true;
                }
                println!("64-bit pointers in file, pointer size differs? {}",
                         ptr_size_differs);
            }
            // little endian or big endian?
            let mut l_endian;
            let endian_test = 1u16; // value one stored in two bytes
            if endian_test.to_le() != endian_test {
                l_endian = false;
            } else {
                // if we are on a little endian machine to_le() is a no-op
                l_endian = true;
            }
            println!("l_endian = {}", l_endian);
            let mut switch_endian;
            if bytes[8] as char == 'v' {
                // file stores little endian
                if !l_endian {
                    switch_endian = true;
                } else {
                    switch_endian = false;
                }
            } else {
                // file stores big endian
                if l_endian {
                    switch_endian = true;
                } else {
                    switch_endian = false;
                }
            }
            println!("switch_endian = {}", switch_endian);
            // get the version number
            let last3c = vec!(bytes[9], bytes[10], bytes[11]);
            let version = String::from_utf8(last3c).unwrap(); // last 3 chars
            println!("version = {}", version);
            if ptr_size == 8 && (ptr_size_differs | switch_endian) == false {
                // assumes 64-bit pointers (in file as well as on platform)
                // we also don't handle endian switching (yet)
                return read_remaining_blend_file(file);
            } else {
                println!("TODO: ptr_size = {}", ptr_size);
                println!("TODO: ptr_size_differs = {}", ptr_size_differs);
                println!("TODO: switch_endian = {}", switch_endian);
            }
        } else {
            println!("ERROR: FILE is not a Blender file");
        }
    } else {
        println!("ERROR: FILE is not a Blender file");
    }
    Ok(())
}

fn read_remaining_blend_file(mut file: File) -> io::Result<()> {
    // read_file_dna
    // 4 * int + 64-bit pointer
    let mut buf = [0u8; 24];
    file.read(&mut buf).unwrap();
    let mut bhead = String::new();
    for e in buf.iter() {
        bhead.push(*e as char);
    }
    let mut code = String::new();
    code.push_str(&bhead); // copy
    code.truncate(4); // first 4 chars
    println!("code = {}", code);
    // first int is 'len'
    let mut len: u32 = 0;
    len += (buf[4] as u32) <<  0;
    len += (buf[5] as u32) <<  8;
    len += (buf[6] as u32) << 16;
    len += (buf[7] as u32) << 24;
    println!("len = {}", len);
    // WORK: read remaining file
    Ok(())
}

fn do_work(inp: &str, out: Option<String>) {
    println!("FILE = {}", inp);
    match out {
        Some(x) => println!("output file name: {}", x),
        None => println!("no output file name"),
    }
    match read_blend_file(inp) {
        Ok(_) => { ; }
        Err(f) => { panic!(f.to_string()) }
    };
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "NAME");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let output = matches.opt_str("o");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };
    do_work(&input, output);
}
<commit_msg>Check the return value of file.read(...).<commit_after>extern crate getopts;
use getopts::Options;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;
use std::mem;

fn pointer_size() -> usize {
    let tmp = 0u8;
    let boxed = Box::new(tmp);
    mem::size_of_val(&boxed)
}

fn read_blend_file(inp: &str) -> io::Result<()> {
    // open file
    let mut file = File::open(inp).unwrap();
    // read 12 bytes from the Blender file
    let mut buf = [0u8; 12];
    let bytes_read = file.read(&mut buf).unwrap();
    if bytes_read != buf.len() {
        println!("{} bytes read, but {} expected ...", bytes_read, buf.len());
        return Ok(());
    }
    let mut header = String::new();
    for e in buf.iter() {
        header.push(*e as char);
    }
    println!("header = \"{}\"", header);
    // compare first 7 chars to "BLENDER"
    if header.len() >= 7 {
        // create copy of header without moving value
        let mut blender = String::new();
        blender = blender + &header;
        blender.truncate(7); // first 7 chars
        if blender == "BLENDER" {
            println!("starts with \"BLENDER\" ...");
            // switch to byte copy of String representation
            let bytes = header.into_bytes();
            // check 8th char of header
            println!("8th char of header = '{}'", bytes[7] as char);
            // check for 32-bit pointers vs. 64-bit pointers
            let ptr_size = pointer_size();
            println!("size of pointer in bytes: {}", ptr_size);
            let mut ptr_size_differs = false;
            if bytes[7] as char == '_' {
                // 32-bit pointers expected
                if ptr_size != 4 {
                    ptr_size_differs = true;
                }
                println!("32-bit pointers in file, pointer size differs? {}",
                         ptr_size_differs);
            } else {
                // 64-bit pointers expected
                if ptr_size != 8 {
                    ptr_size_differs = true;
                }
                println!("64-bit pointers in file, pointer size differs? {}",
                         ptr_size_differs);
            }
            // little endian or big endian?
            let mut l_endian;
            let endian_test = 1u16; // value one stored in two bytes
            if endian_test.to_le() != endian_test {
                l_endian = false;
            } else {
                // if we are on a little endian machine to_le() is a no-op
                l_endian = true;
            }
            println!("l_endian = {}", l_endian);
            let mut switch_endian;
            if bytes[8] as char == 'v' {
                // file stores little endian
                if !l_endian {
                    switch_endian = true;
                } else {
                    switch_endian = false;
                }
            } else {
                // file stores big endian
                if l_endian {
                    switch_endian = true;
                } else {
                    switch_endian = false;
                }
            }
            println!("switch_endian = {}", switch_endian);
            // get the version number
            let last3c = vec!(bytes[9], bytes[10], bytes[11]);
            let version = String::from_utf8(last3c).unwrap(); // last 3 chars
            println!("version = {}", version);
            if ptr_size == 8 && (ptr_size_differs | switch_endian) == false {
                // assumes 64-bit pointers (in file as well as on platform)
                // we also don't handle endian switching (yet)
                return read_remaining_blend_file(file);
            } else {
                println!("TODO: ptr_size = {}", ptr_size);
                println!("TODO: ptr_size_differs = {}", ptr_size_differs);
                println!("TODO: switch_endian = {}", switch_endian);
            }
        } else {
            println!("ERROR: FILE is not a Blender file");
        }
    } else {
        println!("ERROR: FILE is not a Blender file");
    }
    Ok(())
}

fn read_remaining_blend_file(mut file: File) -> io::Result<()> {
    // read_file_dna
    // 4 * int + 64-bit pointer
    let mut buf = [0u8; 24];
    let bytes_read = file.read(&mut buf).unwrap();
    if bytes_read != buf.len() {
        println!("{} bytes read, but {} expected ...", bytes_read, buf.len());
        return Ok(());
    }
    let mut bhead = String::new();
    for e in buf.iter() {
        bhead.push(*e as char);
    }
    let mut code = String::new();
    code.push_str(&bhead); // copy
    code.truncate(4); // first 4 chars
    println!("code = {}", code);
    // first int is 'len'
    let mut len: u32 = 0;
    len += (buf[4] as u32) <<  0;
    len += (buf[5] as u32) <<  8;
    len += (buf[6] as u32) << 16;
    len += (buf[7] as u32) << 24;
    println!("len = {}", len);
    // WORK: read remaining file
    Ok(())
}

fn do_work(inp: &str, out: Option<String>) {
    println!("FILE = {}", inp);
    match out {
        Some(x) => println!("output file name: {}", x),
        None => println!("no output file name"),
    }
    match read_blend_file(inp) {
        Ok(_) => { ; }
        Err(f) => { panic!(f.to_string()) }
    };
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} FILE [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("o", "", "set output file name", "NAME");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }
    let output = matches.opt_str("o");
    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };
    do_work(&input, output);
}
<|endoftext|>


<commit_before>
use super::super::lex::*;

///
/// Tokens that can exist in a script
///
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub enum ScriptLexerToken {
    Unknown,
    EndOfFile,

    Identifier,
    String,
    Number,
    HexNumber,

    Newline,
    Whitespace,
    Comment,

    Let,
    Var,
    If,
    Using,
    While,
    Do,
    Loop,
    For,
    In,
    Def,

    Symbol(String)
}

impl ScriptLexerToken {
    ///
    /// Shortcut for generating a symbol token
    ///
    #[inline]
    pub fn symbol(sym: &str) -> ScriptLexerToken {
        ScriptLexerToken::Symbol(String::from(sym))
    }
}

///
/// Token matched from the script
///
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct ScriptToken {
    pub token:      ScriptLexerToken,
    pub start:      i32,
    pub end:        i32,
    pub matched:    String
}

impl ScriptToken {
    ///
    /// Creates a new script token
    ///
    pub fn new(lexer_token: ScriptLexerToken, start: i32, end: i32, matched: String) -> ScriptToken {
        ScriptToken {
            token:      lexer_token,
            start:      start,
            end:        end,
            matched:    matched
        }
    }

    ///
    /// Creates a script token that's an identifier
    ///
    pub fn identifier(id: &str) -> ScriptToken {
        ScriptToken { token: ScriptLexerToken::Identifier, start: 0, end: id.len() as i32, matched: String::from(id) }
    }

    ///
    /// Creates a script token that's an identifier
    ///
    pub fn number(num: &str) -> ScriptToken {
        ScriptToken { token: ScriptLexerToken::Number, start: 0, end: num.len() as i32, matched: String::from(num) }
    }

    ///
    /// Creates a new script token from a generic `LexerMatch` object
    ///
    pub fn from_lexer_match(lexer_match: &LexerMatch) -> ScriptToken {
        let token: &str     = &lexer_match.token;
        let script_token    = match token {
            "let"           => ScriptLexerToken::Let,
            "var"           => ScriptLexerToken::Var,
            "if"            => ScriptLexerToken::If,
            "using"         => ScriptLexerToken::Using,
            "while"         => ScriptLexerToken::While,
            "do"            => ScriptLexerToken::Do,
            "loop"          => ScriptLexerToken::Loop,
            "for"           => ScriptLexerToken::For,
            "in"            => ScriptLexerToken::In,
            "def"           => ScriptLexerToken::Def,

            "." | "," | ":" | "+" | "-" | "*" | "/" | "|" | "&" | "=" | "==" | "!=" | ">" | "<" | "<=" | ">=" | "!" | "?" | "||" | "&&" | "(" | ")" | "{" | "}" | "[" | "]"
                            => ScriptLexerToken::Symbol(lexer_match.token.clone()),

            "String"        => ScriptLexerToken::String,
            "Number"        => ScriptLexerToken::Number,
            "HexNumber"     => ScriptLexerToken::HexNumber,
            "Identifier"    => ScriptLexerToken::Identifier,
            "Newline"       => ScriptLexerToken::Newline,
            "Whitespace"    => ScriptLexerToken::Whitespace,
            "Comment"       => ScriptLexerToken::Comment,

            _               => ScriptLexerToken::Unknown
        };

        ScriptToken::new(script_token, lexer_match.start, lexer_match.end, lexer_match.matched.clone())
    }
}

///
/// Representation of a parsed script
///
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Script {
    /// Run a command, with parameters
    RunCommand(Expression),

    /// Runs a sequence of commands
    Sequence(Vec<Script>),

    /// let a = b
    Let(ScriptToken, Expression),

    /// var a = b
    Var(ScriptToken, Expression),

    /// a = b
    Assign(ScriptToken, Expression),

    /// loop { stuff }
    Loop(Box<Script>),

    /// while expr { stuff }
    While(Expression, Box<Script>),

    /// using expr { stuff }
    Using(Expression, Box<Script>),

    /// def tool pattern { stuff }
    Def(ScriptToken, Expression, Box<Script>)
}

///
/// Representation of an expression from the script
///
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Expression {

    // -- Constant values and data structures

    /// "Foo"
    String(ScriptToken),

    /// 12.3
    Number(ScriptToken),

    /// [ foo, bar, baz ]
    Array(Vec<Expression>),

    /// ( foo, bar, baz )
    Tuple(Vec<Expression>),

    /// { a: b, c: d }
    Map(Vec<(Expression, Expression)>),

    // -- Evaluatable expressions

    /// some-identifier
    Identifier(ScriptToken),

    /// a[b]
    Index(Box<(Expression, Expression)>),

    /// a.b
    FieldAccess(Box<(Expression, Expression)>),

    /// a (parameters)
    Apply(Box<(Expression, Expression)>)
}

impl Expression {
    ///
    /// Creates a new string expression
    ///
    pub fn string(s: &str) -> Expression {
        Expression::String(ScriptToken { token: ScriptLexerToken::String, start: 0, end: s.len() as i32, matched: String::from(s) })
    }

    ///
    /// Creates a new identifier expression
    ///
    pub fn identifier(id: &str) -> Expression {
        Expression::Identifier(ScriptToken { token: ScriptLexerToken::Identifier, start: 0, end: id.len() as i32, matched: String::from(id) })
    }

    ///
    /// Creates a new number expression
    ///
    pub fn number(num: &str) -> Expression {
        Expression::Number(ScriptToken { token: ScriptLexerToken::Number, start: 0, end: num.len() as i32, matched: String::from(num) })
    }

    ///
    /// True if this is an Apply expression
    ///
    pub fn is_apply(&self) -> bool {
        match self {
            &Expression::Apply(_)   => true,
            _                       => false
        }
    }
}<commit_msg>Add an If statement to the script<commit_after>
use super::super::lex::*;

///
/// Tokens that can exist in a script
///
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Debug)]
pub enum ScriptLexerToken {
    Unknown,
    EndOfFile,

    Identifier,
    String,
    Number,
    HexNumber,

    Newline,
    Whitespace,
    Comment,

    Let,
    Var,
    If,
    Using,
    While,
    Do,
    Loop,
    For,
    In,
    Def,

    Symbol(String)
}

impl ScriptLexerToken {
    ///
    /// Shortcut for generating a symbol token
    ///
    #[inline]
    pub fn symbol(sym: &str) -> ScriptLexerToken {
        ScriptLexerToken::Symbol(String::from(sym))
    }
}

///
/// Token matched from the script
///
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct ScriptToken {
    pub token:      ScriptLexerToken,
    pub start:      i32,
    pub end:        i32,
    pub matched:    String
}

impl ScriptToken {
    ///
    /// Creates a new script token
    ///
    pub fn new(lexer_token: ScriptLexerToken, start: i32, end: i32, matched: String) -> ScriptToken {
        ScriptToken {
            token:      lexer_token,
            start:      start,
            end:        end,
            matched:    matched
        }
    }

    ///
    /// Creates a script token that's an identifier
    ///
    pub fn identifier(id: &str) -> ScriptToken {
        ScriptToken { token: ScriptLexerToken::Identifier, start: 0, end: id.len() as i32, matched: String::from(id) }
    }

    ///
    /// Creates a script token that's an identifier
    ///
    pub fn number(num: &str) -> ScriptToken {
        ScriptToken { token: ScriptLexerToken::Number, start: 0, end: num.len() as i32, matched: String::from(num) }
    }

    ///
    /// Creates a new script token from a generic `LexerMatch` object
    ///
    pub fn from_lexer_match(lexer_match: &LexerMatch) -> ScriptToken {
        let token: &str     = &lexer_match.token;
        let script_token    = match token {
            "let"           => ScriptLexerToken::Let,
            "var"           => ScriptLexerToken::Var,
            "if"            => ScriptLexerToken::If,
            "using"         => ScriptLexerToken::Using,
            "while"         => ScriptLexerToken::While,
            "do"            => ScriptLexerToken::Do,
            "loop"          => ScriptLexerToken::Loop,
            "for"           => ScriptLexerToken::For,
            "in"            => ScriptLexerToken::In,
            "def"           => ScriptLexerToken::Def,

            "." | "," | ":" | "+" | "-" | "*" | "/" | "|" | "&" | "=" | "==" | "!=" | ">" | "<" | "<=" | ">=" | "!" | "?" | "||" | "&&" | "(" | ")" | "{" | "}" | "[" | "]"
                            => ScriptLexerToken::Symbol(lexer_match.token.clone()),

            "String"        => ScriptLexerToken::String,
            "Number"        => ScriptLexerToken::Number,
            "HexNumber"     => ScriptLexerToken::HexNumber,
            "Identifier"    => ScriptLexerToken::Identifier,
            "Newline"       => ScriptLexerToken::Newline,
            "Whitespace"    => ScriptLexerToken::Whitespace,
            "Comment"       => ScriptLexerToken::Comment,

            _               => ScriptLexerToken::Unknown
        };

        ScriptToken::new(script_token, lexer_match.start, lexer_match.end, lexer_match.matched.clone())
    }
}

///
/// Representation of a parsed script
///
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Script {
    /// Run a command, with parameters
    RunCommand(Expression),

    /// Runs a sequence of commands
    Sequence(Vec<Script>),

    /// let a = b
    Let(ScriptToken, Expression),

    /// var a = b
    Var(ScriptToken, Expression),

    /// a = b
    Assign(ScriptToken, Expression),

    /// if expr { stuff } (else { stuff })
    If(Expression, Box<Script>, Option<Box<Script>>),

    /// loop { stuff }
    Loop(Box<Script>),

    /// while expr { stuff }
    While(Expression, Box<Script>),

    /// using expr { stuff }
    Using(Expression, Box<Script>),

    /// def tool pattern { stuff }
    Def(ScriptToken, Expression, Box<Script>)
}

///
/// Representation of an expression from the script
///
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum Expression {

    // -- Constant values and data structures

    /// "Foo"
    String(ScriptToken),

    /// 12.3
    Number(ScriptToken),

    /// [ foo, bar, baz ]
    Array(Vec<Expression>),

    /// ( foo, bar, baz )
    Tuple(Vec<Expression>),

    /// { a: b, c: d }
    Map(Vec<(Expression, Expression)>),

    // -- Evaluatable expressions

    /// some-identifier
    Identifier(ScriptToken),

    /// a[b]
    Index(Box<(Expression, Expression)>),

    /// a.b
    FieldAccess(Box<(Expression, Expression)>),

    /// a (parameters)
    Apply(Box<(Expression, Expression)>)
}

impl Expression {
    ///
    /// Creates a new string expression
    ///
    pub fn string(s: &str) -> Expression {
        Expression::String(ScriptToken { token: ScriptLexerToken::String, start: 0, end: s.len() as i32, matched: String::from(s) })
    }

    ///
    /// Creates a new identifier expression
    ///
    pub fn identifier(id: &str) -> Expression {
        Expression::Identifier(ScriptToken { token: ScriptLexerToken::Identifier, start: 0, end: id.len() as i32, matched: String::from(id) })
    }

    ///
    /// Creates a new number expression
    ///
    pub fn number(num: &str) -> Expression {
        Expression::Number(ScriptToken { token: ScriptLexerToken::Number, start: 0, end: num.len() as i32, matched: String::from(num) })
    }

    ///
    /// True if this is an Apply expression
    ///
    pub fn is_apply(&self) -> bool {
        match self {
            &Expression::Apply(_)   => true,
            _                       => false
        }
    }
}<|endoftext|>


<commit_before>//! Utilities for interacting with tasks implemented in the rust-rosetta repository.

use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use toml::{self, Table, Value};
use url::Url;
use walkdir::WalkDir;

use TASK_URL_RE;
use remote;

/// A representation of a RosettaCode task.
///
/// The task may have an implementation in the GitHub repository (local), on the RosettaCode wiki
/// (remote), both, or neither.
#[derive(Debug, Clone)]
pub struct LocalTask {
    crate_name: String,
    path: PathBuf,
    source: Vec<PathBuf>,
    local_url: Result<Url, TaskParseError>,
}

impl LocalTask {
    /// The URL of the task on the RosettaCode wiki.
    ///
    /// If we are reading the task data from the wiki itself, the URL will always be available.
    ///
    /// If we are reading the task information solely from the repository, this information may be
    /// missing or malformed.
    pub fn url(&self) -> Result<Url, TaskParseError> {
        self.local_url.clone()
    }

    /// The "normalized" title of the task on RosettaCode.
    ///
    /// This is the title used to identify the task in the RosettaCode URL.
    pub fn normalized_title(&self) -> String {
        remote::normalize(&TASK_URL_RE.captures(self.url().unwrap().as_str())
            .and_then(|c| c.at(1))
            .unwrap()
            .to_owned())
    }

    /// The name of the crate that implements the task.
    pub fn crate_name(&self) -> String {
        self.crate_name.clone()
    }

    /// A list of paths pointing to the Rust source files of the task.
    pub fn source(&self) -> Vec<PathBuf> {
        self.source.clone()
    }

    /// The directory containing the task crate.
    pub fn path(&self) -> PathBuf {
        self.path.clone()
    }
}

/// Errors that may occur while parsing a task crate.
#[derive(Debug, Clone)]
pub enum TaskParseError {
    /// The task URL was not a valid RosettaCode URL.
    InvalidURL(String),

    /// The task does not have any rosettacode metadata associated with it.
    MissingMetadata,
}

/// Given a path to the root `Cargo.toml`, returns a list of tasks implemented in the rust-rosetta
/// repository.
pub fn parse_tasks
(path: P) -> Vec<LocalTask>
    where P: AsRef<Path>
{
    let cargo_toml = parse_toml(path).unwrap();

    let members = {
        let workspace_table = cargo_toml.get("workspace").unwrap();
        match workspace_table.lookup("members") {
            Some(&Value::Array(ref members)) => {
                members.iter()
                    .map(|path| parse_task(path.as_str().unwrap()))
                    .collect()
            }
            _ => vec![],
        }
    };

    members
}

fn parse_toml
(path: P) -> io::Result

    where P: AsRef<Path>
{
    let mut toml_file = try!(File::open(path));
    let mut contents = String::new();
    try!(toml_file.read_to_string(&mut contents));
    Ok(toml::Parser::new(&contents).parse().unwrap())
}

fn parse_task
(path: P) -> LocalTask
    where P: AsRef<Path>
{
    let path = path.as_ref();

    let crate_name = path.to_str().unwrap().trim_left_matches("tasks/");
    let member_toml = Value::Table(parse_toml(path.join("Cargo.toml")).unwrap());

    let url = member_toml.lookup("package.metadata.rosettacode.url")
        .ok_or(TaskParseError::MissingMetadata)
        .map(|metadata| metadata.as_str().unwrap())
        .and_then(|metadata| {
            Url::parse(metadata).or(Err(TaskParseError::InvalidURL(String::from(metadata))))
        });

    let mut sources = vec![];

    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();

        if let Some("rs") = entry.path().extension().and_then(|s| s.to_str()) {
            sources.push(entry.path().to_owned());
        }
    }

    LocalTask {
        crate_name: String::from(crate_name),
        path: path.to_owned(),
        source: sources,
        local_url: url,
    }
}
<commit_msg>print panic message when task URL format is bad<commit_after>//! Utilities for interacting with tasks implemented in the rust-rosetta repository.

use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use toml::{self, Table, Value};
use url::Url;
use walkdir::WalkDir;

use TASK_URL_RE;
use remote;

/// A representation of a RosettaCode task.
///
/// The task may have an implementation in the GitHub repository (local), on the RosettaCode wiki
/// (remote), both, or neither.
#[derive(Debug, Clone)]
pub struct LocalTask {
    crate_name: String,
    path: PathBuf,
    source: Vec<PathBuf>,
    local_url: Result<Url, TaskParseError>,
}

impl LocalTask {
    /// The URL of the task on the RosettaCode wiki.
    ///
    /// If we are reading the task data from the wiki itself, the URL will always be available.
    ///
    /// If we are reading the task information solely from the repository, this information may be
    /// missing or malformed.
    pub fn url(&self) -> Result<Url, TaskParseError> {
        self.local_url.clone()
    }

    /// The "normalized" title of the task on RosettaCode.
    ///
    /// This is the title used to identify the task in the RosettaCode URL.
    pub fn normalized_title(&self) -> String {
        remote::normalize(&TASK_URL_RE.captures(self.url().unwrap().as_str())
            .and_then(|c| c.at(1))
            .expect(&format!("Found task URL that does not match rosettacode regex: {}",
                             self.url().unwrap()))
            .to_owned())
    }

    /// The name of the crate that implements the task.
    pub fn crate_name(&self) -> String {
        self.crate_name.clone()
    }

    /// A list of paths pointing to the Rust source files of the task.
    pub fn source(&self) -> Vec<PathBuf> {
        self.source.clone()
    }

    /// The directory containing the task crate.
    pub fn path(&self) -> PathBuf {
        self.path.clone()
    }
}

/// Errors that may occur while parsing a task crate.
#[derive(Debug, Clone)]
pub enum TaskParseError {
    /// The task URL was not a valid RosettaCode URL.
    InvalidURL(String),

    /// The task does not have any rosettacode metadata associated with it.
    MissingMetadata,
}

/// Given a path to the root `Cargo.toml`, returns a list of tasks implemented in the rust-rosetta
/// repository.
pub fn parse_tasks
(path: P) -> Vec<LocalTask>
    where P: AsRef<Path>
{
    let cargo_toml = parse_toml(path).unwrap();

    let members = {
        let workspace_table = cargo_toml.get("workspace").unwrap();
        match workspace_table.lookup("members") {
            Some(&Value::Array(ref members)) => {
                members.iter()
                    .map(|path| parse_task(path.as_str().unwrap()))
                    .collect()
            }
            _ => vec![],
        }
    };

    members
}

fn parse_toml
(path: P) -> io::Result

    where P: AsRef<Path>
{
    let mut toml_file = try!(File::open(path));
    let mut contents = String::new();
    try!(toml_file.read_to_string(&mut contents));
    Ok(toml::Parser::new(&contents).parse().unwrap())
}

fn parse_task
(path: P) -> LocalTask
    where P: AsRef<Path>
{
    let path = path.as_ref();

    let crate_name = path.to_str().unwrap().trim_left_matches("tasks/");
    let member_toml = Value::Table(parse_toml(path.join("Cargo.toml")).unwrap());

    let url = member_toml.lookup("package.metadata.rosettacode.url")
        .ok_or(TaskParseError::MissingMetadata)
        .map(|metadata| metadata.as_str().unwrap())
        .and_then(|metadata| {
            Url::parse(metadata).or(Err(TaskParseError::InvalidURL(String::from(metadata))))
        });

    let mut sources = vec![];

    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();

        if let Some("rs") = entry.path().extension().and_then(|s| s.to_str()) {
            sources.push(entry.path().to_owned());
        }
    }

    LocalTask {
        crate_name: String::from(crate_name),
        path: path.to_owned(),
        source: sources,
        local_url: url,
    }
}
<|endoftext|>


<commit_before>// These `thumbv*` targets cover the ARM Cortex-M family of processors which are widely used in
// microcontrollers. Namely, all these processors:
//
// - Cortex-M0
// - Cortex-M0+
// - Cortex-M1
// - Cortex-M3
// - Cortex-M4(F)
// - Cortex-M7(F)
// - Cortex-M23
// - Cortex-M33
//
// We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`,
// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost
// non-existent from the POV of codegen so it doesn't make sense to have separate targets for them.
// And if differences exist between two processors under the same target, rustc flags can be used to
// optimize for one processor or the other.
//
// Also, we have not chosen a single target (`arm-none-eabi`) like GCC does because this makes
// difficult to integrate Rust code and C code. Targeting the Cortex-M4 requires different gcc flags
// than the ones you would use for the Cortex-M0 and with a single target it'd be impossible to
// differentiate one processor from the other.
//
// About arm vs thumb in the name. The Cortex-M devices only support the Thumb instruction set,
// which is more compact (higher code density), and not the ARM instruction set. That's why LLVM
// triples use thumb instead of arm. We follow suit because having thumb in the name let us
// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
// build scripts / gcc flags.

use crate::spec::{PanicStrategy, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    // See rust-lang/rfcs#1645 for a discussion about these defaults
    TargetOptions {
        executables: true,
        // In most cases, LLD is good enough
        linker: Some("rust-lld".to_string()),
        // Because these devices have very little resources having an unwinder is too onerous so we
        // default to "abort" because the "unwind" strategy is very rare.
        panic_strategy: PanicStrategy::Abort,
        // Similarly, one almost always never wants to use relocatable code because of the extra
        // costs it involves.
        relocation_model: "static".to_string(),
        abi_blacklist: super::arm_base::abi_blacklist(),
        // When this section is added a volatile load to its start address is also generated. This
        // volatile load is a footgun as it can end up loading an invalid memory address, depending
        // on how the user set up their linker scripts. This section adds pretty printer for stuff
        // like std::Vec, which is not that used in no-std context, so it's best to left it out
        // until we figure a way to add the pretty printers without requiring a volatile load cf.
        // rust-lang/rust#44993.
        emit_debug_gdb_scripts: false,
        ..Default::default()
    }
}
<commit_msg>Don't eliminate frame pointers on thumb targets<commit_after>// These `thumbv*` targets cover the ARM Cortex-M family of processors which are widely used in
// microcontrollers. Namely, all these processors:
//
// - Cortex-M0
// - Cortex-M0+
// - Cortex-M1
// - Cortex-M3
// - Cortex-M4(F)
// - Cortex-M7(F)
// - Cortex-M23
// - Cortex-M33
//
// We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`,
// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost
// non-existent from the POV of codegen so it doesn't make sense to have separate targets for them.
// And if differences exist between two processors under the same target, rustc flags can be used to
// optimize for one processor or the other.
//
// Also, we have not chosen a single target (`arm-none-eabi`) like GCC does because this makes
// difficult to integrate Rust code and C code. Targeting the Cortex-M4 requires different gcc flags
// than the ones you would use for the Cortex-M0 and with a single target it'd be impossible to
// differentiate one processor from the other.
//
// About arm vs thumb in the name. The Cortex-M devices only support the Thumb instruction set,
// which is more compact (higher code density), and not the ARM instruction set. That's why LLVM
// triples use thumb instead of arm. We follow suit because having thumb in the name let us
// differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
// build scripts / gcc flags.

use crate::spec::{PanicStrategy, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
    // See rust-lang/rfcs#1645 for a discussion about these defaults
    TargetOptions {
        executables: true,
        // In most cases, LLD is good enough
        linker: Some("rust-lld".to_string()),
        // Because these devices have very little resources having an unwinder is too onerous so we
        // default to "abort" because the "unwind" strategy is very rare.
        panic_strategy: PanicStrategy::Abort,
        // Similarly, one almost always never wants to use relocatable code because of the extra
        // costs it involves.
        relocation_model: "static".to_string(),
        abi_blacklist: super::arm_base::abi_blacklist(),
        // When this section is added a volatile load to its start address is also generated. This
        // volatile load is a footgun as it can end up loading an invalid memory address, depending
        // on how the user set up their linker scripts. This section adds pretty printer for stuff
        // like std::Vec, which is not that used in no-std context, so it's best to left it out
        // until we figure a way to add the pretty printers without requiring a volatile load cf.
        // rust-lang/rust#44993.
        emit_debug_gdb_scripts: false,
        // LLVM is eager to trash the link register when calling `nounwind` functions, which
        // breaks debugging. Preserve LR by default to prevent that from happening.
        eliminate_frame_pointer: false,
        ..Default::default()
    }
}
<|endoftext|>


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

use std::collections::{HashMap, TreeMap};
use std::hash::Hash;

#[deriving(Clone, PartialEq, Show)]
pub enum Token<'a> {
    Bool(bool),
    Int(int),
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    Uint(uint),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    F32(f32),
    F64(f64),
    Char(char),
    Str(&'a str),
    Option(bool),

    TupleStart(uint),
    StructStart(&'a str, uint),
    EnumStart(&'a str, &'a str, uint),
    SeqStart(uint),
    MapStart(uint),

    End,
}

//////////////////////////////////////////////////////////////////////////////

pub trait Serializer<E> {
    fn serialize<'a>(&mut self, token: Token<'a>) -> Result<(), E>;

    fn syntax_error<T>(&self) -> Result<T, E>;
}

//////////////////////////////////////////////////////////////////////////////

pub trait Serializable<E, S: Serializer<E>> {
    fn serialize(&self, s: &mut S) -> Result<(), E>;
}

//////////////////////////////////////////////////////////////////////////////

macro_rules! impl_serializable {
    ($ty:ty, $variant:expr) => {
        impl<'a, E, S: Serializer<E>> Serializable<E, S> for $ty {
            #[inline]
            fn serialize(&self, s: &mut S) -> Result<(), E> {
                s.serialize($variant)
            }
        }
    }
}

impl_serializable!(bool, Bool(*self))
impl_serializable!(int, Int(*self))
impl_serializable!(i8, I8(*self))
impl_serializable!(i16, I16(*self))
impl_serializable!(i32, I32(*self))
impl_serializable!(i64, I64(*self))
impl_serializable!(uint, Uint(*self))
impl_serializable!(u8, U8(*self))
impl_serializable!(u16, U16(*self))
impl_serializable!(u32, U32(*self))
impl_serializable!(u64, U64(*self))
impl_serializable!(f32, F32(*self))
impl_serializable!(f64, F64(*self))
impl_serializable!(char, Char(*self))
impl_serializable!(&'a str, Str(*self))
impl_serializable!(String, Str(self.as_slice()))

//////////////////////////////////////////////////////////////////////////////

impl<
    E,
    S: Serializer<E>,
    T: Serializable<E, S>
> Serializable<E, S> for Option<T> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        match *self {
            Some(ref value) => {
                try!(s.serialize(Option(true)));
                value.serialize(s)
            }
            None => {
                s.serialize(Option(false))
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

impl<
    E,
    S: Serializer<E>,
    T: Serializable<E, S>
> Serializable<E, S> for Vec<T> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        try!(s.serialize(SeqStart(self.len())));
        for elt in self.iter() {
            try!(elt.serialize(s));
        }
        s.serialize(End)
    }
}

//////////////////////////////////////////////////////////////////////////////

impl<
    E,
    S: Serializer<E>,
    K: Serializable<E, S> + Eq + Hash,
    V: Serializable<E, S>
> Serializable<E, S> for HashMap<K, V> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        try!(s.serialize(MapStart(self.len())));
        for (key, value) in self.iter() {
            try!(key.serialize(s));
            try!(value.serialize(s));
        }
        s.serialize(End)
    }
}

impl<
    E,
    S: Serializer<E>,
    K: Serializable<E, S> + Ord,
    V: Serializable<E, S>
> Serializable<E, S> for TreeMap<K, V> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        try!(s.serialize(MapStart(self.len())));
        for (key, value) in self.iter() {
            try!(key.serialize(s));
            try!(value.serialize(s));
        }
        s.serialize(End)
    }
}

//////////////////////////////////////////////////////////////////////////////

macro_rules! peel {
    ($name:ident, $($other:ident,)*) => (impl_serialize_tuple!($($other,)*))
}

macro_rules! impl_serialize_tuple {
    () => {
        impl<
            E,
            S: Serializer<E>
        > Serializable<E, S> for () {
            #[inline]
            fn serialize(&self, s: &mut S) -> Result<(), E> {
                try!(s.serialize(TupleStart(0)));
                s.serialize(End)
            }
        }
    };
    ( $($name:ident,)+ ) => {
        impl<
            E,
            S: Serializer<E>,
            $($name:Serializable<E, S>),*
        > Serializable<E, S> for ($($name,)*) {
            #[inline]
            #[allow(uppercase_variables)]
            fn serialize(&self, s: &mut S) -> Result<(), E> {
                // FIXME: how can we count macro args?
                let mut len = 0;
                $({ let $name = 1; len += $name; })*;

                let ($(ref $name,)*) = *self;

                try!(s.serialize(TupleStart(len)));
                $(try!($name.serialize(s));)*
                s.serialize(End)
            }
        }
        peel!($($name,)*)
    }
}

impl_serialize_tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }

//////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use serialize::Decoder;

    use super::{Token, Int, Uint, Str, Char, Option};
    use super::{TupleStart, StructStart, EnumStart};
    use super::{SeqStart, MapStart, End};
    use super::{Serializer, Serializable};

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Clone, PartialEq, Show, Decodable)]
    struct Inner {
        a: (),
        b: uint,
        c: HashMap<String, Option<char>>,
    }

    impl<E, S: Serializer<E>> Serializable<E, S> for Inner {
        #[inline]
        fn serialize(&self, s: &mut S) -> Result<(), E> {
            try!(s.serialize(StructStart("Inner", 3)));
            try!(s.serialize(Str("a")));
            try!(self.a.serialize(s));
            try!(s.serialize(Str("b")));
            try!(self.b.serialize(s));
            try!(s.serialize(Str("c")));
            try!(self.c.serialize(s));
            s.serialize(End)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Clone, PartialEq, Show, Decodable)]
    struct Outer {
        inner: Vec<Inner>,
    }

    impl<E, S: Serializer<E>> Serializable<E, S> for Outer {
        #[inline]
        fn serialize(&self, s: &mut S) -> Result<(), E> {
            try!(s.serialize(StructStart("Outer", 1)));
            try!(s.serialize(Str("inner")));
            try!(self.inner.serialize(s));
            s.serialize(End)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Clone, PartialEq, Show, Decodable)]
    enum Animal {
        Dog,
        Frog(String, int)
    }

    impl<E, S: Serializer<E>> Serializable<E, S> for Animal {
        #[inline]
        fn serialize(&self, s: &mut S) -> Result<(), E> {
            match *self {
                Dog => {
                    try!(s.serialize(EnumStart("Animal", "Dog", 0)));
                }
                Frog(ref x, y) => {
                    try!(s.serialize(EnumStart("Animal", "Frog", 2)));
                    try!(x.serialize(s));
                    try!(y.serialize(s));
                }
            }
            s.serialize(End)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Show)]
    enum Error {
        EndOfStream,
        SyntaxError,
    }

    //////////////////////////////////////////////////////////////////////////////

    struct AssertSerializer<Iter> {
        iter: Iter,
    }

    impl<'a, Iter: Iterator<Token<'a>>> AssertSerializer<Iter> {
        #[inline]
        fn new(iter: Iter) -> AssertSerializer<Iter> {
            AssertSerializer {
                iter: iter,
            }
        }
    }

    impl<'a, Iter: Iterator<Token<'a>>> Serializer<Error> for AssertSerializer<Iter> {
        #[inline]
        fn serialize<'b>(&mut self, token: Token<'b>) -> Result<(), Error> {
            let t = match self.iter.next() {
                Some(t) => t,
                None => { fail!(); }
            };

            assert_eq!(t, token);

            Ok(())
        }

        fn syntax_error<T>(&self) -> Result<T, Error> {
            Err(SyntaxError)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[test]
    fn test_tokens_int() {
        let tokens = vec!(
            Int(5)
        );
        let mut serializer = AssertSerializer::new(tokens.move_iter());
        5i.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_str() {
        let tokens = vec!(
            Str("a"),
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        "a".serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_null() {
        let tokens = vec!(
            TupleStart(0),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        ().serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_option_none() {
        let tokens = vec!(
            Option(false),
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        None::<int>.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_option_some() {
        let tokens = vec!(
            Option(true),
            Int(5),
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Some(5).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_tuple() {
        let tokens = vec!(
            TupleStart(2),
                Int(5),
                Str("a"),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        (5, "a").serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_tuple_compound() {
        let tokens = vec!(
            TupleStart(3),
                TupleStart(0),
                End,

                TupleStart(0),
                End,

                TupleStart(2),
                    Int(5),
                    Str("a"),
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        ((), (), (5, "a")).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_struct_empty() {
        let tokens = vec!(
            StructStart("Outer", 1),
                Str("inner"),
                SeqStart(0),
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Outer { inner: vec!() }.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_struct() {
        let tokens = vec!(
            StructStart("Outer", 1),
                Str("inner"),
                SeqStart(1),
                    StructStart("Inner", 3),
                        Str("a"),
                        TupleStart(0),
                        End,

                        Str("b"),
                        Uint(5),

                        Str("c"),
                        MapStart(1),
                            Str("abc"),

                            Option(true),
                            Char('c'),
                        End,
                    End,
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());

        let mut map = HashMap::new();
        map.insert("abc".to_string(), Some('c'));

        Outer {
            inner: vec!(
                Inner {
                    a: (),
                    b: 5,
                    c: map,
                },
            )
        }.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_enum() {
        let tokens = vec!(
            EnumStart("Animal", "Dog", 0),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Dog.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);

        let tokens = vec!(
            EnumStart("Animal", "Frog", 2),
                Str("Henry"),
                Int(349),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Frog("Henry".to_string(), 349).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_vec_empty() {
        let tokens = vec!(
            SeqStart(0),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        let v: Vec<int> = vec!();
        v.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_vec() {
        let tokens = vec!(
            SeqStart(3),
                Int(5),
                Int(6),
                Int(7),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        (vec!(5, 6, 7)).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_vec_compound() {
        let tokens = vec!(
            SeqStart(3),
                SeqStart(1),
                    Int(1),
                End,

                SeqStart(2),
                    Int(2),
                    Int(3),
                End,

                SeqStart(3),
                    Int(4),
                    Int(5),
                    Int(6),
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        (vec!(vec!(1), vec!(2, 3), vec!(4, 5, 6))).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_hashmap() {
        let tokens = vec!(
            MapStart(2),
                Int(5),
                Str("a"),

                Int(6),
                Str("b"),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());

        let mut map = HashMap::new();
        map.insert(5, "a".to_string());
        map.insert(6, "b".to_string());

        map.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }
}
<commit_msg>Fix ser tests<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashMap, TreeMap};
use std::hash::Hash;

#[deriving(Clone, PartialEq, Show)]
pub enum Token<'a> {
    Bool(bool),
    Int(int),
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    Uint(uint),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    F32(f32),
    F64(f64),
    Char(char),
    Str(&'a str),
    Option(bool),

    TupleStart(uint),
    StructStart(&'a str, uint),
    EnumStart(&'a str, &'a str, uint),
    SeqStart(uint),
    MapStart(uint),

    End,
}

//////////////////////////////////////////////////////////////////////////////

pub trait Serializer<E> {
    fn serialize<'a>(&mut self, token: Token<'a>) -> Result<(), E>;

    fn syntax_error<T>(&self) -> Result<T, E>;
}

//////////////////////////////////////////////////////////////////////////////

pub trait Serializable<E, S: Serializer<E>> {
    fn serialize(&self, s: &mut S) -> Result<(), E>;
}

//////////////////////////////////////////////////////////////////////////////

macro_rules! impl_serializable {
    ($ty:ty, $variant:expr) => {
        impl<'a, E, S: Serializer<E>> Serializable<E, S> for $ty {
            #[inline]
            fn serialize(&self, s: &mut S) -> Result<(), E> {
                s.serialize($variant)
            }
        }
    }
}

impl_serializable!(bool, Bool(*self))
impl_serializable!(int, Int(*self))
impl_serializable!(i8, I8(*self))
impl_serializable!(i16, I16(*self))
impl_serializable!(i32, I32(*self))
impl_serializable!(i64, I64(*self))
impl_serializable!(uint, Uint(*self))
impl_serializable!(u8, U8(*self))
impl_serializable!(u16, U16(*self))
impl_serializable!(u32, U32(*self))
impl_serializable!(u64, U64(*self))
impl_serializable!(f32, F32(*self))
impl_serializable!(f64, F64(*self))
impl_serializable!(char, Char(*self))
impl_serializable!(&'a str, Str(*self))
impl_serializable!(String, Str(self.as_slice()))

//////////////////////////////////////////////////////////////////////////////

impl<
    E,
    S: Serializer<E>,
    T: Serializable<E, S>
> Serializable<E, S> for Option<T> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        match *self {
            Some(ref value) => {
                try!(s.serialize(Option(true)));
                value.serialize(s)
            }
            None => {
                s.serialize(Option(false))
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

impl<
    E,
    S: Serializer<E>,
    T: Serializable<E, S>
> Serializable<E, S> for Vec<T> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        try!(s.serialize(SeqStart(self.len())));
        for elt in self.iter() {
            try!(elt.serialize(s));
        }
        s.serialize(End)
    }
}

//////////////////////////////////////////////////////////////////////////////

impl<
    E,
    S: Serializer<E>,
    K: Serializable<E, S> + Eq + Hash,
    V: Serializable<E, S>
> Serializable<E, S> for HashMap<K, V> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        try!(s.serialize(MapStart(self.len())));
        for (key, value) in self.iter() {
            try!(key.serialize(s));
            try!(value.serialize(s));
        }
        s.serialize(End)
    }
}

impl<
    E,
    S: Serializer<E>,
    K: Serializable<E, S> + Ord,
    V: Serializable<E, S>
> Serializable<E, S> for TreeMap<K, V> {
    #[inline]
    fn serialize(&self, s: &mut S) -> Result<(), E> {
        try!(s.serialize(MapStart(self.len())));
        for (key, value) in self.iter() {
            try!(key.serialize(s));
            try!(value.serialize(s));
        }
        s.serialize(End)
    }
}

//////////////////////////////////////////////////////////////////////////////

macro_rules! peel {
    ($name:ident, $($other:ident,)*) => (impl_serialize_tuple!($($other,)*))
}

macro_rules! impl_serialize_tuple {
    () => {
        impl<
            E,
            S: Serializer<E>
        > Serializable<E, S> for () {
            #[inline]
            fn serialize(&self, s: &mut S) -> Result<(), E> {
                try!(s.serialize(TupleStart(0)));
                s.serialize(End)
            }
        }
    };
    ( $($name:ident,)+ ) => {
        impl<
            E,
            S: Serializer<E>,
            $($name:Serializable<E, S>),*
        > Serializable<E, S> for ($($name,)*) {
            #[inline]
            #[allow(uppercase_variables)]
            fn serialize(&self, s: &mut S) -> Result<(), E> {
                // FIXME: how can we count macro args?
                let mut len = 0;
                $({ let $name = 1; len += $name; })*;

                let ($(ref $name,)*) = *self;

                try!(s.serialize(TupleStart(len)));
                $(try!($name.serialize(s));)*
                s.serialize(End)
            }
        }
        peel!($($name,)*)
    }
}

impl_serialize_tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }

//////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use std::collections::{HashMap, TreeMap};

    use serialize::Decoder;

    use super::{Token, Int, Uint, Str, Char, Option};
    use super::{TupleStart, StructStart, EnumStart};
    use super::{SeqStart, MapStart, End};
    use super::{Serializer, Serializable};

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Clone, PartialEq, Show, Decodable)]
    struct Inner {
        a: (),
        b: uint,
        c: HashMap<String, Option<char>>,
    }

    impl<E, S: Serializer<E>> Serializable<E, S> for Inner {
        #[inline]
        fn serialize(&self, s: &mut S) -> Result<(), E> {
            try!(s.serialize(StructStart("Inner", 3)));
            try!(s.serialize(Str("a")));
            try!(self.a.serialize(s));
            try!(s.serialize(Str("b")));
            try!(self.b.serialize(s));
            try!(s.serialize(Str("c")));
            try!(self.c.serialize(s));
            s.serialize(End)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Clone, PartialEq, Show, Decodable)]
    struct Outer {
        inner: Vec<Inner>,
    }

    impl<E, S: Serializer<E>> Serializable<E, S> for Outer {
        #[inline]
        fn serialize(&self, s: &mut S) -> Result<(), E> {
            try!(s.serialize(StructStart("Outer", 1)));
            try!(s.serialize(Str("inner")));
            try!(self.inner.serialize(s));
            s.serialize(End)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Clone, PartialEq, Show, Decodable)]
    enum Animal {
        Dog,
        Frog(String, int)
    }

    impl<E, S: Serializer<E>> Serializable<E, S> for Animal {
        #[inline]
        fn serialize(&self, s: &mut S) -> Result<(), E> {
            match *self {
                Dog => {
                    try!(s.serialize(EnumStart("Animal", "Dog", 0)));
                }
                Frog(ref x, y) => {
                    try!(s.serialize(EnumStart("Animal", "Frog", 2)));
                    try!(x.serialize(s));
                    try!(y.serialize(s));
                }
            }
            s.serialize(End)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[deriving(Show)]
    enum Error {
        EndOfStream,
        SyntaxError,
    }

    //////////////////////////////////////////////////////////////////////////////

    struct AssertSerializer<Iter> {
        iter: Iter,
    }

    impl<'a, Iter: Iterator<Token<'a>>> AssertSerializer<Iter> {
        #[inline]
        fn new(iter: Iter) -> AssertSerializer<Iter> {
            AssertSerializer {
                iter: iter,
            }
        }
    }

    impl<'a, Iter: Iterator<Token<'a>>> Serializer<Error> for AssertSerializer<Iter> {
        #[inline]
        fn serialize<'b>(&mut self, token: Token<'b>) -> Result<(), Error> {
            let t = match self.iter.next() {
                Some(t) => t,
                None => { fail!(); }
            };

            assert_eq!(t, token);

            Ok(())
        }

        fn syntax_error<T>(&self) -> Result<T, Error> {
            Err(SyntaxError)
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    #[test]
    fn test_tokens_int() {
        let tokens = vec!(
            Int(5)
        );
        let mut serializer = AssertSerializer::new(tokens.move_iter());
        5i.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_str() {
        let tokens = vec!(
            Str("a"),
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        "a".serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_null() {
        let tokens = vec!(
            TupleStart(0),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        ().serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_option_none() {
        let tokens = vec!(
            Option(false),
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        None::<int>.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_option_some() {
        let tokens = vec!(
            Option(true),
            Int(5),
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Some(5).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_tuple() {
        let tokens = vec!(
            TupleStart(2),
                Int(5),
                Str("a"),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        (5, "a").serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_tuple_compound() {
        let tokens = vec!(
            TupleStart(3),
                TupleStart(0),
                End,

                TupleStart(0),
                End,

                TupleStart(2),
                    Int(5),
                    Str("a"),
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        ((), (), (5, "a")).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_struct_empty() {
        let tokens = vec!(
            StructStart("Outer", 1),
                Str("inner"),
                SeqStart(0),
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Outer { inner: vec!() }.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_struct() {
        let tokens = vec!(
            StructStart("Outer", 1),
                Str("inner"),
                SeqStart(1),
                    StructStart("Inner", 3),
                        Str("a"),
                        TupleStart(0),
                        End,

                        Str("b"),
                        Uint(5),

                        Str("c"),
                        MapStart(1),
                            Str("abc"),

                            Option(true),
                            Char('c'),
                        End,
                    End,
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());

        let mut map = HashMap::new();
        map.insert("abc".to_string(), Some('c'));

        Outer {
            inner: vec!(
                Inner {
                    a: (),
                    b: 5,
                    c: map,
                },
            )
        }.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_enum() {
        let tokens = vec!(
            EnumStart("Animal", "Dog", 0),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Dog.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);

        let tokens = vec!(
            EnumStart("Animal", "Frog", 2),
                Str("Henry"),
                Int(349),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        Frog("Henry".to_string(), 349).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_vec_empty() {
        let tokens = vec!(
            SeqStart(0),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        let v: Vec<int> = vec!();
        v.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_vec() {
        let tokens = vec!(
            SeqStart(3),
                Int(5),
                Int(6),
                Int(7),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        (vec!(5, 6, 7)).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_vec_compound() {
        let tokens = vec!(
            SeqStart(3),
                SeqStart(1),
                    Int(1),
                End,

                SeqStart(2),
                    Int(2),
                    Int(3),
                End,

                SeqStart(3),
                    Int(4),
                    Int(5),
                    Int(6),
                End,
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());
        (vec!(vec!(1), vec!(2, 3), vec!(4, 5, 6))).serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }

    #[test]
    fn test_tokens_treemap() {
        let tokens = vec!(
            MapStart(2),
                Int(5),
                Str("a"),

                Int(6),
                Str("b"),
            End,
        );

        let mut serializer = AssertSerializer::new(tokens.move_iter());

        let mut map = TreeMap::new();
        map.insert(5, "a".to_string());
        map.insert(6, "b".to_string());

        map.serialize(&mut serializer).unwrap();
        assert_eq!(serializer.iter.next(), None);
    }
}
<|endoftext|>