<commit_before>use rustc_serialize::json::Json;
use chrono::{DateTime, UTC, Timelike};
use byteorder::{WriteBytesExt, BigEndian};

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct TermRef(u32);

impl TermRef {
    pub fn new(ord: u32) -> TermRef {
        TermRef(ord)
    }

    pub fn ord(&self) -> u32 {
        self.0
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Term {
    String(String),
    Boolean(bool),
    I64(i64),
    U64(u64),
    DateTime(DateTime<UTC>),
}

impl Term {
    pub fn from_json(json: &Json) -> Option<Term> {
        // TODO: Should be aware of mappings
        match *json {
            Json::String(ref string) => Some(Term::String(string.clone())),
            Json::Boolean(value) => Some(Term::Boolean(value)),
            Json::F64(_) => None,
            Json::I64(value) => Some(Term::I64(value)),
            Json::U64(value) => Some(Term::U64(value)),
            Json::Null => None,
            Json::Array(_) => None,
            Json::Object(_) => None,
        }
    }

    pub fn as_json(&self) -> Json {
        match *self {
            Term::String(ref string) => Json::String(string.clone()),
            Term::Boolean(value) => Json::Boolean(value),
            Term::I64(value) => Json::I64(value),
            Term::U64(value) => Json::U64(value),
            Term::DateTime(value) => Json::String(value.to_rfc3339()),
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        match *self {
            Term::String(ref string) => {
                let mut bytes = Vec::with_capacity(string.len());

                for byte in string.as_bytes() {
                    bytes.push(*byte);
                }

                bytes
            },
            Term::Boolean(value) => {
                if value {
                    vec![b't']
                } else {
                    vec![b'f']
                }
            }
            Term::I64(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_i64::<BigEndian>(value).unwrap();
                bytes
            }
            Term::U64(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_u64::<BigEndian>(value).unwrap();
                bytes
            }
            Term::DateTime(value) => {
                let mut bytes = Vec::with_capacity(0);
                let timestamp = value.timestamp();
                let micros = value.nanosecond() / 1000;
                let timestamp_with_micros = timestamp * 1000000 + micros as i64;
                bytes.write_i64::<BigEndian>(timestamp_with_micros).unwrap();
                bytes
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use chrono::{DateTime, UTC, Timelike};
    use super::Term;

    #[test]
    fn test_string_to_bytes() {
        let term = Term::String("foo".to_string());

        assert_eq!(term.to_bytes(), vec![102, 111, 111])
    }

    #[test]
    fn test_hiragana_string_to_bytes() {
        let term = Term::String("こんにちは".to_string());

        assert_eq!(term.to_bytes(), vec![227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175])
    }

    #[test]
    fn test_blank_string_to_bytes() {
        let term = Term::String("".to_string());

        assert_eq!(term.to_bytes(), vec![])
    }

    #[test]
    fn test_boolean_true_to_bytes() {
        let term = Term::Boolean(true);

        // 116 = 't' in ASCII
        assert_eq!(term.to_bytes(), vec![116])
    }

    #[test]
    fn test_boolean_false_to_bytes() {
        let term = Term::Boolean(false);

        // 102 = 'f' in ASCII
        assert_eq!(term.to_bytes(), vec![102])
    }

    #[test]
    fn test_i64_to_bytes() {
        let term = Term::I64(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_negative_i64_to_bytes() {
        let term = Term::I64(-123);

        assert_eq!(term.to_bytes(), vec![255, 255, 255, 255, 255, 255, 255, 133])
    }

    #[test]
    fn test_u64_to_bytes() {
        let term = Term::U64(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_datetime_to_bytes() {
        let date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 191, 101, 0])
    }

    #[test]
    fn test_datetime_with_microseconds_to_bytes() {
        let mut date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        date = date.with_nanosecond(123123123).unwrap();
        let term = Term::DateTime(date);

        // This is exactly 123123 higher than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 193, 69, 243])
    }

    #[test]
    fn test_datetime_with_different_timezone_to_bytes() {
        let date = "2016-07-23T16:15:00+02:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        // This is exactly 3_600_000_000 lower than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 78, 45, 43, 193, 0])
    }
}
<commit_msg>Remove U64 term type and rename I64 to Integer<commit_after>use rustc_serialize::json::Json;
use chrono::{DateTime, UTC, Timelike};
use byteorder::{WriteBytesExt, BigEndian};

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct TermRef(u32);

impl TermRef {
    pub fn new(ord: u32) -> TermRef {
        TermRef(ord)
    }

    pub fn ord(&self) -> u32 {
        self.0
    }
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum Term {
    String(String),
    Boolean(bool),
    Integer(i64),
    DateTime(DateTime<UTC>),
}

impl Term {
    pub fn from_json(json: &Json) -> Option<Term> {
        // TODO: Should be aware of mappings
        match *json {
            Json::String(ref string) => Some(Term::String(string.clone())),
            Json::Boolean(value) => Some(Term::Boolean(value)),
            Json::F64(_) => None,
            Json::I64(value) => Some(Term::Integer(value)),
            Json::U64(value) => Some(Term::Integer(value as i64)),  // FIXME
            Json::Null => None,
            Json::Array(_) => None,
            Json::Object(_) => None,
        }
    }

    pub fn as_json(&self) -> Json {
        match *self {
            Term::String(ref string) => Json::String(string.clone()),
            Term::Boolean(value) => Json::Boolean(value),
            Term::Integer(value) => Json::I64(value),
            Term::DateTime(value) => Json::String(value.to_rfc3339()),
        }
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        match *self {
            Term::String(ref string) => {
                let mut bytes = Vec::with_capacity(string.len());

                for byte in string.as_bytes() {
                    bytes.push(*byte);
                }

                bytes
            },
            Term::Boolean(value) => {
                if value {
                    vec![b't']
                } else {
                    vec![b'f']
                }
            }
            Term::Integer(value) => {
                let mut bytes = Vec::with_capacity(8);
                bytes.write_i64::<BigEndian>(value).unwrap();
                bytes
            }
            Term::DateTime(value) => {
                let mut bytes = Vec::with_capacity(0);
                let timestamp = value.timestamp();
                let micros = value.nanosecond() / 1000;
                let timestamp_with_micros = timestamp * 1000000 + micros as i64;
                bytes.write_i64::<BigEndian>(timestamp_with_micros).unwrap();
                bytes
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use chrono::{DateTime, UTC, Timelike};
    use super::Term;

    #[test]
    fn test_string_to_bytes() {
        let term = Term::String("foo".to_string());

        assert_eq!(term.to_bytes(), vec![102, 111, 111])
    }

    #[test]
    fn test_hiragana_string_to_bytes() {
        let term = Term::String("こんにちは".to_string());

        assert_eq!(term.to_bytes(), vec![227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175])
    }

    #[test]
    fn test_blank_string_to_bytes() {
        let term = Term::String("".to_string());

        assert_eq!(term.to_bytes(), vec![])
    }

    #[test]
    fn test_boolean_true_to_bytes() {
        let term = Term::Boolean(true);

        // 116 = 't' in ASCII
        assert_eq!(term.to_bytes(), vec![116])
    }

    #[test]
    fn test_boolean_false_to_bytes() {
        let term = Term::Boolean(false);

        // 102 = 'f' in ASCII
        assert_eq!(term.to_bytes(), vec![102])
    }

    #[test]
    fn test_integer_to_bytes() {
        let term = Term::Integer(123);

        assert_eq!(term.to_bytes(), vec![0, 0, 0, 0, 0, 0, 0, 123])
    }

    #[test]
    fn test_negative_integer_to_bytes() {
        let term = Term::Integer(-123);

        assert_eq!(term.to_bytes(), vec![255, 255, 255, 255, 255, 255, 255, 133])
    }

    #[test]
    fn test_datetime_to_bytes() {
        let date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 191, 101, 0])
    }

    #[test]
    fn test_datetime_with_microseconds_to_bytes() {
        let mut date = "2016-07-23T16:15:00+01:00".parse::<DateTime<UTC>>().unwrap();
        date = date.with_nanosecond(123123123).unwrap();
        let term = Term::DateTime(date);

        // This is exactly 123123 higher than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 79, 3, 193, 69, 243])
    }

    #[test]
    fn test_datetime_with_different_timezone_to_bytes() {
        let date = "2016-07-23T16:15:00+02:00".parse::<DateTime<UTC>>().unwrap();
        let term = Term::DateTime(date);

        // This is exactly 3_600_000_000 lower than the result of "test_datetime_to_bytes"
        assert_eq!(term.to_bytes(), vec![0, 5, 56, 78, 45, 43, 193, 0])
    }
}
<|endoftext|>


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

#![feature(plugin_registrar, rustc_private)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{MetaItem, Expr};
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::*;
use syntax::ext::deriving::generic::ty::*;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::ext::base::MultiDecorator;
use syntax::parse::token;

use rustc::plugin::Registry;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::syntax::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::syntax::ext::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                      span: Span,
                                      mitem: &MetaItem,
                                      item: &Annotatable,
                                      push: &mut FnMut(Annotatable))
{
    let inline = cx.meta_word(span, InternedString::new("inline"));
    let attrs = vec!(cx.attribute(span, inline));
    let trait_def = TraitDef {
        is_unsafe: false,
        span: span,
        attributes: Vec::new(),
        path: path!(num::FromPrimitive),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "from_i64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(i64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs.clone(),
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("i64", c, s, sub)
                })),
            },
            MethodDef {
                name: "from_u64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(u64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs,
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("u64", c, s, sub)
                })),
            }
        ),
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, mitem, &item, push)
}

fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    if substr.nonself_args.len() != 1 {
        cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
    }

