<commit_before>extern crate rosc;

#[cfg(feature = "std")]
use rosc::address::Matcher;

#[cfg(feature = "std")]
#[test]
fn test_matcher() {
    let mut matcher;

    // Regular address using only alphanumeric parts
    matcher = Matcher::new("/oscillator/1/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/1/frequency").expect("Should match");
    matcher.match_address("/oscillator/1/phase").expect_err("Should not match");
    matcher.match_address("/oscillator/1/frequencyfoo").expect_err("Should not match");
    matcher.match_address("/prefix/oscillator/1/frequency").expect_err("Should not match");

    // Choice
    matcher = Matcher::new("/foo{bar,baz}").expect("Should be valid");
    matcher.match_address("/foobar").expect("Should match");
    matcher.match_address("/foobaz").expect("Should match");

    matcher = Matcher::new("/foo{bar,baz,tron}").expect("Should be valid");
    matcher.match_address("/footron").expect("Should match");

    // Character class
    // Character classes are sets or ranges of characters to match.
    // e.g. [a-z] will match any lower case alphabetic character. [abcd] will match the characters abcd.
    // They can be negated with '!', e.g. [!0-9] will match all characters except 0-9
    // Basic example
    matcher = Matcher::new("/oscillator/[0-9]").expect("Should be valid");
    matcher.match_address("/oscillator/0").expect("Should match");  // Beginning of range included
    matcher.match_address("/oscillator/6").expect("Should match");  // Middle of range
    matcher.match_address("/oscillator/9").expect("Should match");  // Last member of range included

    // Inverted order should work too
    matcher = Matcher::new("/oscillator/[9-0]").expect("Should be valid");
    matcher.match_address("/oscillator/0").expect("Should match");
    matcher.match_address("/oscillator/6").expect("Should match");
    matcher.match_address("/oscillator/9").expect("Should match");

    // Multiple ranges
    matcher = Matcher::new("/oscillator/[a-zA-Z0-9]").expect("Should be valid");
    matcher.match_address("/oscillator/0").expect("Should match");
    matcher.match_address("/oscillator/a").expect("Should match");
    matcher.match_address("/oscillator/A").expect("Should match");

    // Negated range
    matcher = Matcher::new("/oscillator/[!0-9]").expect("Should be valid");
    matcher.match_address("/oscillator/1").expect_err("Should not match");
    matcher.match_address("/oscillator/a").expect("Should match");

    // Extra exclamation points must be entirely ignored
    matcher = Matcher::new("/oscillator/[!0-9!a-z!]").expect("Should be valid");
    matcher.match_address("/oscillator/A").expect("Should match");

    // Trailing dash has no special meaning
    matcher = Matcher::new("/oscillator/[abcd-]").expect("Should be valid");
    matcher.match_address("/oscillator/a").expect("Should match");
    matcher.match_address("/oscillator/-").expect("Should match");

    // Single wildcard
    // A single wildcard '?' matches excatly one alphanumeric character
    matcher = Matcher::new("/oscillator/?/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/1/frequency").expect("Should match");
    matcher.match_address("/oscillator/F/frequency").expect("Should match");
    matcher.match_address("/oscillator//frequency").expect_err("Should not match");
    matcher.match_address("/oscillator/10/frequency").expect_err("Should not match");

    // Test if two consecutive wildcards match
    matcher = Matcher::new("/oscillator/??/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/10/frequency").expect("Should match");
    matcher.match_address("/oscillator/1/frequency").expect_err("Should not match");

    // Test if it works if it is surrounded by non-wildcards
    matcher = Matcher::new("/oscillator/prefixed?postfixed/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/prefixed1postfixed/frequency").expect("Should match");
    matcher.match_address("/oscillator/prefixedpostfixed/frequency").expect_err("Should not match");

    // Wildcard
    // Wildcards '*' match zero or more alphanumeric characters. The implementation is greedy,
    // meaning it will match the longest possible sequence
    matcher = Matcher::new("/oscillator/*/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/anything123/frequency").expect("Should match");
    // Test that wildcard doesn't cross part boundary
    matcher.match_address("/oscillator/extra/part/frequency").expect_err("Should not match");
    matcher.match_address("/oscillator//frequency").expect_err("Should not match");

    // Test greediness
    matcher = Matcher::new("/oscillator/*bar/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobar/frequency").expect("Should match");
    matcher.match_address("/oscillator/foobarbar/frequency").expect("Should match");

    // Minimum length of 2
    matcher = Matcher::new("/oscillator/*??/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobar/frequency").expect("Should match");
    matcher.match_address("/oscillator/f/frequency").expect_err("Should not match");

    // Minimum length of 2 and another component follows
    matcher = Matcher::new("/oscillator/*??baz/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobarbaz/frequency").expect("Should match");
    matcher.match_address("/oscillator/fbaz/frequency").expect_err("Should not match");

    // Mix with character class
    matcher = Matcher::new("/oscillator/*[a-d]/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/a/frequency").expect("Should match");
    matcher.match_address("/oscillator/fooa/frequency").expect("Should match");
    matcher.match_address("/oscillator/foox/frequency").expect_err("Should not match");

    // Mix with choice
    matcher = Matcher::new("/oscillator/*{bar,baz}/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobar/frequency").expect("Should match");
    matcher.match_address("/oscillator/baz/frequency").expect("Should match");
    matcher.match_address("/oscillator/something/frequency").expect_err("Should not match");

    // Check for allowed literal characters
    matcher = Matcher::new("/!\"$%&'()+-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~").expect("Should be valid");
    matcher.match_address("/!\"$%&'()+-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~").expect("Should match");
}

#[cfg(feature = "std")]
#[test]
fn test_bad_address_pattern() {
    let expected_err = "bad OSC address pattern: bad address pattern";
    assert_eq!(Matcher::new("").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("/").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("//empty/parts/").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("////").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("/{unclosed,alternative").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("/unclosed/[range-").unwrap_err().to_string(), expected_err);
}

#[cfg(feature = "std")]
#[test]
fn test_bad_address() {
    let matcher = Matcher::new("/does-not-matter").expect("Matcher::new");
    let expected_err = "bad OSC address: bad address";
    assert_eq!(matcher.match_address("").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/wildcards?").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/wildcards*").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/ranges[a-z]").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/ranges[!a-z]").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/{contains,alternative}").unwrap_err().to_string(), expected_err);
}
<commit_msg>Remove extra '/' character<commit_after>extern crate rosc;

#[cfg(feature = "std")]
use rosc::address::Matcher;

#[cfg(feature = "std")]
#[test]
fn test_matcher() {
    let mut matcher;

    // Regular address using only alphanumeric parts
    matcher = Matcher::new("/oscillator/1/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/1/frequency").expect("Should match");
    matcher.match_address("/oscillator/1/phase").expect_err("Should not match");
    matcher.match_address("/oscillator/1/frequencyfoo").expect_err("Should not match");
    matcher.match_address("/prefix/oscillator/1/frequency").expect_err("Should not match");

    // Choice
    matcher = Matcher::new("/foo{bar,baz}").expect("Should be valid");
    matcher.match_address("/foobar").expect("Should match");
    matcher.match_address("/foobaz").expect("Should match");

    matcher = Matcher::new("/foo{bar,baz,tron}").expect("Should be valid");
    matcher.match_address("/footron").expect("Should match");

    // Character class
    // Character classes are sets or ranges of characters to match.
    // e.g. [a-z] will match any lower case alphabetic character. [abcd] will match the characters abcd.
    // They can be negated with '!', e.g. [!0-9] will match all characters except 0-9
    // Basic example
    matcher = Matcher::new("/oscillator/[0-9]").expect("Should be valid");
    matcher.match_address("/oscillator/0").expect("Should match");  // Beginning of range included
    matcher.match_address("/oscillator/6").expect("Should match");  // Middle of range
    matcher.match_address("/oscillator/9").expect("Should match");  // Last member of range included

    // Inverted order should work too
    matcher = Matcher::new("/oscillator/[9-0]").expect("Should be valid");
    matcher.match_address("/oscillator/0").expect("Should match");
    matcher.match_address("/oscillator/6").expect("Should match");
    matcher.match_address("/oscillator/9").expect("Should match");

    // Multiple ranges
    matcher = Matcher::new("/oscillator/[a-zA-Z0-9]").expect("Should be valid");
    matcher.match_address("/oscillator/0").expect("Should match");
    matcher.match_address("/oscillator/a").expect("Should match");
    matcher.match_address("/oscillator/A").expect("Should match");

    // Negated range
    matcher = Matcher::new("/oscillator/[!0-9]").expect("Should be valid");
    matcher.match_address("/oscillator/1").expect_err("Should not match");
    matcher.match_address("/oscillator/a").expect("Should match");

    // Extra exclamation points must be entirely ignored
    matcher = Matcher::new("/oscillator/[!0-9!a-z!]").expect("Should be valid");
    matcher.match_address("/oscillator/A").expect("Should match");

    // Trailing dash has no special meaning
    matcher = Matcher::new("/oscillator/[abcd-]").expect("Should be valid");
    matcher.match_address("/oscillator/a").expect("Should match");
    matcher.match_address("/oscillator/-").expect("Should match");

    // Single wildcard
    // A single wildcard '?' matches excatly one alphanumeric character
    matcher = Matcher::new("/oscillator/?/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/1/frequency").expect("Should match");
    matcher.match_address("/oscillator/F/frequency").expect("Should match");
    matcher.match_address("/oscillator//frequency").expect_err("Should not match");
    matcher.match_address("/oscillator/10/frequency").expect_err("Should not match");

    // Test if two consecutive wildcards match
    matcher = Matcher::new("/oscillator/??/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/10/frequency").expect("Should match");
    matcher.match_address("/oscillator/1/frequency").expect_err("Should not match");

    // Test if it works if it is surrounded by non-wildcards
    matcher = Matcher::new("/oscillator/prefixed?postfixed/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/prefixed1postfixed/frequency").expect("Should match");
    matcher.match_address("/oscillator/prefixedpostfixed/frequency").expect_err("Should not match");

    // Wildcard
    // Wildcards '*' match zero or more alphanumeric characters. The implementation is greedy,
    // meaning it will match the longest possible sequence
    matcher = Matcher::new("/oscillator/*/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/anything123/frequency").expect("Should match");
    // Test that wildcard doesn't cross part boundary
    matcher.match_address("/oscillator/extra/part/frequency").expect_err("Should not match");
    matcher.match_address("/oscillator//frequency").expect_err("Should not match");

    // Test greediness
    matcher = Matcher::new("/oscillator/*bar/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobar/frequency").expect("Should match");
    matcher.match_address("/oscillator/foobarbar/frequency").expect("Should match");

    // Minimum length of 2
    matcher = Matcher::new("/oscillator/*??/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobar/frequency").expect("Should match");
    matcher.match_address("/oscillator/f/frequency").expect_err("Should not match");

    // Minimum length of 2 and another component follows
    matcher = Matcher::new("/oscillator/*??baz/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobarbaz/frequency").expect("Should match");
    matcher.match_address("/oscillator/fbaz/frequency").expect_err("Should not match");

    // Mix with character class
    matcher = Matcher::new("/oscillator/*[a-d]/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/a/frequency").expect("Should match");
    matcher.match_address("/oscillator/fooa/frequency").expect("Should match");
    matcher.match_address("/oscillator/foox/frequency").expect_err("Should not match");

    // Mix with choice
    matcher = Matcher::new("/oscillator/*{bar,baz}/frequency").expect("Should be valid");
    matcher.match_address("/oscillator/foobar/frequency").expect("Should match");
    matcher.match_address("/oscillator/baz/frequency").expect("Should match");
    matcher.match_address("/oscillator/something/frequency").expect_err("Should not match");

    // Check for allowed literal characters
    matcher = Matcher::new("/!\"$%&'()+-.0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~").expect("Should be valid");
    matcher.match_address("/!\"$%&'()+-.0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~").expect("Should match");
}