    let n = &substr.nonself_args[0];

    match *substr.fields {
        StaticStruct(..) => {
            cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
            return cx.expr_fail(trait_span, InternedString::new(""));
        }
        StaticEnum(enum_def, _) => {
            if enum_def.variants.is_empty() {
                cx.span_err(trait_span,
                            "`FromPrimitive` cannot be derived for enums with no variants");
                return cx.expr_fail(trait_span, InternedString::new(""));
            }

            let mut arms = Vec::new();

            for variant in &enum_def.variants {
                match *variant.node.data {
                    ast::VariantData::Unit(..) => {
                        let span = variant.span;

                        // expr for `$n == $variant as $name`
                        let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
                        let variant = cx.expr_path(path);
                        let ty = cx.ty_ident(span, cx.ident_of(name));
                        let cast = cx.expr_cast(span, variant.clone(), ty);
                        let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);

                        // expr for `Some($variant)`
                        let body = cx.expr_some(span, variant);

                        // arm for `_ if $guard => $body`
                        let arm = ast::Arm {
                            attrs: vec!(),
                            pats: vec!(cx.pat_wild(span)),
                            guard: Some(guard),
                            body: body,
                        };

                        arms.push(arm);
                    }
                    ast::VariantData::Tuple(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for \
                                    enum variants with arguments");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                    ast::VariantData::Struct(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for enums \
                                    with struct variants");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                }
            }

            // arm for `_ => None`
            let arm = ast::Arm {
                attrs: vec!(),
                pats: vec!(cx.pat_wild(trait_span)),
                guard: None,
                body: cx.expr_none(trait_span),
            };
            arms.push(arm);

            cx.expr_match(trait_span, n.clone(), arms)
        }
        _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("derive_NumFromPrimitive"),
        MultiDecorator(Box::new(expand_deriving_from_primitive)));
}
<commit_msg>num-macros: VariantData no longer needs to be dereferenced<commit_after>// Copyright 2012-2015 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.

#![feature(plugin_registrar, rustc_private)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{MetaItem, Expr};
use syntax::ast;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, Annotatable};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::*;
use syntax::ext::deriving::generic::ty::*;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::ext::base::MultiDecorator;
use syntax::parse::token;

use rustc::plugin::Registry;

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        ::syntax::ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! path_local {
    ($x:ident) => (
        ::syntax::ext::deriving::generic::ty::Path::new_local(stringify!($x))
    )
}

macro_rules! pathvec_std {
    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
        let mut v = pathvec!($($rest)::+);
        if let Some(s) = $cx.crate_root {
            v.insert(0, s);
        }
        v
    })
}

pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
                                      span: Span,
                                      mitem: &MetaItem,
                                      item: &Annotatable,
                                      push: &mut FnMut(Annotatable))
{
    let inline = cx.meta_word(span, InternedString::new("inline"));
    let attrs = vec!(cx.attribute(span, inline));
    let trait_def = TraitDef {
        is_unsafe: false,
        span: span,
        attributes: Vec::new(),
        path: path!(num::FromPrimitive),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "from_i64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(i64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs.clone(),
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("i64", c, s, sub)
                })),
            },
            MethodDef {
                name: "from_u64",
                is_unsafe: false,
                generics: LifetimeBounds::empty(),
                explicit_self: None,
                args: vec!(Literal(path_local!(u64))),
                ret_ty: Literal(Path::new_(pathvec_std!(cx, core::option::Option),
                                           None,
                                           vec!(Box::new(Self_)),
                                           true)),
                // #[inline] liable to cause code-bloat
                attributes: attrs,
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_from("u64", c, s, sub)
                })),
            }
        ),
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, mitem, &item, push)
}

fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    if substr.nonself_args.len() != 1 {
        cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
    }

    let n = &substr.nonself_args[0];

    match *substr.fields {
        StaticStruct(..) => {
            cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
            return cx.expr_fail(trait_span, InternedString::new(""));
        }
        StaticEnum(enum_def, _) => {
            if enum_def.variants.is_empty() {
                cx.span_err(trait_span,
                            "`FromPrimitive` cannot be derived for enums with no variants");
                return cx.expr_fail(trait_span, InternedString::new(""));
            }

            let mut arms = Vec::new();

            for variant in &enum_def.variants {
                match variant.node.data {
                    ast::VariantData::Unit(..) => {
                        let span = variant.span;

                        // expr for `$n == $variant as $name`
                        let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
                        let variant = cx.expr_path(path);
                        let ty = cx.ty_ident(span, cx.ident_of(name));
                        let cast = cx.expr_cast(span, variant.clone(), ty);
                        let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);

                        // expr for `Some($variant)`
                        let body = cx.expr_some(span, variant);

                        // arm for `_ if $guard => $body`
                        let arm = ast::Arm {
                            attrs: vec!(),
                            pats: vec!(cx.pat_wild(span)),
                            guard: Some(guard),
                            body: body,
                        };

                        arms.push(arm);
                    }
                    ast::VariantData::Tuple(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for \
                                    enum variants with arguments");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                    ast::VariantData::Struct(..) => {
                        cx.span_err(trait_span,
                                    "`FromPrimitive` cannot be derived for enums \
                                    with struct variants");
                        return cx.expr_fail(trait_span,
                                            InternedString::new(""));
                    }
                }
            }

            // arm for `_ => None`
            let arm = ast::Arm {
                attrs: vec!(),
                pats: vec!(cx.pat_wild(trait_span)),
                guard: None,
                body: cx.expr_none(trait_span),
            };
            arms.push(arm);

            cx.expr_match(trait_span, n.clone(), arms)
        }
        _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")
    }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        token::intern("derive_NumFromPrimitive"),
        MultiDecorator(Box::new(expand_deriving_from_primitive)));
}
<|endoftext|>


<commit_before><commit_msg>Fix compilation of the example program<commit_after><|endoftext|>


<commit_before>//! Using MIDI, verify that the user is able to play a given exercise correctly.  The question
//! should be enough of a description to uniquely describe what should be played.  The answer
//! should be a parseable description of what needs to be played.
//!
//! The answer should be a JSON description of what to play, of one of the following types:
//!
//! { "type": "scale", "base": "C♯", "intervals": "WWHWWWH",
//!   "hands": 1, "octaves": 2, "style": "updown" }
//!
//! This describes a scale.  The base is the first note of the scale.  Sharps and flags can either
//! be "#" and "b" or Unicode characters "♯", and "♭".  The intervals describe the intervals
//! between each note.  Valid characters are 'H' for a half step, 'W' for a whole step, 'm' for a
//! minor third, 'M' for a major third, and '4' for a fourth.  It will be checked that the
//! intervals cover a full octabe.  Hands describes how many hands should be playing the exercise,
//! and octaves are how many octaves to play.  The currently only supported style is "updown",
//! which requires the scale be played from base to base, for the given number of octaves and then
//! back down.  Scales can be played starting in any octave.
//!
//! { "type": "voicing", "chords": [
//!    { "base": "D", "notes": [ "3", "7", "9", "5" },
//!    { "base": "G", "notes": [ "7", "3", "#9", "#5" },
//!    { "base": "C", "notes": [ "3", "7", "9", "5", "11" } ] }
//!
//! This describes a voicing exercise, which is a series of chords to be played.  Each chord has a
//! base, which may or may not actually be played.  The notes in the chord are described in musical
//! notation (again with text or Unicode sharp/flat indicators).  The chord will be built using the
//! next note of the given function.  The octave will be chosen so that the lowest non-root note
//! will be between F#-F surrounding middle C.

#![deny(missing_docs)]

extern crate editdistancewf;
extern crate portmidi;
extern crate timelearn;
#[macro_use] extern crate lazy_static;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;

use portmidi::{PortMidi, InputPort};
use serde_json::{Value};
use std::error;
use std::io::{self, Write};
use std::result;
use std::thread;
use std::time::Duration;
pub use timelearn::{Problem, Status, User};

mod note;
use note::Note;

mod scales;
use scales::{Scale, ScaleSeq};

/// Just box the errors for now.  TODO: Use a proper error type.
pub type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;

/// A learner based on playing the exercises on a MIDI device.
pub struct MidiLearn {
    input: InputPort,
}

impl MidiLearn {
    /// Construct a new MIDI learning, using the default MIDI port.  Invokes `f` with the
    /// MidiLearn.
    pub fn with_new<F, R>(f: F) -> Result<R>
        where F: FnOnce(&mut MidiLearn) -> R
    {
        let pm = PortMidi::new()?;
        let input = pm.default_input_port(4096)?;
        let mut learn = MidiLearn {
            input: input,
        };
        let result = f(&mut learn);
        Ok(result)
    }

}

impl User for MidiLearn {
    /// Practice a single exercise.  Waits for the user to play the exercise, and then returns a
    /// status indicating how well it was played.
    fn single(&mut self, word: &Problem) -> Result<Status> {
        println!("Play: {}", word.question);

        let json: Value = serde_json::from_str(&word.answer)?;
        // println!("Json: {:?}, {:?}", json, json["typr"]);
        if is_type(&json, "scale") {
            let scale: Scale = serde_json::from_value(json)?;

            let mut seq = ScaleSeq::from_scale(&scale)?;
            // println!("scale: {:?}", seq);

            self.drain()?;
            let user = self.record_scale()?;
            // println!("Played: {:?}", user);
            if seq.adjust_octave(&user) {
                // println!("First note good: {:?}", seq);
                let diff_count = seq.differences(&user);
                println!("There are {} differences", diff_count);
                if diff_count <= 3 {
                    Ok(Status::Continue(4 - diff_count as u8))
                } else {
                    Ok(Status::Continue(1))
                }
            } else {
                println!("First note mismatch, stopping");
                Ok(Status::Stopped)
            }

        } else {
            return Err(format!("Invalid type: {:?}", json["type"].as_str()).into());
        }
    }
}