#[cfg(feature = "std")]
#[test]
fn test_bad_address_pattern() {
    let expected_err = "bad OSC address pattern: bad address pattern";
    assert_eq!(Matcher::new("").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("/").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("//empty/parts/").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("////").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("/{unclosed,alternative").unwrap_err().to_string(), expected_err);
    assert_eq!(Matcher::new("/unclosed/[range-").unwrap_err().to_string(), expected_err);
}

#[cfg(feature = "std")]
#[test]
fn test_bad_address() {
    let matcher = Matcher::new("/does-not-matter").expect("Matcher::new");
    let expected_err = "bad OSC address: bad address";
    assert_eq!(matcher.match_address("").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/wildcards?").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/wildcards*").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/ranges[a-z]").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/contains/ranges[!a-z]").unwrap_err().to_string(), expected_err);
    assert_eq!(matcher.match_address("/{contains,alternative}").unwrap_err().to_string(), expected_err);
}
<|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.

//! Some lints that are built in to the compiler.
//!
//! These are the built-in lints that are emitted direct in the main
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.

use lint::{LintPass, LateLintPass, LintArray};

declare_lint! {
    pub CONST_ERR,
    Warn,
    "constant evaluation detected erroneous expression"
}

declare_lint! {
    pub UNUSED_IMPORTS,
    Warn,
    "imports that are never used"
}

declare_lint! {
    pub UNUSED_EXTERN_CRATES,
    Allow,
    "extern crates that are never used"
}

declare_lint! {
    pub UNUSED_QUALIFICATIONS,
    Allow,
    "detects unnecessarily qualified names"
}

declare_lint! {
    pub UNKNOWN_LINTS,
    Warn,
    "unrecognized lint attribute"
}

declare_lint! {
    pub UNUSED_VARIABLES,
    Warn,
    "detect variables which are not used in any way"
}

declare_lint! {
    pub UNUSED_ASSIGNMENTS,
    Warn,
    "detect assignments that will never be read"
}

declare_lint! {
    pub DEAD_CODE,
    Warn,
    "detect unused, unexported items"
}

declare_lint! {
    pub UNREACHABLE_CODE,
    Warn,
    "detects unreachable code paths"
}

declare_lint! {
    pub UNREACHABLE_PATTERNS,
    Warn,
    "detects unreachable patterns"
}

declare_lint! {
    pub UNUSED_MACROS,
    Warn,
    "detects macros that were not used"
}

declare_lint! {
    pub WARNINGS,
    Warn,
    "mass-change the level for lints which produce warnings"
}

declare_lint! {
    pub UNUSED_FEATURES,
    Warn,
    "unused or unknown features found in crate-level #[feature] directives"
}

declare_lint! {
    pub STABLE_FEATURES,
    Warn,
    "stable features found in #[feature] directive"
}

declare_lint! {
    pub UNKNOWN_CRATE_TYPES,
    Deny,
    "unknown crate type found in #[crate_type] directive"
}

declare_lint! {
    pub FAT_PTR_TRANSMUTES,
    Allow,
    "detects transmutes of fat pointers"
}

declare_lint! {
    pub TRIVIAL_CASTS,
    Allow,
    "detects trivial casts which could be removed"
}

declare_lint! {
    pub TRIVIAL_NUMERIC_CASTS,
    Allow,
    "detects trivial casts of numeric types which could be removed"
}

declare_lint! {
    pub PRIVATE_IN_PUBLIC,
    Warn,
    "detect private items in public interfaces not caught by the old implementation"
}

declare_lint! {
    pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
    Deny,
    "detect public reexports of private extern crates"
}

declare_lint! {
    pub INVALID_TYPE_PARAM_DEFAULT,
    Deny,
    "type parameter default erroneously allowed in invalid location"
}

declare_lint! {
    pub RENAMED_AND_REMOVED_LINTS,
    Warn,
    "lints that have been renamed or removed"
}

declare_lint! {
    pub RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
    Deny,
    "attempt to resolve a trait on an expression whose type cannot be inferred but which \
     currently defaults to ()"
}

declare_lint! {
    pub SAFE_EXTERN_STATICS,
    Deny,
    "safe access to extern statics was erroneously allowed"
}

declare_lint! {
    pub PATTERNS_IN_FNS_WITHOUT_BODY,
    Warn,
    "patterns in functions without body were erroneously allowed"
}

declare_lint! {
    pub EXTRA_REQUIREMENT_IN_IMPL,
    Deny,
    "detects extra requirements in impls that were erroneously allowed"
}

declare_lint! {
    pub LEGACY_DIRECTORY_OWNERSHIP,
    Deny,
    "non-inline, non-`#[path]` modules (e.g. `mod foo;`) were erroneously allowed in some files \
     not named `mod.rs`"
}

declare_lint! {
    pub LEGACY_IMPORTS,
    Deny,
    "detects names that resolve to ambiguous glob imports with RFC 1560"
}

declare_lint! {
    pub LEGACY_CONSTRUCTOR_VISIBILITY,
    Deny,
    "detects use of struct constructors that would be invisible with new visibility rules"
}

declare_lint! {
    pub MISSING_FRAGMENT_SPECIFIER,
    Deny,
    "detects missing fragment specifiers in unused `macro_rules!` patterns"
}

declare_lint! {
    pub PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
    Deny,
    "detects parenthesized generic parameters in type and module names"
}

declare_lint! {
    pub LATE_BOUND_LIFETIME_ARGUMENTS,
    Warn,
    "detects generic lifetime arguments in path segments with late bound lifetime parameters"
}

declare_lint! {
    pub DEPRECATED,
    Warn,
    "detects use of deprecated items"
}

/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
pub struct HardwiredLints;

impl LintPass for HardwiredLints {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            UNUSED_IMPORTS,
            UNUSED_EXTERN_CRATES,
            UNUSED_QUALIFICATIONS,
            UNKNOWN_LINTS,
            UNUSED_VARIABLES,
            UNUSED_ASSIGNMENTS,
            DEAD_CODE,
            UNREACHABLE_CODE,
            UNREACHABLE_PATTERNS,
            UNUSED_MACROS,
            WARNINGS,
            UNUSED_FEATURES,
            STABLE_FEATURES,
            UNKNOWN_CRATE_TYPES,
            FAT_PTR_TRANSMUTES,
            TRIVIAL_CASTS,
            TRIVIAL_NUMERIC_CASTS,
            PRIVATE_IN_PUBLIC,
            PUB_USE_OF_PRIVATE_EXTERN_CRATE,
            INVALID_TYPE_PARAM_DEFAULT,
            CONST_ERR,
            RENAMED_AND_REMOVED_LINTS,
            RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
            SAFE_EXTERN_STATICS,
            PATTERNS_IN_FNS_WITHOUT_BODY,
            EXTRA_REQUIREMENT_IN_IMPL,
            LEGACY_DIRECTORY_OWNERSHIP,
            LEGACY_IMPORTS,
            LEGACY_CONSTRUCTOR_VISIBILITY,
            MISSING_FRAGMENT_SPECIFIER,
            PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
            LATE_BOUND_LIFETIME_ARGUMENTS,
            DEPRECATED
        )
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}
<commit_msg>Make unused-extern-crate warn-by-default<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.

//! Some lints that are built in to the compiler.
//!
//! These are the built-in lints that are emitted direct in the main
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.

use lint::{LintPass, LateLintPass, LintArray};

declare_lint! {
    pub CONST_ERR,
    Warn,
    "constant evaluation detected erroneous expression"
}

declare_lint! {
    pub UNUSED_IMPORTS,
    Warn,
    "imports that are never used"
}

declare_lint! {
    pub UNUSED_EXTERN_CRATES,
    Warn,
    "extern crates that are never used"
}

declare_lint! {
    pub UNUSED_QUALIFICATIONS,
    Allow,
    "detects unnecessarily qualified names"
}

declare_lint! {
    pub UNKNOWN_LINTS,
    Warn,
    "unrecognized lint attribute"
}

declare_lint! {
    pub UNUSED_VARIABLES,
    Warn,
    "detect variables which are not used in any way"
}

declare_lint! {
    pub UNUSED_ASSIGNMENTS,
    Warn,
    "detect assignments that will never be read"
}

declare_lint! {
    pub DEAD_CODE,
    Warn,
    "detect unused, unexported items"
}

declare_lint! {
    pub UNREACHABLE_CODE,
    Warn,
    "detects unreachable code paths"
}

declare_lint! {
    pub UNREACHABLE_PATTERNS,
    Warn,
    "detects unreachable patterns"
}

declare_lint! {
    pub UNUSED_MACROS,
    Warn,
    "detects macros that were not used"
}

declare_lint! {
    pub WARNINGS,
    Warn,
    "mass-change the level for lints which produce warnings"
}

declare_lint! {
    pub UNUSED_FEATURES,
    Warn,
    "unused or unknown features found in crate-level #[feature] directives"
}

declare_lint! {
    pub STABLE_FEATURES,
    Warn,
    "stable features found in #[feature] directive"
}

declare_lint! {
    pub UNKNOWN_CRATE_TYPES,
    Deny,
    "unknown crate type found in #[crate_type] directive"
}

declare_lint! {
    pub FAT_PTR_TRANSMUTES,
    Allow,
    "detects transmutes of fat pointers"
}

declare_lint! {
    pub TRIVIAL_CASTS,
    Allow,
    "detects trivial casts which could be removed"
}

declare_lint! {
    pub TRIVIAL_NUMERIC_CASTS,
    Allow,
    "detects trivial casts of numeric types which could be removed"
}

declare_lint! {
    pub PRIVATE_IN_PUBLIC,
    Warn,
    "detect private items in public interfaces not caught by the old implementation"
}

declare_lint! {
    pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
    Deny,
    "detect public reexports of private extern crates"
}

declare_lint! {
    pub INVALID_TYPE_PARAM_DEFAULT,
    Deny,
    "type parameter default erroneously allowed in invalid location"
}

declare_lint! {
    pub RENAMED_AND_REMOVED_LINTS,
    Warn,
    "lints that have been renamed or removed"
}

declare_lint! {
    pub RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
    Deny,
    "attempt to resolve a trait on an expression whose type cannot be inferred but which \
     currently defaults to ()"
}

declare_lint! {
    pub SAFE_EXTERN_STATICS,
    Deny,
    "safe access to extern statics was erroneously allowed"
}

declare_lint! {
    pub PATTERNS_IN_FNS_WITHOUT_BODY,
    Warn,
    "patterns in functions without body were erroneously allowed"
}

declare_lint! {
    pub EXTRA_REQUIREMENT_IN_IMPL,
    Deny,
    "detects extra requirements in impls that were erroneously allowed"
}

declare_lint! {
    pub LEGACY_DIRECTORY_OWNERSHIP,
    Deny,
    "non-inline, non-`#[path]` modules (e.g. `mod foo;`) were erroneously allowed in some files \
     not named `mod.rs`"
}

declare_lint! {
    pub LEGACY_IMPORTS,
    Deny,
    "detects names that resolve to ambiguous glob imports with RFC 1560"
}

declare_lint! {
    pub LEGACY_CONSTRUCTOR_VISIBILITY,
    Deny,
    "detects use of struct constructors that would be invisible with new visibility rules"
}

declare_lint! {
    pub MISSING_FRAGMENT_SPECIFIER,
    Deny,
    "detects missing fragment specifiers in unused `macro_rules!` patterns"
}

declare_lint! {
    pub PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
    Deny,
    "detects parenthesized generic parameters in type and module names"
}

declare_lint! {
    pub LATE_BOUND_LIFETIME_ARGUMENTS,
    Warn,
    "detects generic lifetime arguments in path segments with late bound lifetime parameters"
}

declare_lint! {
    pub DEPRECATED,
    Warn,
    "detects use of deprecated items"
}

/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
pub struct HardwiredLints;

impl LintPass for HardwiredLints {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            UNUSED_IMPORTS,
            UNUSED_EXTERN_CRATES,
            UNUSED_QUALIFICATIONS,
            UNKNOWN_LINTS,
            UNUSED_VARIABLES,
            UNUSED_ASSIGNMENTS,
            DEAD_CODE,
            UNREACHABLE_CODE,
            UNREACHABLE_PATTERNS,
            UNUSED_MACROS,
            WARNINGS,
            UNUSED_FEATURES,
            STABLE_FEATURES,
            UNKNOWN_CRATE_TYPES,
            FAT_PTR_TRANSMUTES,
            TRIVIAL_CASTS,
            TRIVIAL_NUMERIC_CASTS,
            PRIVATE_IN_PUBLIC,
            PUB_USE_OF_PRIVATE_EXTERN_CRATE,
            INVALID_TYPE_PARAM_DEFAULT,
            CONST_ERR,
            RENAMED_AND_REMOVED_LINTS,
            RESOLVE_TRAIT_ON_DEFAULTED_UNIT,
            SAFE_EXTERN_STATICS,
            PATTERNS_IN_FNS_WITHOUT_BODY,
            EXTRA_REQUIREMENT_IN_IMPL,
            LEGACY_DIRECTORY_OWNERSHIP,
            LEGACY_IMPORTS,
            LEGACY_CONSTRUCTOR_VISIBILITY,
            MISSING_FRAGMENT_SPECIFIER,
            PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
            LATE_BOUND_LIFETIME_ARGUMENTS,
            DEPRECATED
        )
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}
<|endoftext|>


<commit_before>// Code by Johannes Schickling <schickling.j@gmail.com>,
// https://github.com/schickling/rust-examples/tree/master/snake-ncurses
// minor revisions accoring to changed rust-spedicifactions were made in
// order to successfully compile the code, game.rs and main.rs were
// merged into specialcrate.rs. Code was published under MIT license.

extern crate rand;

use self::rand::Rng;

pub enum GameError { Wall, Suicide }

#[derive(PartialEq, Copy)]
pub struct Vector {
    pub x: i32,
    pub y: i32,
}

impl Vector {
    fn next (&self, dir: Direction) -> Vector {
        let (dx, dy) = match dir {
            Direction::Up => (0, -1),
            Direction::Down => (0, 1),
            Direction::Left => (-1, 0),
            Direction::Right => (1, 0),
        };

        Vector {
            x: self.x + dx,
            y: self.y + dy,
        }
    }

    fn random (bounds: Vector) -> Vector {
        let mut rng = rand::thread_rng();
        Vector {
            x: rng.gen_range::<>(0, bounds.x),
            y: rng.gen_range::<>(0, bounds.y),
        }
    }
}

impl Clone for Vector {

    fn clone(&self) -> Self {
        Vector { x : self.x, y : self.y}
    }

    fn clone_from(&mut self, source: &Self) {
        self.x = source.x;
        self.y = source.y;
    }
}

pub struct Board {
    bounds: Vector,
    snake: Snake,
    bullet: Vector,
}

impl Board {

    pub fn new (bounds: Vector) -> Board {
        Board {
            bounds: bounds,
            snake: Snake::new(Vector { x: bounds.x / 2, y: bounds.y / 2 }),
            bullet: Vector::random(bounds),
        }
    }

    pub fn set_direction (&mut self, dir: Direction) {
        self.snake.direction = dir;
    }

    pub fn tick (&mut self) -> Result<(), GameError> {

        self.snake.step();

        if self.snake.eats_bullet(self.bullet) {
            self.snake.grow();
            self.bullet = Vector::random(self.bounds);
        }

        if self.snake.hits_wall(self.bounds) {
            Err(GameError::Wall)
        } else if self.snake.hits_itself() {
            Err(GameError::Suicide)
        } else {
            Ok(())
        }
    }

    pub fn get_snake_vectors (&self) -> &[Vector] {
        let ref v = self.snake.segments;
        &v[..]
    }

    pub fn get_bullet_vector (&self) -> &Vector {
        &self.bullet
    }
}

struct Snake {
    segments: Vec<Vector>,
    direction: Direction,
    popped_segment: Vector,
}

impl Snake {

    fn new (pos: Vector) -> Snake {
        Snake {
            segments: vec!(pos),
            direction: Direction::Up,
            popped_segment: Vector { x: 0, y: 0 }
        }
    }

    fn step (&mut self) {
        let new_head = self.segments[0].next(self.direction);
        self.segments.insert(0, new_head);
        self.popped_segment = self.segments.pop().unwrap();
    }

    fn hits_wall (&self, bounds: Vector) -> bool {
        let head = self.segments[0];
        head.x < 0 || head.x == bounds.x || head.y < 0 || head.y == bounds.y
    }