impl MidiLearn {
    /// Drain any queued midi events.
    fn drain(&mut self) -> Result<()> {
        loop {
            match self.input.read()? {
                Some(_) => (),
                None => break,
            }
        }
        Ok(())
    }

    /// Record the user playing a scale.  Consider the scale done after a small pause of no
    /// playing.
    fn record_scale(&mut self) -> Result<Vec<Vec<Note>>> {
        let mut notes: Vec<Vec<Note>> = vec![];
        let mut idle_count = 0;
        let mut last_time = 0;
        loop {
            match self.input.read()? {
                Some(ev) => {
                    // We only care about note down events here.
                    if ev.message.status & 0xf0 == 0x80 {
                        if !notes.is_empty() && ev.timestamp - last_time < 80 {
                            notes.last_mut().unwrap().push(Note(ev.message.data1));
                            // println!("chord : {:?}", notes);
                        } else {
                            // Individual note.
                            notes.push(vec![Note(ev.message.data1)]);
                            // println!("single: {:?}", notes);
                        }
                        idle_count = 0;
                        last_time = ev.timestamp;
                    }
                },
                None => {
                    idle_count += 1;
                    if notes.is_empty() {
                        idle_count = 0;
                    }
                    if idle_count >= 6 {
                        println!("Timing out");
                        break;
                    }
                    thread::sleep(Duration::from_millis(250));
                }
            }
        }

        // Sort the chords, since the incoming order could differ.
        for ch in notes.iter_mut() {
            ch.sort();
        }

        Ok(notes)
    }
}

impl Write for MidiLearn {
    fn flush(&mut self) -> io::Result<()> {
        io::stdout().flush()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        io::stdout().write(buf)
    }
}

// Determine if the json has a the given type.
fn is_type(json: &Value, t: &str) -> bool {
    json["type"] == json!(t)
}
<commit_msg>midilearn: Repeat exercises with errors<commit_after>//! Using MIDI, verify that the user is able to play a given exercise correctly.  The question
//! should be enough of a description to uniquely describe what should be played.  The answer
//! should be a parseable description of what needs to be played.
//!
//! The answer should be a JSON description of what to play, of one of the following types:
//!
//! { "type": "scale", "base": "C♯", "intervals": "WWHWWWH",
//!   "hands": 1, "octaves": 2, "style": "updown" }
//!
//! This describes a scale.  The base is the first note of the scale.  Sharps and flags can either
//! be "#" and "b" or Unicode characters "♯", and "♭".  The intervals describe the intervals
//! between each note.  Valid characters are 'H' for a half step, 'W' for a whole step, 'm' for a
//! minor third, 'M' for a major third, and '4' for a fourth.  It will be checked that the
//! intervals cover a full octabe.  Hands describes how many hands should be playing the exercise,
//! and octaves are how many octaves to play.  The currently only supported style is "updown",
//! which requires the scale be played from base to base, for the given number of octaves and then
//! back down.  Scales can be played starting in any octave.
//!
//! { "type": "voicing", "chords": [
//!    { "base": "D", "notes": [ "3", "7", "9", "5" },
//!    { "base": "G", "notes": [ "7", "3", "#9", "#5" },
//!    { "base": "C", "notes": [ "3", "7", "9", "5", "11" } ] }
//!
//! This describes a voicing exercise, which is a series of chords to be played.  Each chord has a
//! base, which may or may not actually be played.  The notes in the chord are described in musical
//! notation (again with text or Unicode sharp/flat indicators).  The chord will be built using the
//! next note of the given function.  The octave will be chosen so that the lowest non-root note
//! will be between F#-F surrounding middle C.

#![deny(missing_docs)]

extern crate editdistancewf;
extern crate portmidi;
extern crate timelearn;
#[macro_use] extern crate lazy_static;
extern crate serde;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;

use portmidi::{PortMidi, InputPort};
use serde_json::{Value};
use std::error;
use std::io::{self, Write};
use std::result;
use std::thread;
use std::time::Duration;
pub use timelearn::{Problem, Status, User};

mod note;
use note::Note;

mod scales;
use scales::{Scale, ScaleSeq};

/// Just box the errors for now.  TODO: Use a proper error type.
pub type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;

/// A learner based on playing the exercises on a MIDI device.
pub struct MidiLearn {
    input: InputPort,
}

impl MidiLearn {
    /// Construct a new MIDI learning, using the default MIDI port.  Invokes `f` with the
    /// MidiLearn.
    pub fn with_new<F, R>(f: F) -> Result<R>
        where F: FnOnce(&mut MidiLearn) -> R
    {
        let pm = PortMidi::new()?;
        let input = pm.default_input_port(4096)?;
        let mut learn = MidiLearn {
            input: input,
        };
        let result = f(&mut learn);
        Ok(result)
    }

}

impl User for MidiLearn {
    /// Practice a single exercise.  Waits for the user to play the exercise, and then returns a
    /// status indicating how well it was played.
    fn single(&mut self, word: &Problem) -> Result<Status> {
        let st1 = self.single_once(word)?;

        let mut stn = st1;
        loop {
            match stn {
                // If good, return the initial status.
                Status::Continue(4) => return Ok(st1),
                Status::Stopped => return Ok(Status::Stopped),
                _ => (),
            }
            println!("** Mistakes made, please play again **");
            stn = self.single_once(word)?;
        }
    }
}

impl MidiLearn {
    /// Ask the user once to play.
    fn single_once(&mut self, word: &Problem) -> Result<Status> {
        println!("Play: {}", word.question);

        let json: Value = serde_json::from_str(&word.answer)?;
        // println!("Json: {:?}, {:?}", json, json["typr"]);
        if is_type(&json, "scale") {
            let scale: Scale = serde_json::from_value(json)?;

            let mut seq = ScaleSeq::from_scale(&scale)?;
            // println!("scale: {:?}", seq);

            self.drain()?;
            let user = self.record_scale()?;
            // println!("Played: {:?}", user);
            if seq.adjust_octave(&user) {
                // println!("First note good: {:?}", seq);
                let diff_count = seq.differences(&user);
                println!("There are {} differences", diff_count);
                if diff_count <= 3 {
                    Ok(Status::Continue(4 - diff_count as u8))
                } else {
                    Ok(Status::Continue(1))
                }
            } else {
                println!("First note mismatch, stopping");
                Ok(Status::Stopped)
            }

        } else {
            return Err(format!("Invalid type: {:?}", json["type"].as_str()).into());
        }
    }
}

impl MidiLearn {
    /// Drain any queued midi events.
    fn drain(&mut self) -> Result<()> {
        loop {
            match self.input.read()? {
                Some(_) => (),
                None => break,
            }
        }
        Ok(())
    }

    /// Record the user playing a scale.  Consider the scale done after a small pause of no
    /// playing.
    fn record_scale(&mut self) -> Result<Vec<Vec<Note>>> {
        let mut notes: Vec<Vec<Note>> = vec![];
        let mut idle_count = 0;
        let mut last_time = 0;
        loop {
            match self.input.read()? {
                Some(ev) => {
                    // We only care about note down events here.
                    if ev.message.status & 0xf0 == 0x80 {
                        if !notes.is_empty() && ev.timestamp - last_time < 80 {
                            notes.last_mut().unwrap().push(Note(ev.message.data1));
                            // println!("chord : {:?}", notes);
                        } else {
                            // Individual note.
                            notes.push(vec![Note(ev.message.data1)]);
                            // println!("single: {:?}", notes);
                        }
                        idle_count = 0;
                        last_time = ev.timestamp;
                    }
                },
                None => {
                    idle_count += 1;
                    if notes.is_empty() {
                        idle_count = 0;
                    }
                    if idle_count >= 6 {
                        println!("Timing out");
                        break;
                    }
                    thread::sleep(Duration::from_millis(250));
                }
            }
        }

        // Sort the chords, since the incoming order could differ.
        for ch in notes.iter_mut() {
            ch.sort();
        }

        Ok(notes)
    }
}

impl Write for MidiLearn {
    fn flush(&mut self) -> io::Result<()> {
        io::stdout().flush()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        io::stdout().write(buf)
    }
}

// Determine if the json has a the given type.
fn is_type(json: &Value, t: &str) -> bool {
    json["type"] == json!(t)
}
<|endoftext|>


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

use std::cmp::min;
use std::num::Wrapping;
use std::sync::atomic::{fence, Ordering};

use sys_util::{error, GuestAddress, GuestMemory};

const VIRTQ_DESC_F_NEXT: u16 = 0x1;
const VIRTQ_DESC_F_WRITE: u16 = 0x2;
#[allow(dead_code)]
const VIRTQ_DESC_F_INDIRECT: u16 = 0x4;

const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff;

/// An iterator over a single descriptor chain.  Not to be confused with AvailIter,
/// which iterates over the descriptor chain heads in a queue.
pub struct DescIter<'a> {
    next: Option<DescriptorChain<'a>>,
}

impl<'a> DescIter<'a> {
    /// Returns an iterator that only yields the readable descriptors in the chain.
    pub fn readable(self) -> impl Iterator<Item = DescriptorChain<'a>> {
        self.take_while(DescriptorChain::is_read_only)
    }

    /// Returns an iterator that only yields the writable descriptors in the chain.
    pub fn writable(self) -> impl Iterator<Item = DescriptorChain<'a>> {
        self.skip_while(DescriptorChain::is_read_only)
    }
}

impl<'a> Iterator for DescIter<'a> {
    type Item = DescriptorChain<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(current) = self.next.take() {
            self.next = current.next_descriptor();
            Some(current)
        } else {
            None
        }
    }
}

/// A virtio descriptor chain.
#[derive(Clone)]
pub struct DescriptorChain<'a> {
    mem: &'a GuestMemory,
    desc_table: GuestAddress,
    queue_size: u16,
    ttl: u16, // used to prevent infinite chain cycles

    /// Index into the descriptor table
    pub index: u16,

    /// Guest physical address of device specific data
    pub addr: GuestAddress,

    /// Length of device specific data
    pub len: u32,

    /// Includes next, write, and indirect bits
    pub flags: u16,

    /// Index into the descriptor table of the next descriptor if flags has
    /// the next bit set
    pub next: u16,
}

impl<'a> DescriptorChain<'a> {
    pub(crate) fn checked_new(
        mem: &GuestMemory,
        desc_table: GuestAddress,
        queue_size: u16,
        index: u16,
        required_flags: u16,
    ) -> Option<DescriptorChain> {
        if index >= queue_size {
            return None;
        }

        let desc_head = match mem.checked_offset(desc_table, (index as u64) * 16) {
            Some(a) => a,
            None => return None,
        };
        // These reads can't fail unless Guest memory is hopelessly broken.
        let addr = GuestAddress(mem.read_obj_from_addr::<u64>(desc_head).unwrap() as u64);
        if mem.checked_offset(desc_head, 16).is_none() {
            return None;
        }
        let len: u32 = mem.read_obj_from_addr(desc_head.unchecked_add(8)).unwrap();
        let flags: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(12)).unwrap();
        let next: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(14)).unwrap();
        let chain = DescriptorChain {
            mem,
            desc_table,
            queue_size,
            ttl: queue_size,
            index,
            addr,
            len,
            flags,
            next,
        };

        if chain.is_valid() && chain.flags & required_flags == required_flags {
            Some(chain)
        } else {
            None
        }
    }

    #[allow(clippy::if_same_then_else)]
    fn is_valid(&self) -> bool {
        if self.len > 0
            && self
                .mem
                .checked_offset(self.addr, self.len as u64 - 1u64)
                .is_none()
        {
            false
        } else if self.has_next() && self.next >= self.queue_size {
            false
        } else {
            true
        }
    }

    /// Gets if this descriptor chain has another descriptor chain linked after it.
    pub fn has_next(&self) -> bool {
        self.flags & VIRTQ_DESC_F_NEXT != 0 && self.ttl > 1
    }

    /// If the driver designated this as a write only descriptor.
    ///
    /// If this is false, this descriptor is read only.
    /// Write only means the the emulated device can write and the driver can read.
    pub fn is_write_only(&self) -> bool {
        self.flags & VIRTQ_DESC_F_WRITE != 0
    }

    /// If the driver designated this as a read only descriptor.
    ///
    /// If this is false, this descriptor is write only.
    /// Read only means the emulated device can read and the driver can write.
    pub fn is_read_only(&self) -> bool {
        self.flags & VIRTQ_DESC_F_WRITE == 0
    }

    /// Gets the next descriptor in this descriptor chain, if there is one.
    ///
    /// Note that this is distinct from the next descriptor chain returned by `AvailIter`, which is
    /// the head of the next _available_ descriptor chain.
    pub fn next_descriptor(&self) -> Option<DescriptorChain<'a>> {
        if self.has_next() {
            // Once we see a write-only descriptor, all subsequent descriptors must be write-only.
            let required_flags = self.flags & VIRTQ_DESC_F_WRITE;
            DescriptorChain::checked_new(
                self.mem,
                self.desc_table,
                self.queue_size,
                self.next,
                required_flags,
            )
            .map(|mut c| {
                c.ttl = self.ttl - 1;
                c
            })
        } else {
            None
        }
    }

    /// Produces an iterator over all the descriptors in this chain.
    pub fn into_iter(self) -> DescIter<'a> {
        DescIter { next: Some(self) }
    }
}

/// Consuming iterator over all available descriptor chain heads in the queue.
pub struct AvailIter<'a, 'b> {
    mem: &'a GuestMemory,
    queue: &'b mut Queue,
}

impl<'a, 'b> Iterator for AvailIter<'a, 'b> {
    type Item = DescriptorChain<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.queue.pop(self.mem)
    }
}

#[derive(Clone)]
/// A virtio queue's parameters.
pub struct Queue {
    /// The maximal size in elements offered by the device
    pub max_size: u16,

    /// The queue size in elements the driver selected
    pub size: u16,

    /// Inidcates if the queue is finished with configuration
    pub ready: bool,

    /// MSI-X vector for the queue. Don't care for INTx
    pub vector: u16,

    /// Guest physical address of the descriptor table
    pub desc_table: GuestAddress,

    /// Guest physical address of the available ring
    pub avail_ring: GuestAddress,

    /// Guest physical address of the used ring
    pub used_ring: GuestAddress,

    next_avail: Wrapping<u16>,
    next_used: Wrapping<u16>,
}

impl Queue {
    /// Constructs an empty virtio queue with the given `max_size`.
    pub fn new(max_size: u16) -> Queue {
        Queue {
            max_size,
            size: max_size,
            ready: false,
            vector: VIRTIO_MSI_NO_VECTOR,
            desc_table: GuestAddress(0),
            avail_ring: GuestAddress(0),
            used_ring: GuestAddress(0),
            next_avail: Wrapping(0),
            next_used: Wrapping(0),
        }
    }

    /// Return the actual size of the queue, as the driver may not set up a
    /// queue as big as the device allows.
    pub fn actual_size(&self) -> u16 {
        min(self.size, self.max_size)
    }

    pub fn is_valid(&self, mem: &GuestMemory) -> bool {
        let queue_size = self.actual_size() as usize;
        let desc_table = self.desc_table;
        let desc_table_size = 16 * queue_size;
        let avail_ring = self.avail_ring;
        let avail_ring_size = 6 + 2 * queue_size;
        let used_ring = self.used_ring;
        let used_ring_size = 6 + 8 * queue_size;
        if !self.ready {
            error!("attempt to use virtio queue that is not marked ready");
            false
        } else if self.size > self.max_size || self.size == 0 || (self.size & (self.size - 1)) != 0
        {
            error!("virtio queue with invalid size: {}", self.size);
            false
        } else if desc_table
            .checked_add(desc_table_size as u64)
            .map_or(true, |v| !mem.address_in_range(v))
        {
            error!(
                "virtio queue descriptor table goes out of bounds: start:0x{:08x} size:0x{:08x}",
                desc_table.offset(),
                desc_table_size
            );
            false
        } else if avail_ring
            .checked_add(avail_ring_size as u64)
            .map_or(true, |v| !mem.address_in_range(v))
        {
            error!(
                "virtio queue available ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                avail_ring.offset(),
                avail_ring_size
            );
            false
        } else if used_ring
            .checked_add(used_ring_size as u64)
            .map_or(true, |v| !mem.address_in_range(v))
        {
            error!(
                "virtio queue used ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                used_ring.offset(),
                used_ring_size
            );
            false
        } else {
            true
        }
    }

    /// If a new DescriptorHead is available, returns one and removes it from the queue.
    pub fn pop<'a>(&mut self, mem: &'a GuestMemory) -> Option<DescriptorChain<'a>> {
        if !self.is_valid(mem) {
            return None;
        }

        let queue_size = self.actual_size();
        let avail_index_addr = mem.checked_offset(self.avail_ring, 2).unwrap();
        let avail_index: u16 = mem.read_obj_from_addr(avail_index_addr).unwrap();
        let avail_len = Wrapping(avail_index) - self.next_avail;

        if avail_len.0 > queue_size || self.next_avail == Wrapping(avail_index) {
            return None;
        }

        let desc_idx_addr_offset = (4 + (self.next_avail.0 % queue_size) * 2) as u64;
        let desc_idx_addr = mem.checked_offset(self.avail_ring, desc_idx_addr_offset)?;

        // This index is checked below in checked_new.
        let descriptor_index: u16 = mem.read_obj_from_addr(desc_idx_addr).unwrap();

        let descriptor_chain =
            DescriptorChain::checked_new(mem, self.desc_table, queue_size, descriptor_index, 0);
        if descriptor_chain.is_some() {
            self.next_avail += Wrapping(1);
        }
        descriptor_chain
    }

    /// A consuming iterator over all available descriptor chain heads offered by the driver.
    pub fn iter<'a, 'b>(&'b mut self, mem: &'a GuestMemory) -> AvailIter<'a, 'b> {
        AvailIter { mem, queue: self }
    }

    /// Puts an available descriptor head into the used ring for use by the guest.
    pub fn add_used(&mut self, mem: &GuestMemory, desc_index: u16, len: u32) {
        if desc_index >= self.actual_size() {
            error!(
                "attempted to add out of bounds descriptor to used ring: {}",
                desc_index
            );
            return;
        }

        let used_ring = self.used_ring;
        let next_used = (self.next_used.0 % self.actual_size()) as usize;
        let used_elem = used_ring.unchecked_add((4 + next_used * 8) as u64);

        // These writes can't fail as we are guaranteed to be within the descriptor ring.
        mem.write_obj_at_addr(desc_index as u32, used_elem).unwrap();
        mem.write_obj_at_addr(len as u32, used_elem.unchecked_add(4))
            .unwrap();

        self.next_used += Wrapping(1);

        // This fence ensures all descriptor writes are visible before the index update is.
        fence(Ordering::Release);

        mem.write_obj_at_addr(self.next_used.0 as u16, used_ring.unchecked_add(2))
            .unwrap();
    }
}
<commit_msg>virtio: Convert ring index to u64 earlier in Queue::pop<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cmp::min;
use std::num::Wrapping;
use std::sync::atomic::{fence, Ordering};