    fn hits_itself (&self) -> bool {
        self.segments.iter().skip(1).any(|s| *s == self.segments[0] )
    }

    fn grow (&mut self) {
        self.segments.push(self.popped_segment);
    }

    fn eats_bullet (&self, bullet: Vector) -> bool {
        self.segments[0] == bullet
    }
}

// This was the code in main.rs
extern crate ncurses;

use std::thread::sleep_ms as sleep;
use self::ncurses::*;

pub fn snake()
{
    initscr();
    cbreak(); // enable <Ctrl+C> to kill game
    noecho(); // don't show input
    keypad(stdscr, true); // make keys work
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    timeout(100); // tick speed

    let mut bounds = Vector { x: 0, y: 0 };
    getmaxyx(stdscr, &mut bounds.y, &mut bounds.x);

    let mut board = Board::new(bounds);

    let mut direction = Direction::Up;

    loop {
        erase();

        {
            let bullet = board.get_bullet_vector();
            draw_char(bullet, 'o');
        }

        {
            let segments = board.get_snake_vectors();
            for segment in segments.iter() {
                draw_char(segment, '#');
            }
        }

        direction = get_new_direction(direction);
        board.set_direction(direction);

        match board.tick() {
            Err(err) => {
                match err {
                    GameError::Wall => show_text("You hit the wall, stupid."),
                    GameError::Suicide => show_text("Damn it. Stop eating yourself."),
                }
                //let two_secs = Duration::new(2, 0);
                sleep(2000);
                break;
            },
            Ok(_) => (),
        };
    }
    endwin();
}

fn draw_char (pos: &Vector, c: char) {
    mvaddch(pos.y, pos.x, c as u64);
}

fn get_new_direction (prev_dir: Direction) -> Direction {
    match getch() {
        KEY_UP if prev_dir != Direction::Down => Direction::Up,
        KEY_DOWN if prev_dir != Direction::Up => Direction::Down,
        KEY_LEFT if prev_dir != Direction::Right => Direction::Left,
        KEY_RIGHT if prev_dir != Direction::Left => Direction::Right,
        _ => prev_dir,
    }
}

fn show_text (s: &str) {
    erase();
    addstr(s);
    refresh();
}

// Below is space invaders code

#[derive(PartialEq,Copy,Clone)]
pub enum Direction { Up, Down, Left, Right }

pub enum GameStatus { Win, Running, Dead }

pub struct Game {
    bounds: Vector,
    invaders: Vec<Invader>,
    player: Player,
    bullets: Vec<Bullet>,
}

impl Game {

    pub fn new (bounds: Vector) -> Game {

        let mut invaders = vec!();
        //for i in range(0i32, bounds.x / 3) {
        for i in 0i32..(bounds.x / 3) {
            invaders.push(Invader::new( Vector { x: 2 * i, y: 0 }));
        }

        Game {
            bounds: bounds,
            invaders: invaders,
            player: Player::new(Vector { x: bounds.x / 2, y: bounds.y - 1 }),
            bullets: vec!(),
        }
    }

    pub fn tick (&mut self) -> GameStatus {

        for invader in self.invaders.iter_mut() {
            match invader.give_chance_to_fire() {
                Some(bullet) => self.bullets.push(bullet),
                None => (),
            };
            invader.tick(self.bounds);
        }

        for bullet in self.bullets.iter_mut() {
            bullet.tick(self.bounds);

            self.invaders.retain(|i| !bullet.check_collision(i.position));

            if bullet.check_collision(self.player.position) {
                return GameStatus::Dead;
            }
        }

        if self.invaders.is_empty() {
            GameStatus::Win
        } else {
            GameStatus::Running
        }
    }

    pub fn shift (&mut self, dir: Direction) {
        self.player.shift(dir, self.bounds);
    }

    pub fn fire (&mut self) {
        self.bullets.push(self.player.fire());
    }

    pub fn get_player_vector (&self) -> &Vector {
        &self.player.position
    }

    pub fn get_invader_vectors (&self) -> Vec<Vector> {
        self.invaders.iter().map(|i| i.position).collect()
    }

    pub fn get_bullet_vectors (&self) -> Vec<Vector> {
        self.bullets.iter().map(|b| b.position).collect()
    }
}

struct Invader {
    position: Vector,
    direction: Direction,
}

impl Invader {

    fn new (pos: Vector) -> Invader {
        Invader {
            position: pos,
            direction: Direction::Left,
        }
    }

    fn tick (&mut self, bounds: Vector) {
        let x = &mut self.position.x;
        self.direction = match self.direction {
            Direction::Left if *x < 0 => Direction::Right,
            Direction::Right if *x == bounds.x => Direction::Left,
            _ => self.direction.clone()
        };
        match self.direction {
            Direction::Left => *x = *x - 1,
            Direction::Right => *x = *x + 1,
            _ => (),
        };
    }

    fn give_chance_to_fire (&self) -> Option<Bullet> {
        let mut rng = rand::thread_rng();
        let temp: f32 = rng.gen_range(0.0, 1.0);
        if temp > 0.996 {
            Some(Bullet::new(Vector { x: self.position.x, y: self.position.y + 1 }, Direction::Down))
        } else {
            None
        }
    }
}

struct Player {
    position: Vector,
}

impl Player {

    fn new (pos: Vector) -> Player {
        Player { position: pos }
    }

    fn shift (&mut self, dir: Direction, bounds: Vector) {
        let x = &mut self.position.x;
        match dir {
            Direction::Left if *x > 0 => *x = *x - 1,
            Direction::Right if *x < bounds.x - 1 => *x = *x + 1,
            _ => (),
        }
    }

    fn fire (&self) -> Bullet {
        Bullet::new(Vector { x: self.position.x, y: self.position.y - 1 }, Direction::Up)
    }
}

struct Bullet {
    position: Vector,
    direction: Direction,
}

impl Bullet {

    fn new (pos: Vector, dir: Direction) -> Bullet {
        Bullet {
            position: pos,
            direction: dir,
        }
    }

    fn tick (&mut self, bounds: Vector) {
        match self.direction {
            Direction::Up => self.position.y -= 1,
            Direction::Down => self.position.y += 1,
            _ => (),
        };
        if self.position.y < 0 || self.position.y == bounds.y {
            drop(self);
        }
    }

    fn check_collision (&self, other: Vector) -> bool {
        self.position == other
    }
}

// blow is code from main.rs
pub fn space_invaders()
{
    initscr();
    cbreak(); // enable <Ctrl+C> to kill game
    noecho(); // don't show input
    keypad(stdscr, true); // make keys work
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    timeout(1);

    let mut bounds = Vector { x: 0, y: 0};
    getmaxyx(stdscr, &mut bounds.y, &mut bounds.x);

    let mut game = Box::new(Game::new(bounds));

    // TODO rewrite async
    let mut tick_count = 0u8;

    loop {
        tick_count += 1;
        tick_count %= 30;

        erase();

        {
            let player = game.get_player_vector();
            draw_char(player, 'X');
        }

        {
            let invaders = game.get_invader_vectors();
            for invader in invaders.iter() {
                draw_char(invader, '#');
            }
        }

        {
            let bullets = game.get_bullet_vectors();
            for bullet in bullets.iter() {
                draw_char(bullet, '.');
            }
        }

        match getch() {
            KEY_LEFT => game.shift(Direction::Left),
            KEY_RIGHT => game.shift(Direction::Right),
            KEY_UP => game.fire(),
            _ => (),
        }

        if tick_count == 0 {
            match game.tick() {
                GameStatus::Dead => {
                    show_text("Puny human!");
                    sleep(2000);
                    break;
                },
                GameStatus::Win => {
                    show_text("Garglargl");
                    sleep(2000);
                    break;
                },
                GameStatus::Running => (),
            };
        }
    }

    endwin();
}
<commit_msg>Style improvement #2<commit_after>// Code by Johannes Schickling <schickling.j@gmail.com>,
// https://github.com/schickling/rust-examples/tree/master/snake-ncurses
// minor revisions accoring to changed rust-spedicifactions were made in
// order to successfully compile the code, game.rs and main.rs were
// merged into specialcrate.rs. Code was published under MIT license.

extern crate rand;

use self::rand::Rng;

pub enum GameError { Wall, Suicide }

#[derive(PartialEq, Copy)]
pub struct Vector {
    pub x: i32,
    pub y: i32,
}

impl Vector {
    fn next (&self, dir: Direction) -> Vector {
        let (dx, dy) = match dir {
            Direction::Up => (0, -1),
            Direction::Down => (0, 1),
            Direction::Left => (-1, 0),
            Direction::Right => (1, 0),
        };

        Vector {
            x: self.x + dx,
            y: self.y + dy,
        }
    }

    fn random (bounds: Vector) -> Vector {
        let mut rng = rand::thread_rng();
        Vector {
            x: rng.gen_range::<>(0, bounds.x),
            y: rng.gen_range::<>(0, bounds.y),
        }
    }
}

impl Clone for Vector {

    fn clone(&self) -> Self {
        Vector { x : self.x, y : self.y}
    }

    fn clone_from(&mut self, source: &Self) {
        self.x = source.x;
        self.y = source.y;
    }
}

pub struct Board {
    bounds: Vector,
    snake: Snake,
    bullet: Vector,
}

impl Board {

    pub fn new (bounds: Vector) -> Board {
        Board {
            bounds: bounds,
            snake: Snake::new(Vector { x: bounds.x / 2, y: bounds.y / 2 }),
            bullet: Vector::random(bounds),
        }
    }

    pub fn set_direction (&mut self, dir: Direction) {
        self.snake.direction = dir;
    }