use sys_util::{error, GuestAddress, GuestMemory};

const VIRTQ_DESC_F_NEXT: u16 = 0x1;
const VIRTQ_DESC_F_WRITE: u16 = 0x2;
#[allow(dead_code)]
const VIRTQ_DESC_F_INDIRECT: u16 = 0x4;

const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff;

/// An iterator over a single descriptor chain.  Not to be confused with AvailIter,
/// which iterates over the descriptor chain heads in a queue.
pub struct DescIter<'a> {
    next: Option<DescriptorChain<'a>>,
}

impl<'a> DescIter<'a> {
    /// Returns an iterator that only yields the readable descriptors in the chain.
    pub fn readable(self) -> impl Iterator<Item = DescriptorChain<'a>> {
        self.take_while(DescriptorChain::is_read_only)
    }

    /// Returns an iterator that only yields the writable descriptors in the chain.
    pub fn writable(self) -> impl Iterator<Item = DescriptorChain<'a>> {
        self.skip_while(DescriptorChain::is_read_only)
    }
}

impl<'a> Iterator for DescIter<'a> {
    type Item = DescriptorChain<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(current) = self.next.take() {
            self.next = current.next_descriptor();
            Some(current)
        } else {
            None
        }
    }
}

/// A virtio descriptor chain.
#[derive(Clone)]
pub struct DescriptorChain<'a> {
    mem: &'a GuestMemory,
    desc_table: GuestAddress,
    queue_size: u16,
    ttl: u16, // used to prevent infinite chain cycles

    /// Index into the descriptor table
    pub index: u16,

    /// Guest physical address of device specific data
    pub addr: GuestAddress,

    /// Length of device specific data
    pub len: u32,

    /// Includes next, write, and indirect bits
    pub flags: u16,

    /// Index into the descriptor table of the next descriptor if flags has
    /// the next bit set
    pub next: u16,
}

impl<'a> DescriptorChain<'a> {
    pub(crate) fn checked_new(
        mem: &GuestMemory,
        desc_table: GuestAddress,
        queue_size: u16,
        index: u16,
        required_flags: u16,
    ) -> Option<DescriptorChain> {
        if index >= queue_size {
            return None;
        }

        let desc_head = match mem.checked_offset(desc_table, (index as u64) * 16) {
            Some(a) => a,
            None => return None,
        };
        // These reads can't fail unless Guest memory is hopelessly broken.
        let addr = GuestAddress(mem.read_obj_from_addr::<u64>(desc_head).unwrap() as u64);
        if mem.checked_offset(desc_head, 16).is_none() {
            return None;
        }
        let len: u32 = mem.read_obj_from_addr(desc_head.unchecked_add(8)).unwrap();
        let flags: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(12)).unwrap();
        let next: u16 = mem.read_obj_from_addr(desc_head.unchecked_add(14)).unwrap();
        let chain = DescriptorChain {
            mem,
            desc_table,
            queue_size,
            ttl: queue_size,
            index,
            addr,
            len,
            flags,
            next,
        };

        if chain.is_valid() && chain.flags & required_flags == required_flags {
            Some(chain)
        } else {
            None
        }
    }

    #[allow(clippy::if_same_then_else)]
    fn is_valid(&self) -> bool {
        if self.len > 0
            && self
                .mem
                .checked_offset(self.addr, self.len as u64 - 1u64)
                .is_none()
        {
            false
        } else if self.has_next() && self.next >= self.queue_size {
            false
        } else {
            true
        }
    }

    /// Gets if this descriptor chain has another descriptor chain linked after it.
    pub fn has_next(&self) -> bool {
        self.flags & VIRTQ_DESC_F_NEXT != 0 && self.ttl > 1
    }

    /// If the driver designated this as a write only descriptor.
    ///
    /// If this is false, this descriptor is read only.
    /// Write only means the the emulated device can write and the driver can read.
    pub fn is_write_only(&self) -> bool {
        self.flags & VIRTQ_DESC_F_WRITE != 0
    }

    /// If the driver designated this as a read only descriptor.
    ///
    /// If this is false, this descriptor is write only.
    /// Read only means the emulated device can read and the driver can write.
    pub fn is_read_only(&self) -> bool {
        self.flags & VIRTQ_DESC_F_WRITE == 0
    }

    /// Gets the next descriptor in this descriptor chain, if there is one.
    ///
    /// Note that this is distinct from the next descriptor chain returned by `AvailIter`, which is
    /// the head of the next _available_ descriptor chain.
    pub fn next_descriptor(&self) -> Option<DescriptorChain<'a>> {
        if self.has_next() {
            // Once we see a write-only descriptor, all subsequent descriptors must be write-only.
            let required_flags = self.flags & VIRTQ_DESC_F_WRITE;
            DescriptorChain::checked_new(
                self.mem,
                self.desc_table,
                self.queue_size,
                self.next,
                required_flags,
            )
            .map(|mut c| {
                c.ttl = self.ttl - 1;
                c
            })
        } else {
            None
        }
    }

    /// Produces an iterator over all the descriptors in this chain.
    pub fn into_iter(self) -> DescIter<'a> {
        DescIter { next: Some(self) }
    }
}

/// Consuming iterator over all available descriptor chain heads in the queue.
pub struct AvailIter<'a, 'b> {
    mem: &'a GuestMemory,
    queue: &'b mut Queue,
}

impl<'a, 'b> Iterator for AvailIter<'a, 'b> {
    type Item = DescriptorChain<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.queue.pop(self.mem)
    }
}

#[derive(Clone)]
/// A virtio queue's parameters.
pub struct Queue {
    /// The maximal size in elements offered by the device
    pub max_size: u16,

    /// The queue size in elements the driver selected
    pub size: u16,

    /// Inidcates if the queue is finished with configuration
    pub ready: bool,

    /// MSI-X vector for the queue. Don't care for INTx
    pub vector: u16,

    /// Guest physical address of the descriptor table
    pub desc_table: GuestAddress,

    /// Guest physical address of the available ring
    pub avail_ring: GuestAddress,

    /// Guest physical address of the used ring
    pub used_ring: GuestAddress,

    next_avail: Wrapping<u16>,
    next_used: Wrapping<u16>,
}

impl Queue {
    /// Constructs an empty virtio queue with the given `max_size`.
    pub fn new(max_size: u16) -> Queue {
        Queue {
            max_size,
            size: max_size,
            ready: false,
            vector: VIRTIO_MSI_NO_VECTOR,
            desc_table: GuestAddress(0),
            avail_ring: GuestAddress(0),
            used_ring: GuestAddress(0),
            next_avail: Wrapping(0),
            next_used: Wrapping(0),
        }
    }

    /// Return the actual size of the queue, as the driver may not set up a
    /// queue as big as the device allows.
    pub fn actual_size(&self) -> u16 {
        min(self.size, self.max_size)
    }

    pub fn is_valid(&self, mem: &GuestMemory) -> bool {
        let queue_size = self.actual_size() as usize;
        let desc_table = self.desc_table;
        let desc_table_size = 16 * queue_size;
        let avail_ring = self.avail_ring;
        let avail_ring_size = 6 + 2 * queue_size;
        let used_ring = self.used_ring;
        let used_ring_size = 6 + 8 * queue_size;
        if !self.ready {
            error!("attempt to use virtio queue that is not marked ready");
            false
        } else if self.size > self.max_size || self.size == 0 || (self.size & (self.size - 1)) != 0
        {
            error!("virtio queue with invalid size: {}", self.size);
            false
        } else if desc_table
            .checked_add(desc_table_size as u64)
            .map_or(true, |v| !mem.address_in_range(v))
        {
            error!(
                "virtio queue descriptor table goes out of bounds: start:0x{:08x} size:0x{:08x}",
                desc_table.offset(),
                desc_table_size
            );
            false
        } else if avail_ring
            .checked_add(avail_ring_size as u64)
            .map_or(true, |v| !mem.address_in_range(v))
        {
            error!(
                "virtio queue available ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                avail_ring.offset(),
                avail_ring_size
            );
            false
        } else if used_ring
            .checked_add(used_ring_size as u64)
            .map_or(true, |v| !mem.address_in_range(v))
        {
            error!(
                "virtio queue used ring goes out of bounds: start:0x{:08x} size:0x{:08x}",
                used_ring.offset(),
                used_ring_size
            );
            false
        } else {
            true
        }
    }