    pub fn tick (&mut self) -> Result<(), GameError> {

        self.snake.step();

        if self.snake.eats_bullet(self.bullet) {
            self.snake.grow();
            self.bullet = Vector::random(self.bounds);
        }

        if self.snake.hits_wall(self.bounds) {
            Err(GameError::Wall)
        } else if self.snake.hits_itself() {
            Err(GameError::Suicide)
        } else {
            Ok(())
        }
    }

    pub fn get_snake_vectors (&self) -> &[Vector] {
        let ref v = self.snake.segments;
        &v[..]
    }

    pub fn get_bullet_vector (&self) -> &Vector {
        &self.bullet
    }
}

struct Snake {
    segments: Vec<Vector>,
    direction: Direction,
    popped_segment: Vector,
}

impl Snake {

    fn new (pos: Vector) -> Snake {
        Snake {
            segments: vec!(pos),
            direction: Direction::Up,
            popped_segment: Vector { x: 0, y: 0 }
        }
    }

    fn step (&mut self) {
        let new_head = self.segments[0].next(self.direction);
        self.segments.insert(0, new_head);
        self.popped_segment = self.segments.pop().unwrap();
    }

    fn hits_wall (&self, bounds: Vector) -> bool {
        let head = self.segments[0];
        head.x < 0 || head.x == bounds.x || head.y < 0 || head.y == bounds.y
    }

    fn hits_itself (&self) -> bool {
        self.segments.iter().skip(1).any(|s| *s == self.segments[0] )
    }

    fn grow (&mut self) {
        self.segments.push(self.popped_segment);
    }

    fn eats_bullet (&self, bullet: Vector) -> bool {
        self.segments[0] == bullet
    }
}

// This was the code in main.rs
extern crate ncurses;

use std::thread::sleep_ms as sleep;
use self::ncurses::*;

pub fn snake()
{
    initscr();
    cbreak(); // enable <Ctrl+C> to kill game
    noecho(); // don't show input
    keypad(stdscr, true); // make keys work
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    timeout(100); // tick speed

    let mut bounds = Vector { x: 0, y: 0 };
    getmaxyx(stdscr, &mut bounds.y, &mut bounds.x);

    let mut board = Board::new(bounds);

    let mut direction = Direction::Up;

    loop {
        erase();

        {
            let bullet = board.get_bullet_vector();
            draw_char(bullet, 'o');
        }

        {
            let segments = board.get_snake_vectors();
            for segment in segments.iter() {
                draw_char(segment, '#');
            }
        }

        direction = get_new_direction(direction);
        board.set_direction(direction);

        match board.tick() {
            Err(err) => {
                match err {
                    GameError::Wall => show_text("You hit the wall, stupid."),
                    GameError::Suicide => show_text("Damn it. Stop eating yourself."),
                }
                //let two_secs = Duration::new(2, 0);
                sleep(2000);
                break;
            },
            Ok(_) => (),
        };
    }
    endwin();
}

fn draw_char (pos: &Vector, c: char) {
    mvaddch(pos.y, pos.x, c as u64);
}

fn get_new_direction (prev_dir: Direction) -> Direction {
    match getch() {
        KEY_UP if prev_dir != Direction::Down => Direction::Up,
        KEY_DOWN if prev_dir != Direction::Up => Direction::Down,
        KEY_LEFT if prev_dir != Direction::Right => Direction::Left,
        KEY_RIGHT if prev_dir != Direction::Left => Direction::Right,
        _ => prev_dir,
    }
}

fn show_text (s: &str) {
    erase();
    addstr(s);
    refresh();
}

// Below is space invaders code

#[derive(PartialEq,Copy,Clone)]
pub enum Direction { Up, Down, Left, Right }

pub enum GameStatus { Win, Running, Dead }

pub struct Game {
    bounds: Vector,
    invaders: Vec<Invader>,
    player: Player,
    bullets: Vec<Bullet>,
}

impl Game {

    pub fn new (bounds: Vector) -> Game {

        let mut invaders = vec!();
        //for i in range(0i32, bounds.x / 3) {
        for i in 0i32..(bounds.x / 3) {
            invaders.push(Invader::new( Vector { x: 2 * i, y: 0 }));
        }

        Game {
            bounds: bounds,
            invaders: invaders,
            player: Player::new(Vector { x: bounds.x / 2, y: bounds.y - 1 }),
            bullets: vec!(),
        }
    }

    pub fn tick (&mut self) -> GameStatus {

        for invader in self.invaders.iter_mut() {
            match invader.give_chance_to_fire() {
                Some(bullet) => self.bullets.push(bullet),
                None => (),
            };
            invader.tick(self.bounds);
        }

        for bullet in self.bullets.iter_mut() {
            bullet.tick(self.bounds);

            self.invaders.retain(|i| !bullet.check_collision(i.position));

            if bullet.check_collision(self.player.position) {
                return GameStatus::Dead;
            }
        }

        if self.invaders.is_empty() {
            GameStatus::Win
        } else {
            GameStatus::Running
        }
    }

    pub fn shift (&mut self, dir: Direction) {
        self.player.shift(dir, self.bounds);
    }

    pub fn fire (&mut self) {
        self.bullets.push(self.player.fire());
    }

    pub fn get_player_vector (&self) -> &Vector {
        &self.player.position
    }

    pub fn get_invader_vectors (&self) -> Vec<Vector> {
        self.invaders.iter().map(|i| i.position).collect()
    }

    pub fn get_bullet_vectors (&self) -> Vec<Vector> {
        self.bullets.iter().map(|b| b.position).collect()
    }
}

struct Invader {
    position: Vector,
    direction: Direction,
}

impl Invader {

    fn new (pos: Vector) -> Invader {
        Invader {
            position: pos,
            direction: Direction::Left,
        }
    }

    fn tick (&mut self, bounds: Vector) {
        let x = &mut self.position.x;
        self.direction = match self.direction {
            Direction::Left if *x < 0 => Direction::Right,
            Direction::Right if *x == bounds.x => Direction::Left,
            _ => self.direction.clone()
        };
        match self.direction {
            Direction::Left => *x = *x - 1,
            Direction::Right => *x = *x + 1,
            _ => (),
        };
    }

    fn give_chance_to_fire (&self) -> Option<Bullet> {
        let mut rng = rand::thread_rng();
        let temp: f32 = rng.gen_range(0.0, 1.0);
        if temp > 0.996 {
            Some(Bullet::new(Vector { x: self.position.x,
                y: self.position.y + 1 }, Direction::Down))
        } else {
            None
        }
    }
}

struct Player {
    position: Vector,
}

impl Player {

    fn new (pos: Vector) -> Player {
        Player { position: pos }
    }

    fn shift (&mut self, dir: Direction, bounds: Vector) {
        let x = &mut self.position.x;
        match dir {
            Direction::Left if *x > 0 => *x = *x - 1,
            Direction::Right if *x < bounds.x - 1 => *x = *x + 1,
            _ => (),
        }
    }

    fn fire (&self) -> Bullet {
        Bullet::new(Vector { x: self.position.x, y: self.position.y - 1 }, Direction::Up)
    }
}

struct Bullet {
    position: Vector,
    direction: Direction,
}

impl Bullet {

    fn new (pos: Vector, dir: Direction) -> Bullet {
        Bullet {
            position: pos,
            direction: dir,
        }
    }

    fn tick (&mut self, bounds: Vector) {
        match self.direction {
            Direction::Up => self.position.y -= 1,
            Direction::Down => self.position.y += 1,
            _ => (),
        };
        if self.position.y < 0 || self.position.y == bounds.y {
            drop(self);
        }
    }

    fn check_collision (&self, other: Vector) -> bool {
        self.position == other
    }
}

// blow is code from main.rs
pub fn space_invaders()
{
    initscr();
    cbreak(); // enable <Ctrl+C> to kill game
    noecho(); // don't show input
    keypad(stdscr, true); // make keys work
    curs_set(CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    timeout(1);

    let mut bounds = Vector { x: 0, y: 0};
    getmaxyx(stdscr, &mut bounds.y, &mut bounds.x);

    let mut game = Box::new(Game::new(bounds));

    // TODO rewrite async
    let mut tick_count = 0u8;

    loop {
        tick_count += 1;
        tick_count %= 30;

        erase();

        {
            let player = game.get_player_vector();
            draw_char(player, 'X');
        }

        {
            let invaders = game.get_invader_vectors();
            for invader in invaders.iter() {
                draw_char(invader, '#');
            }
        }

        {
            let bullets = game.get_bullet_vectors();
            for bullet in bullets.iter() {
                draw_char(bullet, '.');
            }
        }

        match getch() {
            KEY_LEFT => game.shift(Direction::Left),
            KEY_RIGHT => game.shift(Direction::Right),
            KEY_UP => game.fire(),
            _ => (),
        }

        if tick_count == 0 {
            match game.tick() {
                GameStatus::Dead => {
                    show_text("Puny human!");
                    sleep(2000);
                    break;
                },
                GameStatus::Win => {
                    show_text("Garglargl");
                    sleep(2000);
                    break;
                },
                GameStatus::Running => (),
            };
        }
    }

    endwin();
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::path::Path;
use toml::Value;
use error::Result;
use failure::err_msg;

/// Metadata for custom builds
///
/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your
/// crates' `Cargo.toml`.
///
/// An example metadata:
///
/// ```text
/// [package]
/// name = "test"
///
/// [package.metadata.docs.rs]
/// features = [ "feature1", "feature2" ]
/// all-features = true
/// no-default-features = true
/// default-target = "x86_64-unknown-linux-gnu"
/// extra-targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
/// rustc-args = [ "--example-rustc-arg" ]
/// rustdoc-args = [ "--example-rustdoc-arg" ]
/// ```
///
/// You can define one or more fields in your `Cargo.toml`.
pub struct Metadata {
    /// List of features docs.rs will build.
    ///
    /// By default, docs.rs will only build default features.
    pub features: Option<Vec<String>>,

    /// Set `all-features` to true if you want docs.rs to build all features for your crate
    pub all_features: bool,

    /// Docs.rs will always build default features.
    ///
    /// Set `no-default-fatures` to `false` if you want to build only certain features.
    pub no_default_features: bool,

    /// Docs.rs is running on `x86_64-unknown-linux-gnu` target system and default documentation
    /// is always built on this target. You can change default target by setting this.
    pub default_target: Option<String>,

    /// If you want a crate to build only for specific targets,
    /// set `extra-targets` to the list of targets to build, in addition to `default-target`.
    ///
    /// If you do not set `extra_targets`, all of the tier 1 supported targets will be built.
    /// If you set `extra_targets` to an empty array, only the default target will be built.
    pub extra_targets: Option<Vec<String>>,

    /// List of command line arguments for `rustc`.
    pub rustc_args: Option<Vec<String>>,

    /// List of command line arguments for `rustdoc`.
    pub rustdoc_args: Option<Vec<String>>,
}

impl Metadata {
    pub(crate) fn from_source_dir(source_dir: &Path) -> Result<Metadata> {
        for c in ["Cargo.toml.orig", "Cargo.toml"].iter() {
            let manifest_path = source_dir.clone().join(c);
            if manifest_path.exists() {
                return Ok(Metadata::from_manifest(manifest_path));
            }
        }
        Err(err_msg("Manifest not found"))
    }

    fn from_manifest<P: AsRef<Path>>(path: P) -> Metadata {
        use std::fs::File;
        use std::io::Read;
        let mut f = match File::open(path) {
            Ok(f) => f,
            Err(_) => return Metadata::default(),
        };
        let mut s = String::new();
        if let Err(_) = f.read_to_string(&mut s) {
            return Metadata::default();
        }
        Metadata::from_str(&s)
    }

    // This is similar to Default trait but it's private
    fn default() -> Metadata {
        Metadata {
            features: None,
            all_features: false,
            no_default_features: false,
            default_target: None,
            rustc_args: None,
            rustdoc_args: None,
            extra_targets: None,
        }
    }

    fn from_str(manifest: &str) -> Metadata {
        let mut metadata = Metadata::default();

        let manifest = match manifest.parse::<Value>() {
            Ok(m) => m,
            Err(_) => return metadata,
        };

        if let Some(table) = manifest.get("package").and_then(|p| p.as_table())
            .and_then(|p| p.get("metadata")).and_then(|p| p.as_table())
                .and_then(|p| p.get("docs")).and_then(|p| p.as_table())
                .and_then(|p| p.get("rs")).and_then(|p| p.as_table()) {
                    metadata.features = table.get("features").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.no_default_features = table.get("no-default-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features);
                    metadata.all_features = table.get("all-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.all_features);
                    metadata.default_target = table.get("default-target")
                        .and_then(|v| v.as_str()).map(|v| v.to_owned());
                    metadata.extra_targets = table.get("extra-targets").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustc_args = table.get("rustc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                }

        metadata
    }
    pub(super) fn select_extra_targets<'a>(&'a self, default_target: &str) -> HashSet<&'a str> {
        use super::rustwide_builder::TARGETS;
        // this is a breaking change, don't enable it by default
        let build_specific = std::env::var("DOCS_RS_BUILD_ONLY_SPECIFIED_TARGETS")
            .map(|s| s == "true").unwrap_or(false);
        // If the env variable is set, _only_ build the specified targets
        // If no targets are specified, only build the default target.
        let mut extra_targets: HashSet<_> = if build_specific {
            self.extra_targets
                    .as_ref()
                    .map(|v| v.iter().map(|s| s.as_str()).collect())
                    .unwrap_or_default()
        // Otherwise, let people opt-in to only having specific targets
        } else if let Some(explicit_targets) = &self.extra_targets {
            explicit_targets.iter().map(|s| s.as_str()).collect()
        // Otherwise, keep the existing behavior
        } else {
            TARGETS.iter().copied().collect()
        };
        extra_targets.remove(default_target);
        extra_targets
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::Metadata;

    #[test]
    fn test_cratesfyi_metadata() {
        let _ = env_logger::try_init();
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
            all-features = true
            no-default-features = true
            default-target = "x86_64-unknown-linux-gnu"
            extra-targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
            rustc-args = [ "--example-rustc-arg" ]
            rustdoc-args = [ "--example-rustdoc-arg" ]
        "#;

        let metadata = Metadata::from_str(manifest);

        assert!(metadata.features.is_some());
        assert!(metadata.all_features == true);
        assert!(metadata.no_default_features == true);
        assert!(metadata.default_target.is_some());
        assert!(metadata.rustdoc_args.is_some());

        let features = metadata.features.unwrap();
        assert_eq!(features.len(), 2);
        assert_eq!(features[0], "feature1".to_owned());
        assert_eq!(features[1], "feature2".to_owned());

        assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned());

        let extra_targets = metadata.extra_targets.expect("should have explicit extra target");
        assert_eq!(extra_targets.len(), 2);
        assert_eq!(extra_targets[0], "x86_64-apple-darwin");
        assert_eq!(extra_targets[1], "x86_64-pc-windows-msvc");

        let rustc_args = metadata.rustc_args.unwrap();
        assert_eq!(rustc_args.len(), 1);
        assert_eq!(rustc_args[0], "--example-rustc-arg".to_owned());

        let rustdoc_args = metadata.rustdoc_args.unwrap();
        assert_eq!(rustdoc_args.len(), 1);
        assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned());
    }

    #[test]
    fn test_no_extra_targets() {
        // metadata section but no extra_targets
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
        "#;
        let metadata = Metadata::from_str(manifest);
        assert!(metadata.extra_targets.is_none());

        // no package.metadata.docs.rs section
        let metadata = Metadata::from_str(r#"
            [package]
            name = "test"
        "#);
        assert!(metadata.extra_targets.is_none());

        // extra targets explicitly set to empty array
        let metadata = Metadata::from_str(r#"
            [package.metadata.docs.rs]
            extra-targets = []
        "#);
        assert!(metadata.extra_targets.unwrap().is_empty());
    }
}
<commit_msg>Add test for select_extra_targets<commit_after>use std::collections::HashSet;
use std::path::Path;
use toml::Value;
use error::Result;
use failure::err_msg;

/// Metadata for custom builds
///
/// You can customize docs.rs builds by defining `[package.metadata.docs.rs]` table in your
/// crates' `Cargo.toml`.
///
/// An example metadata:
///
/// ```text
/// [package]
/// name = "test"
///
/// [package.metadata.docs.rs]
/// features = [ "feature1", "feature2" ]
/// all-features = true
/// no-default-features = true
/// default-target = "x86_64-unknown-linux-gnu"
/// extra-targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
/// rustc-args = [ "--example-rustc-arg" ]
/// rustdoc-args = [ "--example-rustdoc-arg" ]
/// ```
///
/// You can define one or more fields in your `Cargo.toml`.
pub struct Metadata {
    /// List of features docs.rs will build.
    ///
    /// By default, docs.rs will only build default features.
    pub features: Option<Vec<String>>,

    /// Set `all-features` to true if you want docs.rs to build all features for your crate
    pub all_features: bool,

    /// Docs.rs will always build default features.
    ///
    /// Set `no-default-fatures` to `false` if you want to build only certain features.
    pub no_default_features: bool,

    /// Docs.rs is running on `x86_64-unknown-linux-gnu` target system and default documentation
    /// is always built on this target. You can change default target by setting this.
    pub default_target: Option<String>,

    /// If you want a crate to build only for specific targets,
    /// set `extra-targets` to the list of targets to build, in addition to `default-target`.
    ///
    /// If you do not set `extra_targets`, all of the tier 1 supported targets will be built.
    /// If you set `extra_targets` to an empty array, only the default target will be built.
    pub extra_targets: Option<Vec<String>>,

    /// List of command line arguments for `rustc`.
    pub rustc_args: Option<Vec<String>>,

    /// List of command line arguments for `rustdoc`.
    pub rustdoc_args: Option<Vec<String>>,
}

impl Metadata {
    pub(crate) fn from_source_dir(source_dir: &Path) -> Result<Metadata> {
        for c in ["Cargo.toml.orig", "Cargo.toml"].iter() {
            let manifest_path = source_dir.clone().join(c);
            if manifest_path.exists() {
                return Ok(Metadata::from_manifest(manifest_path));
            }
        }
        Err(err_msg("Manifest not found"))
    }

    fn from_manifest<P: AsRef<Path>>(path: P) -> Metadata {
        use std::fs::File;
        use std::io::Read;
        let mut f = match File::open(path) {
            Ok(f) => f,
            Err(_) => return Metadata::default(),
        };
        let mut s = String::new();
        if let Err(_) = f.read_to_string(&mut s) {
            return Metadata::default();
        }
        Metadata::from_str(&s)
    }

    // This is similar to Default trait but it's private
    fn default() -> Metadata {
        Metadata {
            features: None,
            all_features: false,
            no_default_features: false,
            default_target: None,
            rustc_args: None,
            rustdoc_args: None,
            extra_targets: None,
        }
    }

    fn from_str(manifest: &str) -> Metadata {
        let mut metadata = Metadata::default();

        let manifest = match manifest.parse::<Value>() {
            Ok(m) => m,
            Err(_) => return metadata,
        };

        if let Some(table) = manifest.get("package").and_then(|p| p.as_table())
            .and_then(|p| p.get("metadata")).and_then(|p| p.as_table())
                .and_then(|p| p.get("docs")).and_then(|p| p.as_table())
                .and_then(|p| p.get("rs")).and_then(|p| p.as_table()) {
                    metadata.features = table.get("features").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.no_default_features = table.get("no-default-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.no_default_features);
                    metadata.all_features = table.get("all-features")
                        .and_then(|v| v.as_bool()).unwrap_or(metadata.all_features);
                    metadata.default_target = table.get("default-target")
                        .and_then(|v| v.as_str()).map(|v| v.to_owned());
                    metadata.extra_targets = table.get("extra-targets").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustc_args = table.get("rustc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                    metadata.rustdoc_args = table.get("rustdoc-args").and_then(|f| f.as_array())
                        .and_then(|f| f.iter().map(|v| v.as_str().map(|v| v.to_owned())).collect());
                }

        metadata
    }
    pub(super) fn select_extra_targets<'a>(&'a self, default_target: &str) -> HashSet<&'a str> {
        use super::rustwide_builder::TARGETS;
        // this is a breaking change, don't enable it by default
        let build_specific = std::env::var("DOCS_RS_BUILD_ONLY_SPECIFIED_TARGETS")
            .map(|s| s == "true").unwrap_or(false);
        // If the env variable is set, _only_ build the specified targets
        // If no targets are specified, only build the default target.
        let mut extra_targets: HashSet<_> = if build_specific {
            self.extra_targets
                    .as_ref()
                    .map(|v| v.iter().map(|s| s.as_str()).collect())
                    .unwrap_or_default()
        // Otherwise, let people opt-in to only having specific targets
        } else if let Some(explicit_targets) = &self.extra_targets {
            explicit_targets.iter().map(|s| s.as_str()).collect()
        // Otherwise, keep the existing behavior
        } else {
            TARGETS.iter().copied().collect()
        };
        extra_targets.remove(default_target);
        extra_targets
    }
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use super::Metadata;

    #[test]
    fn test_cratesfyi_metadata() {
        let _ = env_logger::try_init();
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
            all-features = true
            no-default-features = true
            default-target = "x86_64-unknown-linux-gnu"
            extra-targets = [ "x86_64-apple-darwin", "x86_64-pc-windows-msvc" ]
            rustc-args = [ "--example-rustc-arg" ]
            rustdoc-args = [ "--example-rustdoc-arg" ]
        "#;

        let metadata = Metadata::from_str(manifest);

        assert!(metadata.features.is_some());
        assert!(metadata.all_features == true);
        assert!(metadata.no_default_features == true);
        assert!(metadata.default_target.is_some());
        assert!(metadata.rustdoc_args.is_some());

        let features = metadata.features.unwrap();
        assert_eq!(features.len(), 2);
        assert_eq!(features[0], "feature1".to_owned());
        assert_eq!(features[1], "feature2".to_owned());

        assert_eq!(metadata.default_target.unwrap(), "x86_64-unknown-linux-gnu".to_owned());

        let extra_targets = metadata.extra_targets.expect("should have explicit extra target");
        assert_eq!(extra_targets.len(), 2);
        assert_eq!(extra_targets[0], "x86_64-apple-darwin");
        assert_eq!(extra_targets[1], "x86_64-pc-windows-msvc");

        let rustc_args = metadata.rustc_args.unwrap();
        assert_eq!(rustc_args.len(), 1);
        assert_eq!(rustc_args[0], "--example-rustc-arg".to_owned());

        let rustdoc_args = metadata.rustdoc_args.unwrap();
        assert_eq!(rustdoc_args.len(), 1);
        assert_eq!(rustdoc_args[0], "--example-rustdoc-arg".to_owned());
    }

    #[test]
    fn test_no_extra_targets() {
        // metadata section but no extra_targets
        let manifest = r#"
            [package]
            name = "test"

            [package.metadata.docs.rs]
            features = [ "feature1", "feature2" ]
        "#;
        let metadata = Metadata::from_str(manifest);
        assert!(metadata.extra_targets.is_none());

        // no package.metadata.docs.rs section
        let metadata = Metadata::from_str(r#"
            [package]
            name = "test"
        "#);
        assert!(metadata.extra_targets.is_none());

        // extra targets explicitly set to empty array
        let metadata = Metadata::from_str(r#"
            [package.metadata.docs.rs]
            extra-targets = []
        "#);
        assert!(metadata.extra_targets.unwrap().is_empty());
    }
    #[test]
    fn test_select_extra_targets() {
        use crate::docbuilder::rustwide_builder::TARGETS;

        let mut metadata = Metadata {
            extra_targets: None,
            ..Metadata::default()
        };
        const DEFAULT_TARGET: &str = "x86-unknown-linux-gnu";

        // unchanged default_target, extra targets not specified
        let tier_one = metadata.select_extra_targets(DEFAULT_TARGET);
        // should be equal to TARGETS except for DEFAULT_TARGET
        for actual in &tier_one {
            assert!(TARGETS.contains(actual));
        }
        for expected in TARGETS {
            if *expected == DEFAULT_TARGET {
                assert!(!tier_one.contains(DEFAULT_TARGET));
            } else {
                assert!(tier_one.contains(expected));
            }
        }

        // unchanged default_target, extra targets specified to be empty
        metadata.extra_targets = Some(Vec::new());
        assert!(metadata.select_extra_targets(DEFAULT_TARGET).is_empty());

        // unchanged default_target, extra targets includes targets besides default_target
        metadata.extra_targets = Some(vec!["i686-pc-windows-msvc".into(), "i686-apple-darwin".into()]);
        let extras = metadata.select_extra_targets(DEFAULT_TARGET);
        assert_eq!(extras.len(), 2);
        assert!(extras.contains("i686-pc-windows-msvc"));
        assert!(extras.contains("i686-apple-darwin"));

        // make sure that default_target is not built twice
        metadata.extra_targets = Some(vec![DEFAULT_TARGET.into()]);
        assert!(metadata.select_extra_targets(DEFAULT_TARGET).is_empty());

        // make sure that duplicates are removed
        metadata.extra_targets = Some(vec!["i686-pc-windows-msvc".into(), "i686-pc-windows-msvc".into()]);
        assert_eq!(metadata.select_extra_targets(DEFAULT_TARGET).len(), 1);

        // try it with a different default target just for sanity
        assert!(metadata.select_extra_targets("i686-pc-windows-msvc").is_empty());

    }
}
<|endoftext|>


<commit_before>use cpuio::UnsafePort;
use spin::Mutex;

use alloc::vec::Vec;

use d7abi::fs::protocol::console::KeyboardEvent;

use crate::multitasking::{EventQueue, ExplicitEventId, WaitFor, SCHEDULER};
use crate::time::SYSCLOCK;
use crate::util::io_wait;

mod state;

pub use self::state::KeyboardState;

// PS/2 ports
const PS2_DATA: u16 = 0x60; // rw
const PS2_STATUS: u16 = 0x64; // r-
const PS2_COMMAND: u16 = 0x64; // -w

// PIC commands
const PIC_CMD_EOI: u8 = 0x20;
const PIC_CMD_INIT: u8 = 0x11;

// Sensible timeout
const IO_WAIT_TIMEOUT: usize = 1000;

// Event buffer max size
const EVENT_BUFFER_LIMIT: usize = 1024;

pub struct Keyboard {
    enabled: bool,
    data_port: UnsafePort<u8>,
    status_port: UnsafePort<u8>,
    command_port: UnsafePort<u8>,
    state: KeyboardState,
    pub event_queue: EventQueue<KeyboardEvent>,
}

impl Keyboard {
    pub unsafe fn new() -> Keyboard {
        Keyboard {
            enabled: false,
            data_port: UnsafePort::new(PS2_DATA),
            status_port: UnsafePort::new(PS2_STATUS),
            command_port: UnsafePort::new(PS2_COMMAND),
            state: KeyboardState::new(),
            event_queue: EventQueue::new(EVENT_BUFFER_LIMIT),
        }
    }

    unsafe fn init(&mut self) {
        if self.self_test() {
            rprintln!("Keyboard: self test: ok");
        } else {
            rprintln!("Keyboard: self test: failed");
            panic!("Keyboard: self test: failed");
        }

        rprintln!(
            "Keyboard: echo: {}",
            if self.test_echo() { "ok" } else { "failed" }
        );

        self.disable_scanning();
        self.verify_keyboard();
        self.configure();
        self.enable_scanning();

        self.enabled = true;
    }

    pub fn is_enabled(&self) -> bool {
        self.enabled
    }

    /// Waits until output buffer has data
    unsafe fn wait_ready_read(&mut self) {
        loop {
            if (self.status_port.read() & 0x1) != 0 {
                break;
            }
        }
    }

    /// Waits until output buffer has space for data
    unsafe fn wait_ready_write(&mut self) {
        loop {
            if (self.status_port.read() & 0x2) == 0 {
                break;
            }
        }
    }

    pub unsafe fn test_result(&mut self, result: u8) -> bool {
        for _ in 0..IO_WAIT_TIMEOUT {
            io_wait();
            if self.read_byte() == result {
                return true;
            }
        }
        false
    }

    pub unsafe fn test_echo(&mut self) -> bool {
        self.wait_ready_write();
        self.data_port.write(0xEE);
        self.test_result(0xEE)
    }

    pub unsafe fn self_test(&mut self) -> bool {
        self.wait_ready_write();
        self.data_port.write(0xFF);
        self.test_result(0xAA)
    }

    pub unsafe fn verify_keyboard(&mut self) {
        self.wait_ready_write();
        self.data_port.write(0xF2);

        // This doesn't care about ack byte (0xFA), because Qemu doesn't support it, and it's not needed

        for _ in 0..IO_WAIT_TIMEOUT {
            let x = self.read_byte();
            if x == 0xAB {
                for _ in 0..IO_WAIT_TIMEOUT {
                    let kbd_subtype = self.read_byte();
                    if kbd_subtype == 0x41 || kbd_subtype == 0xC1 || kbd_subtype == 0x83 {
                        return;
                    }
                }
                panic!("Unsupported keyboard: unknown subtype");
            }
            io_wait();
        }
        panic!("Unsupported keyboard: cannot identify");
    }

    pub unsafe fn configure(&mut self) {
        // configure PS/2 controller
        self.wait_ready_write();
        self.ps2_write_command(0x20);
        io_wait();
        // https://wiki.osdev.org/%228042%22_PS/2_Controller#PS.2F2_Controller_Configuration_Byte
        let mut conf = self.read_byte();
        conf &= 0b1011_1111; // disable translation
        self.ps2_write_command(0x60);
        self.wait_ready_write();
        self.data_port.write(conf);

        // configure keyboard
        self.wait_ready_write();
        self.data_port.write(0xF0);
        io_wait();
        self.wait_ready_write();
        self.data_port.write(0x02); // scan code set 2
        io_wait();
        if !self.test_result(0xFA) {
            panic!("Unsupported keyboard");
        }
    }

    pub unsafe fn disable_scanning(&mut self) {
        self.wait_ready_write();
        self.data_port.write(0xF5);
        if !self.test_result(0xFA) {
            panic!("Unsupported keyboard");
        }
    }

    pub unsafe fn enable_scanning(&mut self) {
        self.wait_ready_write();
        self.data_port.write(0xF4);
        if !self.test_result(0xFA) {
            panic!("Unsupported keyboard");
        }
    }

    unsafe fn read_byte(&mut self) -> u8 {
        self.wait_ready_read();
        self.data_port.read()
    }

    unsafe fn ps2_write_command(&mut self, c: u8) {
        self.wait_ready_write();
        self.command_port.write(c)
    }

    pub unsafe fn notify(&mut self) {
        let byte = self.read_byte();

        if !self.enabled || byte == 0xFA || byte == 0xEE {
            return;
        }

        let timestamp = SYSCLOCK.now();

        if let Some(event) = self.state.apply(byte, timestamp) {
            self.event_queue.push(event);
        }
    }
}

lazy_static::lazy_static! {
    pub static ref KEYBOARD: Mutex<Keyboard> = Mutex::new(unsafe { Keyboard::new() });
}

// Interrupts must be disabled during initialization,
// so this wont deadlock on not-terribly-slow computers, including Qemu
pub fn init() {
    unsafe {
        KEYBOARD.lock().init();
    }
}
<commit_msg>Add some debugging features behind F-keys<commit_after>use cpuio::UnsafePort;
use spin::Mutex;

use alloc::vec::Vec;

use d7abi::fs::protocol::console::KeyboardEvent;

use crate::multitasking::{EventQueue, ExplicitEventId, WaitFor, SCHEDULER};
use crate::time::SYSCLOCK;
use crate::util::io_wait;

mod state;

pub use self::state::KeyboardState;

// PS/2 ports
const PS2_DATA: u16 = 0x60; // rw
const PS2_STATUS: u16 = 0x64; // r-
const PS2_COMMAND: u16 = 0x64; // -w

// PIC commands
const PIC_CMD_EOI: u8 = 0x20;
const PIC_CMD_INIT: u8 = 0x11;

// Sensible timeout
const IO_WAIT_TIMEOUT: usize = 1000;

// Event buffer max size
const EVENT_BUFFER_LIMIT: usize = 1024;

pub struct Keyboard {
    enabled: bool,
    data_port: UnsafePort<u8>,
    status_port: UnsafePort<u8>,
    command_port: UnsafePort<u8>,
    state: KeyboardState,
    pub event_queue: EventQueue<KeyboardEvent>,
}

impl Keyboard {
    pub unsafe fn new() -> Keyboard {
        Keyboard {
            enabled: false,
            data_port: UnsafePort::new(PS2_DATA),
            status_port: UnsafePort::new(PS2_STATUS),
            command_port: UnsafePort::new(PS2_COMMAND),
            state: KeyboardState::new(),
            event_queue: EventQueue::new("keyboard", EVENT_BUFFER_LIMIT),
        }
    }

    unsafe fn init(&mut self) {
        if self.self_test() {
            log::info!("self test: ok");
        } else {
            log::info!("self test: failed");
            panic!("self test: failed");
        }

        log::info!("echo: {}", if self.test_echo() { "ok" } else { "failed" });

        self.disable_scanning();
        self.verify_keyboard();
        self.configure();
        self.enable_scanning();

        self.enabled = true;
    }

    pub fn is_enabled(&self) -> bool {
        self.enabled
    }

    /// Waits until output buffer has data
    unsafe fn wait_ready_read(&mut self) {
        loop {
            if (self.status_port.read() & 0x1) != 0 {
                break;
            }
        }
    }

    /// Waits until output buffer has space for data
    unsafe fn wait_ready_write(&mut self) {
        loop {
            if (self.status_port.read() & 0x2) == 0 {
                break;
            }
        }
    }

    pub unsafe fn test_result(&mut self, result: u8) -> bool {
        for _ in 0..IO_WAIT_TIMEOUT {
            io_wait();
            if self.read_byte() == result {
                return true;
            }
        }
        false
    }

    pub unsafe fn test_echo(&mut self) -> bool {
        self.wait_ready_write();
        self.data_port.write(0xEE);
        self.test_result(0xEE)
    }

    pub unsafe fn self_test(&mut self) -> bool {
        self.wait_ready_write();
        self.data_port.write(0xFF);
        self.test_result(0xAA)
    }

    pub unsafe fn verify_keyboard(&mut self) {
        self.wait_ready_write();
        self.data_port.write(0xF2);

        // This doesn't care about ack byte (0xFA), because Qemu doesn't support it, and it's not needed

        for _ in 0..IO_WAIT_TIMEOUT {
            let x = self.read_byte();
            if x == 0xAB {
                for _ in 0..IO_WAIT_TIMEOUT {
                    let kbd_subtype = self.read_byte();
                    if kbd_subtype == 0x41 || kbd_subtype == 0xC1 || kbd_subtype == 0x83 {
                        return;
                    }
                }
                panic!("Unsupported keyboard: unknown subtype");
            }
            io_wait();
        }
        panic!("Unsupported keyboard: cannot identify");
    }

    pub unsafe fn configure(&mut self) {
        // configure PS/2 controller
        self.wait_ready_write();
        self.ps2_write_command(0x20);
        io_wait();
        // https://wiki.osdev.org/%228042%22_PS/2_Controller#PS.2F2_Controller_Configuration_Byte
        let mut conf = self.read_byte();
        conf &= 0b1011_1111; // disable translation
        self.ps2_write_command(0x60);
        self.wait_ready_write();
        self.data_port.write(conf);

        // configure keyboard
        self.wait_ready_write();
        self.data_port.write(0xF0);
        io_wait();
        self.wait_ready_write();
        self.data_port.write(0x02); // scan code set 2
        io_wait();
        if !self.test_result(0xFA) {
            panic!("Unsupported keyboard");
        }
    }

    pub unsafe fn disable_scanning(&mut self) {
        self.wait_ready_write();
        self.data_port.write(0xF5);
        if !self.test_result(0xFA) {
            panic!("Unsupported keyboard");
        }
    }

    pub unsafe fn enable_scanning(&mut self) {
        self.wait_ready_write();
        self.data_port.write(0xF4);
        if !self.test_result(0xFA) {
            panic!("Unsupported keyboard");
        }
    }

    unsafe fn read_byte(&mut self) -> u8 {
        self.wait_ready_read();
        self.data_port.read()
    }

    unsafe fn ps2_write_command(&mut self, c: u8) {
        self.wait_ready_write();
        self.command_port.write(c)
    }

    pub unsafe fn notify(&mut self) {
        let byte = self.read_byte();

        if !self.enabled || byte == 0xFA || byte == 0xEE {
            return;
        }

        let timestamp = SYSCLOCK.now();

        if let Some(event) = self.state.apply(byte, timestamp) {
            log::trace!("{:?}", event);

            // Kernel debugging F-keys
            // TODO: Remove these or at least move them behind a key combination
            if !event.release {
                match event.keycode {
                    5 => {
                        // F1: Panic immediately
                        panic!("F1 pressed");
                    },
                    6 => {
                        // F2: Display process queues
                        rprintln!("{}", SCHEDULER.try_lock().unwrap().debug_view_string())
                    },
                    _ => {},
                }
            }

            self.event_queue.push(event);
        }
    }
}

lazy_static::lazy_static! {
    pub static ref KEYBOARD: Mutex<Keyboard> = Mutex::new(unsafe { Keyboard::new() });
}

// Interrupts must be disabled during initialization,
// so this wont deadlock on not-terribly-slow computers, including Qemu
pub fn init() {
    unsafe {
        KEYBOARD.lock().init();
    }
}
<|endoftext|>