    /// If a new DescriptorHead is available, returns one and removes it from the queue.
    pub fn pop<'a>(&mut self, mem: &'a GuestMemory) -> Option<DescriptorChain<'a>> {
        if !self.is_valid(mem) {
            return None;
        }

        let queue_size = self.actual_size();
        let avail_index_addr = mem.checked_offset(self.avail_ring, 2).unwrap();
        let avail_index: u16 = mem.read_obj_from_addr(avail_index_addr).unwrap();
        let avail_len = Wrapping(avail_index) - self.next_avail;

        if avail_len.0 > queue_size || self.next_avail == Wrapping(avail_index) {
            return None;
        }

        let desc_idx_addr_offset = 4 + (u64::from(self.next_avail.0 % queue_size) * 2);
        let desc_idx_addr = mem.checked_offset(self.avail_ring, desc_idx_addr_offset)?;

        // This index is checked below in checked_new.
        let descriptor_index: u16 = mem.read_obj_from_addr(desc_idx_addr).unwrap();

        let descriptor_chain =
            DescriptorChain::checked_new(mem, self.desc_table, queue_size, descriptor_index, 0);
        if descriptor_chain.is_some() {
            self.next_avail += Wrapping(1);
        }
        descriptor_chain
    }

    /// A consuming iterator over all available descriptor chain heads offered by the driver.
    pub fn iter<'a, 'b>(&'b mut self, mem: &'a GuestMemory) -> AvailIter<'a, 'b> {
        AvailIter { mem, queue: self }
    }

    /// Puts an available descriptor head into the used ring for use by the guest.
    pub fn add_used(&mut self, mem: &GuestMemory, desc_index: u16, len: u32) {
        if desc_index >= self.actual_size() {
            error!(
                "attempted to add out of bounds descriptor to used ring: {}",
                desc_index
            );
            return;
        }

        let used_ring = self.used_ring;
        let next_used = (self.next_used.0 % self.actual_size()) as usize;
        let used_elem = used_ring.unchecked_add((4 + next_used * 8) as u64);

        // These writes can't fail as we are guaranteed to be within the descriptor ring.
        mem.write_obj_at_addr(desc_index as u32, used_elem).unwrap();
        mem.write_obj_at_addr(len as u32, used_elem.unchecked_add(4))
            .unwrap();

        self.next_used += Wrapping(1);

        // This fence ensures all descriptor writes are visible before the index update is.
        fence(Ordering::Release);

        mem.write_obj_at_addr(self.next_used.0 as u16, used_ring.unchecked_add(2))
            .unwrap();
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix warnings<commit_after><|endoftext|>


<commit_before><commit_msg>librustc: Remove the `const` declaration form everywhere<commit_after><|endoftext|>


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

use std::env;

fn main() {
    let include_paths = if env::var("USE_SYSTEM_OPENEXR").map(|x| x != "0").unwrap_or(false) {
        // We don't take linker flags from IlmBase because OpenEXR's subsume them.
        let ilm = pkg_config::Config::new().cargo_metadata(false).probe("IlmBase").unwrap();
        let exr = pkg_config::probe_library("OpenEXR").unwrap();
        let mut include_paths = ilm.include_paths.clone();
        include_paths.extend_from_slice(&exr.include_paths);
        include_paths
    } else {
        // Build IlmBase
        let ilmbase_dst = cmake::Config::new("openexr/IlmBase")
            .define("BUILD_SHARED_LIBS", "OFF")
            .build();
        println!("cargo:rustc-link-search=native={}", ilmbase_dst.join("lib").display());

        // Build OpenEXR
        let openexr_dst = cmake::Config::new("openexr/OpenEXR")
            .define("ILMBASE_PACKAGE_PREFIX", &ilmbase_dst)
            .define("BUILD_SHARED_LIBS", "OFF")
            .build();
        println!("cargo:rustc-link-search=native={}", openexr_dst.join("lib").display());

        // Link all the libs from OpenEXR
        println!("cargo:rustc-link-lib=static=IlmImf-2_2");
        println!("cargo:rustc-link-lib=static=IlmImfUtil-2_2");
        println!("cargo:rustc-link-lib=static=IexMath-2_2");
        println!("cargo:rustc-link-lib=static=Iex-2_2");
        println!("cargo:rustc-link-lib=static=Imath-2_2");
        println!("cargo:rustc-link-lib=static=IlmThread-2_2");
        println!("cargo:rustc-link-lib=static=Half");

        vec![openexr_dst.join("include")]
    };

    // Build C wrapper for OpenEXR
    let mut gcc = gcc::Config::new();
    gcc.cpp(true)
        .flag("-std=c++11")
        .include("c_wrapper");
    for path in &include_paths {
        gcc.include(path);
    }
    gcc.file("c_wrapper/cexr.cpp")
        .file("c_wrapper/memory_istream.cpp")
        .compile("libcexr.a");

    // Find and link zlib, needed for OpenEXR
    pkg_config::probe_library("zlib").unwrap();
}
<commit_msg>Fix windows build<commit_after>extern crate pkg_config;
extern crate cmake;
extern crate gcc;

use std::env;

fn main() {
    let include_paths = if env::var("USE_SYSTEM_OPENEXR").map(|x| x != "0").unwrap_or(false) {
        // We don't take linker flags from IlmBase because OpenEXR's subsume them.
        let ilm = pkg_config::Config::new().cargo_metadata(false).probe("IlmBase").unwrap();
        let exr = pkg_config::probe_library("OpenEXR").unwrap();
        let mut include_paths = ilm.include_paths.clone();
        include_paths.extend_from_slice(&exr.include_paths);
        include_paths
    } else {
        // Build IlmBase
        let ilmbase_dst = cmake::Config::new("openexr/IlmBase")
            .define("BUILD_SHARED_LIBS", "OFF")
            .build();
        println!("cargo:rustc-link-search=native={}", ilmbase_dst.join("lib").display());

        // Build OpenEXR
        let mut openexr_cfg = cmake::Config::new("openexr/OpenEXR");
        openexr_cfg.define("ILMBASE_PACKAGE_PREFIX", &ilmbase_dst)
            .define("BUILD_SHARED_LIBS", "OFF");
        #[cfg(windows)]
        openexr_cfg.cxxflag("/DWIN32");
        let openexr_dst = openexr_cfg.build();
        println!("cargo:rustc-link-search=native={}", openexr_dst.join("lib").display());

        // Link all the libs from OpenEXR
        println!("cargo:rustc-link-lib=static=IlmImf-2_2");
        println!("cargo:rustc-link-lib=static=IlmImfUtil-2_2");
        println!("cargo:rustc-link-lib=static=IexMath-2_2");
        println!("cargo:rustc-link-lib=static=Iex-2_2");
        println!("cargo:rustc-link-lib=static=Imath-2_2");
        println!("cargo:rustc-link-lib=static=IlmThread-2_2");
        println!("cargo:rustc-link-lib=static=Half");

        vec![openexr_dst.join("include")]
    };

    // Build C wrapper for OpenEXR
    let mut gcc = gcc::Config::new();
    gcc.cpp(true)
        .include("c_wrapper");
    #[cfg(target_env = "msvc")]
    gcc.flag("/std:c++14");
    #[cfg(not(target_env = "msvc"))]
    gcc.flag("-std=c++14");
    for path in &include_paths {
        gcc.include(path);
    }
    gcc.file("c_wrapper/cexr.cpp")
        .file("c_wrapper/memory_istream.cpp")
        .compile("libcexr.a");

    // Find and link zlib, needed for OpenEXR
    if let Err(err) = pkg_config::probe_library("zlib") {
        if let Ok(path) = env::var("ZLIB_LIBRARY") {
            println!("cargo:rustc-link-search=native={}", path);
            println!("cargo:rustc-link-lib=static=zlibstatic");
        } else {
            panic!("couldn't find zlib: ZLIB_LIBRARY is unset and pkg-config failed: {}", err);
        }
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate serialize;
#[phase(plugin, link)] extern crate log;

extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::collections::TreeSet;
use std::os;
use std::io;
use std::io::fs;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use docopt::FlagParser;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute_main_without_stdin(execute, true)
}

docopt!(Flags, "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
")

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo; args={}", os::args());
    shell.set_verbose(flags.flag_verbose);
    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().iter() {
            println!("    {}", command);
            // TODO: it might be helpful to add result of -h to each command.
        };
        return Ok(None)
    }
    let mut args = flags.arg_args.clone();
    args.insert(0, flags.arg_command.clone());
    match flags.arg_command.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            let r = cargo::call_main_without_stdin(config_for_key, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            let r = cargo::call_main_without_stdin(config_list, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            let r = cargo::call_main_without_stdin(locate_project, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        // If we have `help` with no arguments, re-invoke ourself with `-h` to
        // get the help message printed
        "help" if flags.arg_args.len() == 0 => {
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin(execute, shell,
                                                   ["-h".to_string()], false);
            cargo::process_executed(r, shell)
        },
        orig_cmd => {
            let is_help = orig_cmd == "help";
            let cmd = if is_help {
                flags.arg_args[0].as_slice()
            } else {
                orig_cmd
            };
            execute_subcommand(cmd, is_help, &flags, shell)
        }
    }
    Ok(None)
}

fn execute_subcommand(cmd: &str, is_help: bool, flags: &Flags, shell: &mut MultiShell) -> () {
    match find_command(cmd) {
        Some(command) => {
            let mut command = Command::new(command);
            let command = if is_help {
                command.arg("-h")
            } else {
                command.args(flags.arg_args.as_slice())
            };
            let status = command
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match status {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) => {
                    handle_error(CliError::new("", i as uint), shell)
                }
                Ok(ExitSignal(i)) => {
                    let msg = format!("subcommand failed with signal: {}", i);
                    handle_error(CliError::new(msg, i as uint), shell)
                }
                Err(io::IoError{kind, ..}) if kind == io::FileNotFound =>
                    handle_error(CliError::new("No such subcommand", 127), shell),
                Err(err) => handle_error(
                    CliError::new(
                        format!("Subcommand failed to run: {}", err), 127),
                    shell)
            }
        },
        None => handle_error(CliError::new("No such subcommand", 127), shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> TreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = TreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(os::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = filename.slice(
                    command_prefix.len(),
                    filename.len() - os::consts::EXE_SUFFIX.len());
                commands.insert(String::from_str(command));
            }
        }
    }
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(io::FileStat{kind, perm, ..}) =>
            (kind == io::TypeFile) && perm.contains(io::OtherExecute),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(command_exe.as_slice()));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    match os::self_exe_path() {
        Some(path) => {
            dirs.push(path.join("../lib/cargo"));
            dirs.push(path);
        },
        None => {}
    };
    match std::os::getenv("PATH") {
        Some(val) => {
            for dir in os::split_paths(val).iter() {
                dirs.push(Path::new(dir))
            }
        },
        None => {}
    };
    dirs
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

docopt!(ConfigForKeyFlags, "
Usage: cargo config-for-key --human --key=<key>
")

fn config_for_key(args: ConfigForKeyFlags,
                  _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.flag_key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.flag_human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.flag_key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

docopt!(ConfigListFlags, "
Usage: cargo config-list --human
")

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.flag_human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

docopt!(LocateProjectFlags, "
Usage: cargo locate-project
")

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

fn locate_project(_: LocateProjectFlags,
                  _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<commit_msg>Print help message if cargo is invoked with no arguments<commit_after>#![feature(phase)]

extern crate serialize;
#[phase(plugin, link)] extern crate log;

extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;

use std::collections::TreeSet;
use std::os;
use std::io;
use std::io::fs;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use docopt::FlagParser;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute_main_without_stdin(execute, true)
}

docopt!(Flags, "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
")

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, shell: &mut MultiShell) -> CliResult<Option<()>> {
    debug!("executing; cmd=cargo; args={}", os::args());
    shell.set_verbose(flags.flag_verbose);
    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().iter() {
            println!("    {}", command);
            // TODO: it might be helpful to add result of -h to each command.
        };
        return Ok(None)
    }
    let mut args = flags.arg_args.clone();
    args.insert(0, flags.arg_command.clone());
    match flags.arg_command.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            let r = cargo::call_main_without_stdin(config_for_key, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            let r = cargo::call_main_without_stdin(config_list, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            let r = cargo::call_main_without_stdin(locate_project, shell,
                                                   args.as_slice(), false);
            cargo::process_executed(r, shell)
        },
        // If we are invoked with no arguments or with `help` with no
        // arguments, re-invoke ourself with `-h` to get the help
        // message printed
        "" | "help" if flags.arg_args.len() == 0 => {
            shell.set_verbose(true);
            let r = cargo::call_main_without_stdin(execute, shell,
                                                   ["-h".to_string()], false);
            cargo::process_executed(r, shell)
        },
        orig_cmd => {
            let is_help = orig_cmd == "help";
            let cmd = if is_help {
                flags.arg_args[0].as_slice()
            } else {
                orig_cmd
            };
            execute_subcommand(cmd, is_help, &flags, shell)
        }
    }
    Ok(None)
}

fn execute_subcommand(cmd: &str, is_help: bool, flags: &Flags, shell: &mut MultiShell) -> () {
    match find_command(cmd) {
        Some(command) => {
            let mut command = Command::new(command);
            let command = if is_help {
                command.arg("-h")
            } else {
                command.args(flags.arg_args.as_slice())
            };
            let status = command
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match status {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) => {
                    handle_error(CliError::new("", i as uint), shell)
                }
                Ok(ExitSignal(i)) => {
                    let msg = format!("subcommand failed with signal: {}", i);
                    handle_error(CliError::new(msg, i as uint), shell)
                }
                Err(io::IoError{kind, ..}) if kind == io::FileNotFound =>
                    handle_error(CliError::new("No such subcommand", 127), shell),
                Err(err) => handle_error(
                    CliError::new(
                        format!("Subcommand failed to run: {}", err), 127),
                    shell)
            }
        },
        None => handle_error(CliError::new("No such subcommand", 127), shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> TreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = TreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(os::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = filename.slice(
                    command_prefix.len(),
                    filename.len() - os::consts::EXE_SUFFIX.len());
                commands.insert(String::from_str(command));
            }
        }
    }
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(io::FileStat{kind, perm, ..}) =>
            (kind == io::TypeFile) && perm.contains(io::OtherExecute),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, os::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(command_exe.as_slice()));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    match os::self_exe_path() {
        Some(path) => {
            dirs.push(path.join("../lib/cargo"));
            dirs.push(path);
        },
        None => {}
    };
    match std::os::getenv("PATH") {
        Some(val) => {
            for dir in os::split_paths(val).iter() {
                dirs.push(Path::new(dir))
            }
        },
        None => {}
    };
    dirs
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

docopt!(ConfigForKeyFlags, "
Usage: cargo config-for-key --human --key=<key>
")

fn config_for_key(args: ConfigForKeyFlags,
                  _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.flag_key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.flag_human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.flag_key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

docopt!(ConfigListFlags, "
Usage: cargo config-list --human
")

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.flag_human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

docopt!(LocateProjectFlags, "
Usage: cargo locate-project
")

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

fn locate_project(_: LocateProjectFlags,
                  _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(&os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_string() }))
}
<|endoftext|>


<commit_before>#![warn(unused, bad_style,
        unused_qualifications, unused_typecasts, unused_results)]

#![feature(macro_rules, slicing_syntax)]

extern crate glob;
extern crate num;
extern crate serialize;
extern crate term;
extern crate common;

use std::{io, os, str};
use std::io::{Command, MemReader};
use std::io::process::ExitStatus;
use std::path::Display;
use std::str::{MaybeOwned, SendStr};
use glob::Paths;
use num::Integer;
use serialize::{json, Decodable};
use term::{color, Terminal};
use term::color::Color;
use common::SolveResult;

const PROBLEM_EXE_PAT: &'static str = "p[0-9][0-9][0-9]";

const NSEC_PER_SEC:    u64 = 1000000000;
const NSEC_WARN_LIMIT: u64 = 1  * NSEC_PER_SEC;
const NSEC_NG_LIMIT:   u64 = 10 * NSEC_PER_SEC;

const COLOR_OK:   Color = color::GREEN;
const COLOR_NG:   Color = color::RED;
const COLOR_WARN: Color = color::YELLOW;

macro_rules! try2(
    ($e:expr) => (try!($e.map_err(|e| e.to_program_error())))
)

type ProgramResult<T> = Result<T, ProgramError>;
type OutputPair<'a> = (Option<Color>, MaybeOwned<'a>);

#[deriving(Show)]
enum ProgramErrorKind {
    IoError(io::IoError),
    JsonSyntaxError(json::ErrorCode, uint, uint),
    JsonDecoderError(json::DecoderError),
    Unknown
}

#[deriving(Show)]
struct ProgramError {
    kind: ProgramErrorKind,
    message: SendStr
}

impl ProgramError {
    pub fn new<T: IntoMaybeOwned<'static>>(msg: T, kind: ProgramErrorKind) -> ProgramError {
        ProgramError {
            kind: kind,
            message: msg.into_maybe_owned()
        }
    }
}

trait ToProgramError {
    fn to_program_error(self) -> ProgramError;
}

impl ToProgramError for io::IoError {
    fn to_program_error(self) -> ProgramError {
        ProgramError::new(self.desc.into_maybe_owned(), IoError(self))
    }
}

impl ToProgramError for json::ParserError {
    fn to_program_error(self) -> ProgramError {
        match self {
            json::SyntaxError(code, line, col) => {
                ProgramError::new(format!("{}:{}:{}", line, col, json::error_str(code)),
                                  JsonSyntaxError(code, line, col))
            },
            json::IoError(kind, desc) => {
                (io::IoError {kind: kind, desc: desc, detail: None })
                    .to_program_error()
            }
        }
    }
}

impl ToProgramError for json::DecoderError {
    fn to_program_error(self: json::DecoderError) -> ProgramError {
        ProgramError::new(format!("{}", self), JsonDecoderError(self))
    }
}

fn exe_path() -> ProgramResult<Path> {
    match os::self_exe_name() {
        Some(x) => Ok(x),
        None    => Err(ProgramError::new("cannot get self exe name", Unknown))
    }
}

fn problem_paths(dir_path: Path) -> ProgramResult<Paths> {
    let pat = dir_path.join(PROBLEM_EXE_PAT);
    match pat.as_str() {
        Some(x) => Ok(glob::glob(x)),
        None    => Err(ProgramError::new("path contains non-utf8 character", Unknown))
    }
}

fn run_problem(path: &Path) -> ProgramResult<SolveResult<String>> {
    let proc_out = try2!(Command::new(path).output());

    if !proc_out.error.is_empty() {
        let _ = match str::from_utf8(proc_out.error[]) {
            Some(s) => writeln!(&mut io::stderr(), "{}", s.trim()),
            None    => writeln!(&mut io::stderr(), "{}", proc_out.error)
        };
    }

    match proc_out.status {
        ExitStatus(0) | ExitStatus(1) => { } // expected
        st => {
            return Err(ProgramError::new(format!("child process exit with {}", st), Unknown))
        }
    }

    let json = try2!(json::from_reader(&mut MemReader::new(proc_out.output)));
    Ok(try2!(Decodable::decode(&mut json::Decoder::new(json))))
}

fn print_items<'a>(items: &[OutputPair]) {
    match term::stdout() {
        None => {
            let mut out = io::stdout();
            for &(_, ref s) in items.iter() { let _ = out.write_str(s.as_slice()); }
            let _ = out.flush();
        },
        Some(mut t) => {
            for &(c, ref s) in items.iter() {
                match c {
                    Some(c) => { let _ = t.fg(c); let _ = t.write_str(s.as_slice()); let _ = t.reset(); }
                    None    => { let _ = t.write_str(s.as_slice()); }
                }
            }
            let _ = t.flush();
        }
    }
}

fn print_result<'a, T: GenericPath>(name: Display<T>, result: ProgramResult<SolveResult<String>>) {
    let mut items = vec![];
    match result {
        Ok(r) => {
            items.push(normal("["));
            if r.is_ok {
                items.push(ok("OK"));
            } else {
                items.push(ng("NG"));
                os::set_exit_status(1);
            }
            items.push(normal("] "));
            items.push(normal(format!("{} ", name)));
            items.push(normal(format!("{:20} ", r.answer)));
            let (sec, nsec) = r.time.div_rem(&NSEC_PER_SEC);
            let time_str = format!("{:3}.{:09}", sec, nsec);
            if r.time < NSEC_WARN_LIMIT {
                items.push(normal(time_str));
            } else if r.time < NSEC_NG_LIMIT {
                items.push(warn(time_str));
            } else {
                items.push(ng(time_str));
            }
        }
        Err(e) => {
            items.push(normal("["));
            items.push(ng("!!"));
            items.push(normal("] "));
            items.push(normal(format!("{} ", name)));
            items.push(normal(format!("{}", e)));
            os::set_exit_status(1);
        }
    }
    items.push(normal("\n"));
    print_items(items[]);

    fn normal<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (None, s.into_maybe_owned())
    }
    fn ok<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (Some(COLOR_OK), s.into_maybe_owned())
    }
    fn warn<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (Some(COLOR_WARN), s.into_maybe_owned())
    }
    fn ng<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (Some(COLOR_NG), s.into_maybe_owned())
    }
}

fn run() -> ProgramResult<()> {
    let dir_path = try!(exe_path()).dir_path();

    for path in try!(problem_paths(dir_path)) {
        print_result(path.filename_display(), run_problem(&path));
    }

    Ok(())
}

fn main() {
    match run() {
        Ok(()) => {}
        Err(e) => {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            os::set_exit_status(255);
        }
    }
}
<commit_msg>euler: print average and total time<commit_after>#![warn(unused, bad_style,
        unused_qualifications, unused_typecasts, unused_results)]

#![feature(if_let, macro_rules, slicing_syntax)]

extern crate glob;
extern crate num;
extern crate serialize;
extern crate term;
extern crate common;

use std::{io, os, str};
use std::io::{Command, MemReader};
use std::io::process::ExitStatus;
use std::str::{MaybeOwned, SendStr};
use glob::Paths;
use num::Integer;
use serialize::{json, Decodable};
use term::{color, Terminal};
use term::color::Color;
use common::SolveResult;

const PROBLEM_EXE_PAT: &'static str = "p[0-9][0-9][0-9]";

const NSEC_PER_SEC:    u64 = 1000000000;
const NSEC_WARN_LIMIT: u64 = 1  * NSEC_PER_SEC;
const NSEC_NG_LIMIT:   u64 = 10 * NSEC_PER_SEC;

const COLOR_OK:   Color = color::GREEN;
const COLOR_NG:   Color = color::RED;
const COLOR_WARN: Color = color::YELLOW;

macro_rules! try2(
    ($e:expr) => (try!($e.map_err(|e| e.to_program_error())))
)

type ProgramResult<T> = Result<T, ProgramError>;
type OutputPair<'a> = (Option<Color>, MaybeOwned<'a>);

#[deriving(Show)]
enum ProgramErrorKind {
    IoError(io::IoError),
    JsonSyntaxError(json::ErrorCode, uint, uint),
    JsonDecoderError(json::DecoderError),
    Unknown
}

#[deriving(Show)]
struct ProgramError {
    kind: ProgramErrorKind,
    message: SendStr
}

impl ProgramError {
    pub fn new<T: IntoMaybeOwned<'static>>(msg: T, kind: ProgramErrorKind) -> ProgramError {
        ProgramError {
            kind: kind,
            message: msg.into_maybe_owned()
        }
    }
}

trait ToProgramError {
    fn to_program_error(self) -> ProgramError;
}

impl ToProgramError for io::IoError {
    fn to_program_error(self) -> ProgramError {
        ProgramError::new(self.desc.into_maybe_owned(), IoError(self))
    }
}

impl ToProgramError for json::ParserError {
    fn to_program_error(self) -> ProgramError {
        match self {
            json::SyntaxError(code, line, col) => {
                ProgramError::new(format!("{}:{}:{}", line, col, json::error_str(code)),
                                  JsonSyntaxError(code, line, col))
            },
            json::IoError(kind, desc) => {
                (io::IoError {kind: kind, desc: desc, detail: None })
                    .to_program_error()
            }
        }
    }
}

impl ToProgramError for json::DecoderError {
    fn to_program_error(self: json::DecoderError) -> ProgramError {
        ProgramError::new(format!("{}", self), JsonDecoderError(self))
    }
}

fn exe_path() -> ProgramResult<Path> {
    match os::self_exe_name() {
        Some(x) => Ok(x),
        None    => Err(ProgramError::new("cannot get self exe name", Unknown))
    }
}

fn problem_paths(dir_path: Path) -> ProgramResult<Paths> {
    let pat = dir_path.join(PROBLEM_EXE_PAT);
    match pat.as_str() {
        Some(x) => Ok(glob::glob(x)),
        None    => Err(ProgramError::new("path contains non-utf8 character", Unknown))
    }
}

fn run_problem(path: &Path) -> ProgramResult<SolveResult<String>> {
    let proc_out = try2!(Command::new(path).output());

    if !proc_out.error.is_empty() {
        let _ = match str::from_utf8(proc_out.error[]) {
            Some(s) => writeln!(&mut io::stderr(), "{}", s.trim()),
            None    => writeln!(&mut io::stderr(), "{}", proc_out.error)
        };
    }

    match proc_out.status {
        ExitStatus(0) | ExitStatus(1) => { } // expected
        st => {
            return Err(ProgramError::new(format!("child process exit with {}", st), Unknown))
        }
    }

    let json = try2!(json::from_reader(&mut MemReader::new(proc_out.output)));
    Ok(try2!(Decodable::decode(&mut json::Decoder::new(json))))
}

fn print_items<'a>(items: &[OutputPair]) {
    match term::stdout() {
        None => {
            let mut out = io::stdout();
            for &(_, ref s) in items.iter() {
                let _ = out.write_str(s.as_slice());
            }
            let _ = out.flush();
        }
        Some(mut t) => {
            for &(c, ref s) in items.iter() {
                match c {
                    Some(c) => {
                        let _ = t.fg(c);
                        let _ = t.write_str(s.as_slice());
                        let _ = t.reset();
                    }
                    None => {
                        let _ = t.write_str(s.as_slice());
                    }
                }
            }
            let _ = t.flush();
        }
    }
}

fn print_result(name: &str, result: ProgramResult<SolveResult<String>>, enable_time_color: bool) {
    let mut items = vec![];
    match result {
        Ok(r) => {
            items.push(normal("["));
            if r.is_ok {
                items.push(ok("OK"));
            } else {
                items.push(ng("NG"));
                os::set_exit_status(1);
            }
            items.push(normal("] "));
            items.push(normal(format!("{:5} ", name)));
            items.push(normal(format!("{:20} ", r.answer)));
            let (sec, nsec) = r.time.div_rem(&NSEC_PER_SEC);
            let time_str = format!("{:3}.{:09}", sec, nsec);
            if !enable_time_color || r.time < NSEC_WARN_LIMIT {
                items.push(normal(time_str));
            } else if r.time < NSEC_NG_LIMIT {
                items.push(warn(time_str));
            } else {
                items.push(ng(time_str));
            }
        }
        Err(e) => {
            items.push(normal("["));
            items.push(ng("!!"));
            items.push(normal("] "));
            items.push(normal(format!("{:5} ", name)));
            items.push(normal(format!("{}", e)));
            os::set_exit_status(1);
        }
    }
    items.push(normal("\n"));
    print_items(items[]);

    fn normal<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (None, s.into_maybe_owned())
    }
    fn ok<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (Some(COLOR_OK), s.into_maybe_owned())
    }
    fn warn<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (Some(COLOR_WARN), s.into_maybe_owned())
    }
    fn ng<'a, T: IntoMaybeOwned<'a>>(s: T) -> OutputPair<'a> {
        (Some(COLOR_NG), s.into_maybe_owned())
    }
}

fn run() -> ProgramResult<()> {
    let dir_path = try!(exe_path()).dir_path();

    let mut is_ok = true;
    let mut num_prob = 0;
    let mut total_time = 0;
    for path in try!(problem_paths(dir_path)) {
        let result = run_problem(&path);
        if let Ok(ref r) = result {
            num_prob   += 1;
            total_time += r.time;
            is_ok &= r.is_ok;
        } else {
            is_ok = false;
        }
        print_result(format!("{}", path.filename_display())[], result, true);
    }

    if num_prob > 0 {
        let r = SolveResult {
            time: total_time / num_prob,
            answer: "".to_string(),
            is_ok: is_ok
        };
        print_result("AVG", Ok(r), true);

        let r = SolveResult {
            time: total_time,
            answer: "".to_string(),
            is_ok: is_ok
        };
        print_result("TOTAL", Ok(r), false);
    }

    Ok(())
}

fn main() {
    match run() {
        Ok(()) => {}
        Err(e) => {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            os::set_exit_status(255);
        }
    }
}
<|endoftext|>