<commit_before>use {Dependency, Manifest};
use regex::Regex;
use reqwest;
use semver;
use serde_json as json;
use std::env;
use std::io;
use std::io::Read;
use std::path::Path;
use std::time::Duration;

const REGISTRY_HOST: &'static str = "https://crates.io";

#[derive(Deserialize)]
struct Versions {
    versions: Vec<CrateVersion>,
}

#[derive(Deserialize)]
struct CrateVersion {
    #[serde(rename = "crate")]
    name: String,
    #[serde(rename = "num")]
    version: semver::Version,
    yanked: bool,
}

/// Query latest version from crates.io
///
/// The latest version will be returned as a `Dependency`. This will fail, when
///
/// - there is no Internet connection,
/// - the response from crates.io is an error or in an incorrect format,
/// - or when a crate with the given name does not exist on crates.io.
pub fn get_latest_dependency(
    crate_name: &str,
    flag_allow_prerelease: bool,
) -> Result<Dependency, FetchVersionError> {
    if env::var("CARGO_IS_TEST").is_ok() {
        // We are in a simulated reality. Nothing is real here.
        // FIXME: Use actual test handling code.
        if flag_allow_prerelease {
            return Ok(
                Dependency::new(crate_name)
                    .set_version(&format!("{}--PRERELEASE_VERSION_TEST", crate_name)),
            );
        } else {
            return Ok(
                Dependency::new(crate_name)
                    .set_version(&format!("{}--CURRENT_VERSION_TEST", crate_name)),
            );
        }
    }

    let crate_versions = fetch_cratesio(&format!("/crates/{}", crate_name))?;

    let dep = read_latest_version(&crate_versions, flag_allow_prerelease)?;

    if dep.name != crate_name {
        println!("WARN: Added `{}` instead of `{}`", dep.name, crate_name);
    }

    Ok(dep)
}

// Checks whether a version object is a stable release
fn version_is_stable(version: &CrateVersion) -> bool {
    !version.version.is_prerelease()
}

/// Read latest version from Versions structure
///
/// Assumes the version are sorted so that the first non-yanked version is the
/// latest, and thus the one we want.
fn read_latest_version(
    versions: &Versions,
    flag_allow_prerelease: bool,
) -> Result<Dependency, FetchVersionError> {
    let latest = versions
        .versions
        .iter()
        .filter(|&v| flag_allow_prerelease || version_is_stable(v))
        .find(|&v| !v.yanked)
        .ok_or(FetchVersionError::NoneAvailable)?;

    let name = &latest.name;
    let version = latest.version.to_string();
    Ok(Dependency::new(name).set_version(&version))
}

#[test]
fn get_latest_stable_version_from_json() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "foo",
          "num": "0.6.0-alpha",
          "yanked": false
        },
        {
          "crate": "foo",
          "num": "0.5.0",
          "yanked": false
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert_eq!(
        read_latest_version(&versions, false)
            .unwrap()
            .version()
            .unwrap(),
        "0.5.0"
    );
}

#[test]
fn get_latest_unstable_or_stable_version_from_json() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "foo",
          "num": "0.6.0-alpha",
          "yanked": false
        },
        {
          "crate": "foo",
          "num": "0.5.0",
          "yanked": false
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert_eq!(
        read_latest_version(&versions, true)
            .unwrap()
            .version()
            .unwrap(),
        "0.6.0-alpha"
    );
}

#[test]
fn get_latest_version_from_json_test() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "treexml",
          "num": "0.3.1",
          "yanked": true
        },
        {
          "crate": "treexml",
          "num": "0.3.0",
          "yanked": false
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert_eq!(
        read_latest_version(&versions, false)
            .unwrap()
            .version()
            .unwrap(),
        "0.3.0"
    );
}

#[test]
fn get_no_latest_version_from_json_when_all_are_yanked() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "treexml",
          "num": "0.3.1",
          "yanked": true
        },
        {
          "crate": "treexml",
          "num": "0.3.0",
          "yanked": true
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert!(read_latest_version(&versions, false).is_err());
}

quick_error! {
    #[derive(Debug)]
    pub enum FetchVersionError {
        Reqwest(err: reqwest::Error) {
            from()
            description("Https error")
            display("Https error: {}", err)
            cause(err)
        }
        Json(err: json::Error) {
            from()
            description("Json error")
            display("Json error (crate does not exist?): {}", err)
            cause(err)
        }
        NoneAvailable {
            description("No available versions exist. Either all were yanked\
                         or only prerelease versions exist. Trying with the\
                         --fetch-prereleases flag might solve the issue."
            )
        }
    }
}

fn fetch_cratesio(path: &str) -> Result<Versions, FetchVersionError> {
    let url = format!("{host}/api/v1{path}", host = REGISTRY_HOST, path = path);
    let response = get_with_timeout(&url, get_default_timeout())?;
    let versions: Versions = json::from_reader(response)
        .map_err(FetchVersionError::Json)?;
    Ok(versions)
}

#[cfg_attr(rustfmt, rustfmt_skip)]
quick_error! {
    #[derive(Debug)]
    pub enum FetchGitError {
        FetchGit(err: reqwest::Error) {
            from()
            description("fetch error: ")
            display("fetch error: {}", err)
            cause(err)
        }
        Io(err: io::Error) {
            from()
            description("io error: ")
            display("io error: {}", err)
            cause(err)
        }
        ParseRegex { description("parse error: unable to parse git repo url") }
        IncompleteCaptures { description("parse error: the git repo url seems incomplete") }
        LocalCargoToml { description("path error: unable to open Cargo.toml") }
        ParseCargoToml { description("parse error: unable to parse the external Cargo.toml") }
    }
}

fn get_crate_name_from_repository<T>(
    repo: &str,
    matcher: &Regex,
    url_template: T,
) -> Result<String, FetchGitError>
where
    T: Fn(&str, &str) -> String,
{
    matcher
        .captures(repo)
        .ok_or(FetchGitError::ParseRegex)
        .and_then(|cap| match (cap.get(1), cap.get(2)) {
            (Some(user), Some(repo)) => {
                let url = url_template(user.as_str(), repo.as_str());
                let data: Result<Manifest, _> = get_cargo_toml_from_git_url(&url)
                    .and_then(|m| m.parse().map_err(|_| FetchGitError::ParseCargoToml));
                data.and_then(|ref manifest| get_name_from_manifest(manifest))
            }
            _ => Err(FetchGitError::IncompleteCaptures),
        })
}

/// Query crate name by accessing a github repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from github is an error or in an incorrect format.
pub fn get_crate_name_from_github(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(
        r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$",
    ).unwrap();
    get_crate_name_from_repository(repo, &re, |user, repo| {
        format!(
            "https://raw.githubusercontent.com/{user}/{repo}/master/Cargo.toml",
            user = user,
            repo = repo
        )
    })
}

/// Query crate name by accessing a gitlab repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from gitlab is an error or in an incorrect format.
pub fn get_crate_name_from_gitlab(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(
        r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$",
    ).unwrap();
    get_crate_name_from_repository(repo, &re, |user, repo| {
        format!(
            "https://gitlab.com/{user}/{repo}/raw/master/Cargo.toml",
            user = user,
            repo = repo
        )
    })
}

/// Query crate name by accessing Cargo.toml in a local path
///
/// The name will be returned as a string. This will fail, when
/// Cargo.toml is not present in the root of the path.
pub fn get_crate_name_from_path(path: &str) -> Result<String, FetchGitError> {
    let cargo_file = Path::new(path).join("Cargo.toml");
    Manifest::open(&Some(cargo_file))
        .map_err(|_| FetchGitError::LocalCargoToml)
        .and_then(|ref manifest| get_name_from_manifest(manifest))
}

fn get_name_from_manifest(manifest: &Manifest) -> Result<String, FetchGitError> {
    manifest
        .data
        .get("package")
        .and_then(|m| m.get("name"))
        .and_then(|name| name.as_str().map(|s| s.to_string()))
        .ok_or(FetchGitError::ParseCargoToml)
}

fn get_default_timeout() -> Duration {
    Duration::from_secs(10)
}

fn get_with_timeout(url: &str, timeout: Duration) -> reqwest::Result<reqwest::Response> {
    let client = reqwest::ClientBuilder::new()?.timeout(timeout).build()?;

    client.get(url)?.send()
}

fn get_cargo_toml_from_git_url(url: &str) -> Result<String, FetchGitError> {
    let mut res = get_with_timeout(url, get_default_timeout())?;
    let mut body = String::new();
    res.read_to_string(&mut body)?;
    Ok(body)
}
<commit_msg>Refactor to avoid code repetition.<commit_after>use {Dependency, Manifest};
use regex::Regex;
use reqwest;
use semver;
use serde_json as json;
use std::env;
use std::io;
use std::io::Read;
use std::path::Path;
use std::time::Duration;

const REGISTRY_HOST: &'static str = "https://crates.io";

#[derive(Deserialize)]
struct Versions {
    versions: Vec<CrateVersion>,
}

#[derive(Deserialize)]
struct CrateVersion {
    #[serde(rename = "crate")]
    name: String,
    #[serde(rename = "num")]
    version: semver::Version,
    yanked: bool,
}

/// Query latest version from crates.io
///
/// The latest version will be returned as a `Dependency`. This will fail, when
///
/// - there is no Internet connection,
/// - the response from crates.io is an error or in an incorrect format,
/// - or when a crate with the given name does not exist on crates.io.
pub fn get_latest_dependency(
    crate_name: &str,
    flag_allow_prerelease: bool,
) -> Result<Dependency, FetchVersionError> {
    if env::var("CARGO_IS_TEST").is_ok() {
        // We are in a simulated reality. Nothing is real here.
        // FIXME: Use actual test handling code.
        let new_version = if flag_allow_prerelease {
            format!("{}--PRERELEASE_VERSION_TEST", crate_name)
        } else {
            format!("{}--CURRENT_VERSION_TEST", crate_name)
        };

        return Ok(Dependency::new(crate_name).set_version(&new_version));
    }

    let crate_versions = fetch_cratesio(&format!("/crates/{}", crate_name))?;

    let dep = read_latest_version(&crate_versions, flag_allow_prerelease)?;

    if dep.name != crate_name {
        println!("WARN: Added `{}` instead of `{}`", dep.name, crate_name);
    }

    Ok(dep)
}

// Checks whether a version object is a stable release
fn version_is_stable(version: &CrateVersion) -> bool {
    !version.version.is_prerelease()
}

/// Read latest version from Versions structure
///
/// Assumes the version are sorted so that the first non-yanked version is the
/// latest, and thus the one we want.
fn read_latest_version(
    versions: &Versions,
    flag_allow_prerelease: bool,
) -> Result<Dependency, FetchVersionError> {
    let latest = versions
        .versions
        .iter()
        .filter(|&v| flag_allow_prerelease || version_is_stable(v))
        .find(|&v| !v.yanked)
        .ok_or(FetchVersionError::NoneAvailable)?;

    let name = &latest.name;
    let version = latest.version.to_string();
    Ok(Dependency::new(name).set_version(&version))
}

#[test]
fn get_latest_stable_version_from_json() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "foo",
          "num": "0.6.0-alpha",
          "yanked": false
        },
        {
          "crate": "foo",
          "num": "0.5.0",
          "yanked": false
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert_eq!(
        read_latest_version(&versions, false)
            .unwrap()
            .version()
            .unwrap(),
        "0.5.0"
    );
}

#[test]
fn get_latest_unstable_or_stable_version_from_json() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "foo",
          "num": "0.6.0-alpha",
          "yanked": false
        },
        {
          "crate": "foo",
          "num": "0.5.0",
          "yanked": false
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert_eq!(
        read_latest_version(&versions, true)
            .unwrap()
            .version()
            .unwrap(),
        "0.6.0-alpha"
    );
}

#[test]
fn get_latest_version_from_json_test() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "treexml",
          "num": "0.3.1",
          "yanked": true
        },
        {
          "crate": "treexml",
          "num": "0.3.0",
          "yanked": false
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert_eq!(
        read_latest_version(&versions, false)
            .unwrap()
            .version()
            .unwrap(),
        "0.3.0"
    );
}

#[test]
fn get_no_latest_version_from_json_when_all_are_yanked() {
    let versions: Versions = json::from_str(
        r#"{
      "versions": [
        {
          "crate": "treexml",
          "num": "0.3.1",
          "yanked": true
        },
        {
          "crate": "treexml",
          "num": "0.3.0",
          "yanked": true
        }
      ]
    }"#,
    ).expect("crate version is correctly parsed");

    assert!(read_latest_version(&versions, false).is_err());
}

quick_error! {
    #[derive(Debug)]
    pub enum FetchVersionError {
        Reqwest(err: reqwest::Error) {
            from()
            description("Https error")
            display("Https error: {}", err)
            cause(err)
        }
        Json(err: json::Error) {
            from()
            description("Json error")
            display("Json error (crate does not exist?): {}", err)
            cause(err)
        }
        NoneAvailable {
            description("No available versions exist. Either all were yanked\
                         or only prerelease versions exist. Trying with the\
                         --fetch-prereleases flag might solve the issue."
            )
        }
    }
}

fn fetch_cratesio(path: &str) -> Result<Versions, FetchVersionError> {
    let url = format!("{host}/api/v1{path}", host = REGISTRY_HOST, path = path);
    let response = get_with_timeout(&url, get_default_timeout())?;
    let versions: Versions = json::from_reader(response)
        .map_err(FetchVersionError::Json)?;
    Ok(versions)
}

#[cfg_attr(rustfmt, rustfmt_skip)]
quick_error! {
    #[derive(Debug)]
    pub enum FetchGitError {
        FetchGit(err: reqwest::Error) {
            from()
            description("fetch error: ")
            display("fetch error: {}", err)
            cause(err)
        }
        Io(err: io::Error) {
            from()
            description("io error: ")
            display("io error: {}", err)
            cause(err)
        }
        ParseRegex { description("parse error: unable to parse git repo url") }
        IncompleteCaptures { description("parse error: the git repo url seems incomplete") }
        LocalCargoToml { description("path error: unable to open Cargo.toml") }
        ParseCargoToml { description("parse error: unable to parse the external Cargo.toml") }
    }
}

fn get_crate_name_from_repository<T>(
    repo: &str,
    matcher: &Regex,
    url_template: T,
) -> Result<String, FetchGitError>
where
    T: Fn(&str, &str) -> String,
{
    matcher
        .captures(repo)
        .ok_or(FetchGitError::ParseRegex)
        .and_then(|cap| match (cap.get(1), cap.get(2)) {
            (Some(user), Some(repo)) => {
                let url = url_template(user.as_str(), repo.as_str());
                let data: Result<Manifest, _> = get_cargo_toml_from_git_url(&url)
                    .and_then(|m| m.parse().map_err(|_| FetchGitError::ParseCargoToml));
                data.and_then(|ref manifest| get_name_from_manifest(manifest))
            }
            _ => Err(FetchGitError::IncompleteCaptures),
        })
}

/// Query crate name by accessing a github repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from github is an error or in an incorrect format.
pub fn get_crate_name_from_github(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(
        r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$",
    ).unwrap();
    get_crate_name_from_repository(repo, &re, |user, repo| {
        format!(
            "https://raw.githubusercontent.com/{user}/{repo}/master/Cargo.toml",
            user = user,
            repo = repo
        )
    })
}

/// Query crate name by accessing a gitlab repo Cargo.toml
///
/// The name will be returned as a string. This will fail, when
///
/// - there is no Internet connection,
/// - Cargo.toml is not present in the root of the master branch,
/// - the response from gitlab is an error or in an incorrect format.
pub fn get_crate_name_from_gitlab(repo: &str) -> Result<String, FetchGitError> {
    let re = Regex::new(
        r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$",
    ).unwrap();
    get_crate_name_from_repository(repo, &re, |user, repo| {
        format!(
            "https://gitlab.com/{user}/{repo}/raw/master/Cargo.toml",
            user = user,
            repo = repo
        )
    })
}

/// Query crate name by accessing Cargo.toml in a local path
///
/// The name will be returned as a string. This will fail, when
/// Cargo.toml is not present in the root of the path.
pub fn get_crate_name_from_path(path: &str) -> Result<String, FetchGitError> {
    let cargo_file = Path::new(path).join("Cargo.toml");
    Manifest::open(&Some(cargo_file))
        .map_err(|_| FetchGitError::LocalCargoToml)
        .and_then(|ref manifest| get_name_from_manifest(manifest))
}

fn get_name_from_manifest(manifest: &Manifest) -> Result<String, FetchGitError> {
    manifest
        .data
        .get("package")
        .and_then(|m| m.get("name"))
        .and_then(|name| name.as_str().map(|s| s.to_string()))
        .ok_or(FetchGitError::ParseCargoToml)
}

fn get_default_timeout() -> Duration {
    Duration::from_secs(10)
}

fn get_with_timeout(url: &str, timeout: Duration) -> reqwest::Result<reqwest::Response> {
    let client = reqwest::ClientBuilder::new()?.timeout(timeout).build()?;

    client.get(url)?.send()
}

fn get_cargo_toml_from_git_url(url: &str) -> Result<String, FetchGitError> {
    let mut res = get_with_timeout(url, get_default_timeout())?;
    let mut body = String::new();
    res.read_to_string(&mut body)?;
    Ok(body)
}
<|endoftext|>


<commit_before>
//! Provides utilities for tracking the state of various input devices

use {StateRequest, Event};
use cable_math::Vec2;
use std::sync::mpsc;
use glutin::{self, MouseButton, ElementState, MouseScrollDelta};

const MOUSE_KEYS: usize = 5;
const KEYBOARD_KEYS: usize = 256; // This MUST be `u8::max_value() + 1`

/// Manages keyboard and mouse input. This manager receives events from a
/// `mpsc::Receiver`. This means it can be created and used in other threads.
/// Note that [`InputManager::refresh`] should be called once per frame.
///
/// `InputManager`s are created by [`GameState::gen_input_manager`]
///
/// [`GameState::gen_input_manager`]: ../struct.GameState.html#method.gen_input_manager
/// [`InputManager::refresh`]:        struct.InputManager.html#method.refresh
pub struct InputManager {
    mouse_pos: Vec2<f32>,
    mouse_delta: Vec2<f32>,
    mouse_scroll: Vec2<f32>,
    mouse_states: [KeyState; MOUSE_KEYS],
    keyboard_states: [KeyState; KEYBOARD_KEYS],
    type_buffer: String,

    prev_event_count: usize,
    event_source: mpsc::Receiver<Event>,
    event_sink: mpsc::Sender<StateRequest>,
}

impl InputManager {
    /// Dont call this directly. Use [`GameState::gen_input_manager`] instead.
    ///
    /// [`GameState::gen_input_manager`]: struct.GameState.html#method.gen_input_manager
    pub fn new(event_source: mpsc::Receiver<Event>, event_sink: mpsc::Sender<StateRequest>) -> InputManager {
        InputManager {
            mouse_pos: Vec2::zero(),
            mouse_delta: Vec2::zero(),
            mouse_scroll: Vec2::zero(),
            mouse_states: [KeyState::Up; MOUSE_KEYS],
            keyboard_states: [KeyState::Up; KEYBOARD_KEYS],
            type_buffer: String::with_capacity(10),

            prev_event_count: 0,
            event_source: event_source,
            event_sink: event_sink,
        }
    }

    /// Pulls new data from this input managers source. This should be called once per frame.
    pub fn refresh(&mut self) {
        self.mouse_delta = Vec2::zero();
        self.mouse_scroll = Vec2::zero();
        self.type_buffer.clear();

        for state in self.mouse_states.iter_mut() {
            if *state == KeyState::Released { *state = KeyState::Up; }
            if *state == KeyState::Pressed  { *state = KeyState::Down; }
        }
        for state in self.keyboard_states.iter_mut() {
            if *state == KeyState::Released { *state = KeyState::Up; }
            if *state == KeyState::Pressed  { *state = KeyState::Down; }
        }

        self.prev_event_count = 0;
        for event in self.event_source.try_iter() {
            self.prev_event_count += 1;

            if let Event::GlutinEvent(glutin_event) = event {
                // Handle raw glutin events
                match glutin_event {
                    glutin::WindowEvent::MouseInput(state, button) => {
                        let index = match button {
                            MouseButton::Left => 0,
                            MouseButton::Right => 1,
                            MouseButton::Middle => 2,
                            MouseButton::Other(index) => index,
                        } as usize;
                        if index < self.mouse_states.len() {
                            self.mouse_states[index] = match state {
                                ElementState::Pressed => KeyState::Pressed,
                                ElementState::Released => KeyState::Released,
                            };
                        }
                    },
                    glutin::WindowEvent::MouseWheel(delta, _) => {
                        match delta {
                            MouseScrollDelta::LineDelta(x, y) => {
                                self.mouse_scroll += Vec2::new(x, y);
                            },
                            MouseScrollDelta::PixelDelta(x, y) => {
                                self.mouse_delta += Vec2::new(x, y);
                            },
                        }
                    },
                    glutin::WindowEvent::KeyboardInput(state, key, name, _modifier_state) => {
                        if let Some(name) = name { println!("{:?} = 0x{:x}", name, key); }

                        let ref mut internal_state = self.keyboard_states[key as usize];
                        match state {
                            ElementState::Pressed => {
                                *internal_state = if internal_state.down() {
                                    KeyState::PressedRepeat
                                } else {
                                    KeyState::Pressed
                                }
                            },
                            ElementState::Released => *internal_state = KeyState::Released,
                        };
                    },
                    glutin::WindowEvent::ReceivedCharacter(c) => self.type_buffer.push(c),
                    _ => {},
                }
            } else {
                // Handle custom event workarounds
                match event {
                    Event::MouseMoved { delta, pos } => {
                        self.mouse_pos = Vec2::new(pos.x as f32, pos.y as f32);
                        self.mouse_delta += Vec2::new(delta.x as f32, delta.y as f32);
                    },

                    Event::GlutinEvent(_) => unreachable!(),
                }
            }
        }
    }

    // Getters
    /// Position of the mouse cursor in pixels, relative to the top left corner of the screen
    pub fn mouse_pos(&self)   -> Vec2<f32> { self.mouse_pos }
    /// The distance the mouse cursor moved in the last frame
    pub fn mouse_delta(&self) -> Vec2<f32> { self.mouse_delta }
    /// The number of units scrolled in the last frame
    pub fn mouse_scroll(&self) -> f32 { self.mouse_scroll.y }
    /// The state of the given mouse key. Panics if `key` is greater than 4. The left
    /// mouse key is 0, the right key is 1 and the middle key is 2.
    pub fn mouse_key(&self, key: u8) -> KeyState {
        let key = key as usize;
        if key >= self.mouse_states.len() {
            panic!("{} is not a valid index for a mouse key");
        }
        self.mouse_states[key]
    }
    /// The state of the given keyboard key. Note that `Key` represent scancodes.
    /// See [`Key`](enum.Key.html) for more info
    pub fn key(&self, key: Key) -> KeyState {
        self.keyboard_states[key as usize]
    }
    /// Characters that have been typed. This is cleared each frame.
    pub fn typed(&self) -> &str {
        &self.type_buffer
    }

    /// The total number of events that occured between the last two calls to [`refresh`].
    ///
    /// [`refresh`]: struct.InputManager.html#fn.refresh
    pub fn prev_event_count(&self) -> usize {
        self.prev_event_count
    }

    /// See [`CursorState`] for more info.
    ///
    /// [`CursorState`]: enum.CursorState.html
    pub fn set_cursor_state(&mut self, state: CursorState) {
        self.event_sink.send(StateRequest::ChangeCursorState(state)).unwrap();
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum KeyState {
    /// The button is not held down.
    Up,
    /// The button is being held down. In the previous frame it was not held down.
    Pressed,
    /// The button is being held down, and its repeat action triggered
    PressedRepeat,
    /// The button is being held down.
    Down,
    /// The button is not being held down. In the previous frame it was held down.
    Released,
}
impl KeyState {
    /// Returns true if the button is being held down (`Down` or `Pressed`) and
    /// false otherwise (`Up`, `Released` or `PressedRepeat`).
    pub fn down(self) -> bool {
        match self {
            KeyState::Up | KeyState::Released => false,
            KeyState::Down | KeyState::Pressed | KeyState::PressedRepeat => true,
        }
    }
    /// Returns true if the button is not being held down (`Up` or `Released`) and
    /// false otherwise (`Down` or `Pressed`).
    pub fn up(self) -> bool {
        !self.down()
    }
    /// Returns true if the button is being held down, but was not held down in the last
    /// frame (`Pressed`)
    pub fn pressed(self) -> bool { self == KeyState::Pressed }
    /// Returns true either if this button is being held down and was not held down in the
    /// last frame (`Pressed`), or if the repeat action has been triggered by the key being
    /// held down for an extended amount of time (`PressedRepeat`).
    pub fn pressed_repeat(self) -> bool {
        self == KeyState::Pressed || self == KeyState::PressedRepeat
    }
    /// Returns true if the button is being not held down, but was held down in the last
    /// frame (`Released`)
    pub fn released(self) -> bool { self == KeyState::Released }
}

/// Codes for most keys. Note that these are scancodes, so they refer to a position
/// on the keyboard, rather than a specific symbol. These can be used as parameters
/// to [`InputManager::key`](struct.InputManager.html#method.key). The names are
/// based on the american keyboard layout.
#[cfg(target_os = "linux")]
#[repr(u8)]
pub enum Key {
    Key1 = 0xa, Key2 = 0xb, Key3 = 0xc, Key4 = 0xd, Key5 = 0xe,
    Key6 = 0xf, Key7 = 0x10, Key8 = 0x11, Key9 = 0x12, Key0 = 0x13,

    Q = 0x18, W = 0x19, E = 0x1a, R = 0x1b, T = 0x1c, Y = 0x1d, U = 0x1e, I = 0x1f, P = 0x20,
    A = 0x26, S = 0x27, D = 0x28, F = 0x29, G = 0x2a, H = 0x2b, J = 0x2c, K = 0x2d, L = 0x2e,
    Z = 0x34, X = 0x35, C = 0x36, V = 0x37, B = 0x38, N = 0x39, M = 0x3a,

    Space = 0x41,

    Escape = 0x9, Grave  = 0x31, Tab = 0x17, CapsLock  = 0x42,
    LShift = 0x32, LCtrl = 0x25, LAlt = 0x40,
    RAlt  = 0x6c, RMeta  = 0x86, RCtrl = 0x69, RShift = 0x3e, Return = 0x24, Back = 0x16,

    Right = 0x72, Left = 0x71, Down = 0x74, Up = 0x6f,

    Insert = 0x76, Delete = 0x77, Home = 0x6e, End = 0x73, PageUp = 0x70, PageDown = 0x75,

    F1 = 0x43, F2 = 0x44, F3 = 0x45, F4 = 0x46, F5 = 0x47, F6 = 0x48,
    F7 = 0x49, F8 = 0x4a, F9 = 0x4b, F10 = 0x4c, F11 = 0x5f, F12 = 0x60,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CursorState {
    Normal,
    /// The cursor is not drawn when over the game window. It can still move freely and leave the
    /// window.
    Hidden,
    /// The cursor can not leave the game window.
    Grabbed,
    /// A comibnation of `Hidden` and `Grabbed`. In this state, the absolute position of the cursor
    /// is constrained to (0, 0).
    HiddenGrabbed,

}

<commit_msg>Use different scancodes on windows. Not all scancodes are supported yet.<commit_after>
//! Provides utilities for tracking the state of various input devices

use {StateRequest, Event};
use cable_math::Vec2;
use std::sync::mpsc;
use glutin::{self, MouseButton, ElementState, MouseScrollDelta};

const MOUSE_KEYS: usize = 5;
const KEYBOARD_KEYS: usize = 256; // This MUST be `u8::max_value() + 1`

/// Manages keyboard and mouse input. This manager receives events from a
/// `mpsc::Receiver`. This means it can be created and used in other threads.
/// Note that [`InputManager::refresh`] should be called once per frame.
///
/// `InputManager`s are created by [`GameState::gen_input_manager`]
///
/// [`GameState::gen_input_manager`]: ../struct.GameState.html#method.gen_input_manager
/// [`InputManager::refresh`]:        struct.InputManager.html#method.refresh
pub struct InputManager {
    mouse_pos: Vec2<f32>,
    mouse_delta: Vec2<f32>,
    mouse_scroll: Vec2<f32>,
    mouse_states: [KeyState; MOUSE_KEYS],
    keyboard_states: [KeyState; KEYBOARD_KEYS],
    type_buffer: String,

    prev_event_count: usize,
    event_source: mpsc::Receiver<Event>,
    event_sink: mpsc::Sender<StateRequest>,
}

impl InputManager {
    /// Dont call this directly. Use [`GameState::gen_input_manager`] instead.
    ///
    /// [`GameState::gen_input_manager`]: struct.GameState.html#method.gen_input_manager
    pub fn new(event_source: mpsc::Receiver<Event>, event_sink: mpsc::Sender<StateRequest>) -> InputManager {
        InputManager {
            mouse_pos: Vec2::zero(),
            mouse_delta: Vec2::zero(),
            mouse_scroll: Vec2::zero(),
            mouse_states: [KeyState::Up; MOUSE_KEYS],
            keyboard_states: [KeyState::Up; KEYBOARD_KEYS],
            type_buffer: String::with_capacity(10),

            prev_event_count: 0,
            event_source: event_source,
            event_sink: event_sink,
        }
    }

    /// Pulls new data from this input managers source. This should be called once per frame.
    pub fn refresh(&mut self) {
        self.mouse_delta = Vec2::zero();
        self.mouse_scroll = Vec2::zero();
        self.type_buffer.clear();

        for state in self.mouse_states.iter_mut() {
            if *state == KeyState::Released { *state = KeyState::Up; }
            if *state == KeyState::Pressed  { *state = KeyState::Down; }
        }
        for state in self.keyboard_states.iter_mut() {
            if *state == KeyState::Released { *state = KeyState::Up; }
            if *state == KeyState::Pressed  { *state = KeyState::Down; }
        }

        self.prev_event_count = 0;
        for event in self.event_source.try_iter() {
            self.prev_event_count += 1;

            if let Event::GlutinEvent(glutin_event) = event {
                // Handle raw glutin events
                match glutin_event {
                    glutin::WindowEvent::MouseInput(state, button) => {
                        let index = match button {
                            MouseButton::Left => 0,
                            MouseButton::Right => 1,
                            MouseButton::Middle => 2,
                            MouseButton::Other(index) => index,
                        } as usize;
                        if index < self.mouse_states.len() {
                            self.mouse_states[index] = match state {
                                ElementState::Pressed => KeyState::Pressed,
                                ElementState::Released => KeyState::Released,
                            };
                        }
                    },
                    glutin::WindowEvent::MouseWheel(delta, _) => {
                        match delta {
                            MouseScrollDelta::LineDelta(x, y) => {
                                self.mouse_scroll += Vec2::new(x, y);
                            },
                            MouseScrollDelta::PixelDelta(x, y) => {
                                self.mouse_delta += Vec2::new(x, y);
                            },
                        }
                    },
                    glutin::WindowEvent::KeyboardInput(state, key, name, _modifier_state) => {
                        if state == ElementState::Pressed {
                            if let Some(name) = name {
                                println!("{:?} = 0x{:x},", name, key);
                            } else {
                                println!("? = 0x{:x},", key);
                            }
                        }

                        let ref mut internal_state = self.keyboard_states[key as usize];
                        match state {
                            ElementState::Pressed => {
                                *internal_state = if internal_state.down() {
                                    KeyState::PressedRepeat
                                } else {
                                    KeyState::Pressed
                                }
                            },
                            ElementState::Released => *internal_state = KeyState::Released,
                        };
                    },
                    glutin::WindowEvent::ReceivedCharacter(c) => self.type_buffer.push(c),
                    _ => {},
                }
            } else {
                // Handle custom event workarounds
                match event {
                    Event::MouseMoved { delta, pos } => {
                        self.mouse_pos = Vec2::new(pos.x as f32, pos.y as f32);
                        self.mouse_delta += Vec2::new(delta.x as f32, delta.y as f32);
                    },

                    Event::GlutinEvent(_) => unreachable!(),
                }
            }
        }
    }

    // Getters
    /// Position of the mouse cursor in pixels, relative to the top left corner of the screen
    pub fn mouse_pos(&self)   -> Vec2<f32> { self.mouse_pos }
    /// The distance the mouse cursor moved in the last frame
    pub fn mouse_delta(&self) -> Vec2<f32> { self.mouse_delta }
    /// The number of units scrolled in the last frame
    pub fn mouse_scroll(&self) -> f32 { self.mouse_scroll.y }
    /// The state of the given mouse key. Panics if `key` is greater than 4. The left
    /// mouse key is 0, the right key is 1 and the middle key is 2.
    pub fn mouse_key(&self, key: u8) -> KeyState {
        let key = key as usize;
        if key >= self.mouse_states.len() {
            panic!("{} is not a valid index for a mouse key");
        }
        self.mouse_states[key]
    }
    /// The state of the given keyboard key. Note that `Key` represent scancodes.
    /// See [`Key`](enum.Key.html) for more info
    pub fn key(&self, key: Key) -> KeyState {
        self.keyboard_states[key as usize]
    }
    /// Characters that have been typed. This is cleared each frame.
    pub fn typed(&self) -> &str {
        &self.type_buffer
    }

    /// The total number of events that occured between the last two calls to [`refresh`].
    ///
    /// [`refresh`]: struct.InputManager.html#fn.refresh
    pub fn prev_event_count(&self) -> usize {
        self.prev_event_count
    }

    /// See [`CursorState`] for more info.
    ///
    /// [`CursorState`]: enum.CursorState.html
    pub fn set_cursor_state(&mut self, state: CursorState) {
        self.event_sink.send(StateRequest::ChangeCursorState(state)).unwrap();
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum KeyState {
    /// The button is not held down.
    Up,
    /// The button is being held down. In the previous frame it was not held down.
    Pressed,
    /// The button is being held down, and its repeat action triggered
    PressedRepeat,
    /// The button is being held down.
    Down,
    /// The button is not being held down. In the previous frame it was held down.
    Released,
}
impl KeyState {
    /// Returns true if the button is being held down (`Down` or `Pressed`) and
    /// false otherwise (`Up`, `Released` or `PressedRepeat`).
    pub fn down(self) -> bool {
        match self {
            KeyState::Up | KeyState::Released => false,
            KeyState::Down | KeyState::Pressed | KeyState::PressedRepeat => true,
        }
    }
    /// Returns true if the button is not being held down (`Up` or `Released`) and
    /// false otherwise (`Down` or `Pressed`).
    pub fn up(self) -> bool {
        !self.down()
    }
    /// Returns true if the button is being held down, but was not held down in the last
    /// frame (`Pressed`)
    pub fn pressed(self) -> bool { self == KeyState::Pressed }
    /// Returns true either if this button is being held down and was not held down in the
    /// last frame (`Pressed`), or if the repeat action has been triggered by the key being
    /// held down for an extended amount of time (`PressedRepeat`).
    pub fn pressed_repeat(self) -> bool {
        self == KeyState::Pressed || self == KeyState::PressedRepeat
    }
    /// Returns true if the button is being not held down, but was held down in the last
    /// frame (`Released`)
    pub fn released(self) -> bool { self == KeyState::Released }
}

/// Codes for most keys. Note that these are scancodes, so they refer to a position
/// on the keyboard, rather than a specific symbol. These can be used as parameters
/// to [`InputManager::key`](struct.InputManager.html#method.key). The names are
/// based on the american keyboard layout.
///
/// Scancodes are target specific, so the values asigned to each enum name might vary from platform
/// to platform. On some platforms not all keys are available. Check the source code for more
/// detailed information on this.
#[cfg(target_os = "linux")]
#[repr(u8)]
pub enum Key {
    Key1 = 0xa, Key2 = 0xb, Key3 = 0xc, Key4 = 0xd, Key5 = 0xe,
    Key6 = 0xf, Key7 = 0x10, Key8 = 0x11, Key9 = 0x12, Key0 = 0x13,

    Q = 0x18, W = 0x19, E = 0x1a, R = 0x1b, T = 0x1c, Y = 0x1d, U = 0x1e, I = 0x1f, P = 0x20,
    A = 0x26, S = 0x27, D = 0x28, F = 0x29, G = 0x2a, H = 0x2b, J = 0x2c, K = 0x2d, L = 0x2e,
    Z = 0x34, X = 0x35, C = 0x36, V = 0x37, B = 0x38, N = 0x39, M = 0x3a,

    Space = 0x41,

    Escape = 0x9, Grave  = 0x31, Tab = 0x17, CapsLock  = 0x42,
    LShift = 0x32, LCtrl = 0x25, LAlt = 0x40,
    RAlt  = 0x6c, RMeta  = 0x86, RCtrl = 0x69, RShift = 0x3e, Return = 0x24, Back = 0x16,

    Right = 0x72, Left = 0x71, Down = 0x74, Up = 0x6f,

    Insert = 0x76, Delete = 0x77, Home = 0x6e, End = 0x73, PageUp = 0x70, PageDown = 0x75,

    F1 = 0x43, F2 = 0x44, F3 = 0x45, F4 = 0x46,  F5 = 0x47,  F6 = 0x48,
    F7 = 0x49, F8 = 0x4a, F9 = 0x4b, F10 = 0x4c, F11 = 0x5f, F12 = 0x60,
}

/// Codes for most keys. Note that these are scancodes, so they refer to a position on the
/// keyboard, rather than a specific symbol. These can be used as parameters to
/// [`InputManager::key`](struct.InputManager.html#method.key). The names are based on the american
/// keyboard layout.
///
/// Scancodes are target specific, so the values asigned to each enum name might vary from platform
/// to platform. On some platforms not all keys are available. Check the source code for more
/// detailed information on this.
#[cfg(target_os = "windows")]
#[repr(u8)]
pub enum Key {
    Key1 = 0x2, Key2 = 0x3, Key3 = 0x4, Key4 = 0x5, Key5 = 0x6,
    Key6 = 0x7, Key7 = 0x8, Key8 = 0x9, Key9 = 0xa, Key0 = 0xb,

    Q = 0x10, W = 0x11, E = 0x12, R = 0x13, T = 0x14, Y = 0x15, U = 0x16, I = 0x17, O = 0x18, P = 0x19,
    A = 0x1e, S = 0x1f, D = 0x20, F = 0x21, G = 0x22, H = 0x23, J = 0x24, K = 0x25, L = 0x26, Z = 0x2c,
    X = 0x2d, C = 0x2e, V = 0x2f, B = 0x30, N = 0x31, M = 0x32,

    Space = 0x39,

    Escape = 0x1,
//    Grave  = 0x31,
    Tab = 0xf,
//    CapsLock  = 0x42,
    LShift = 0x2a,
    LCtrl = 0x1d,
//    LAlt = 0x40,
//    RAlt  = 0x6c,
//    RMeta  = 0x86,
//    RCtrl = 0x1d, // Same scancode as LCtrl :/
    RShift = 0x36,
    Return = 0x1c,
    Back = 0xe,

    Right = 0x4d, Left = 0x4b, Down = 0x50, Up = 0x48,

    Insert = 0x52, Delete = 0x53, Home = 0x47, End = 0x4f, PageUp = 0x49, PageDown = 0x51,

    F1 = 0x3b, F2 = 0x3c, F3 = 0x3d, F4 = 0x3e,  F5 = 0x3f,  F6 = 0x40,
    F7 = 0x41, F8 = 0x42, F9 = 0x43, F10 = 0x44, F11 = 0x57, F12 = 0x58,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CursorState {
    Normal,
    /// The cursor is not drawn when over the game window. It can still move freely and leave the
    /// window.
    Hidden,
    /// The cursor can not leave the game window.
    Grabbed,
    /// A comibnation of `Hidden` and `Grabbed`. In this state, the absolute position of the cursor
    /// is constrained to (0, 0).
    HiddenGrabbed,

}

<|endoftext|>


<commit_before>
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Var(pub u64);

impl Var {
	pub fn to_u64(self) -> u64 { self.0 }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Sign { Pos, Neg }

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

impl Lit {
	pub fn from_i64(val: i64) -> Lit { Lit(val) }
	pub fn var(self) -> Var { Var(self.0.abs() as u64) }
	pub fn sign(self) -> Sign {
		match self.0 >= 0 {
			true => Sign::Pos,
			_    => Sign::Neg
		}
	}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Clause {
	lits: Box<[Lit]>
}

impl Clause {
	pub fn from_vec(lits: Vec<Lit>) -> Clause {
		Clause{
			lits: lits.into_boxed_slice()
		}
	}

	pub fn len(&self) -> usize {
		self.lits.len()
	}

	pub fn lits(&self) -> &[Lit] {
		&self.lits
	}
}

type FormulaBox  = Box<Formula>;
type FormulaList = Box<[Formula]>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Formula {
	Lit(Lit),
	Paren(FormulaBox),
	Neg(FormulaBox),
	And(FormulaList),
	Or(FormulaList),
	Xor(FormulaList),
	Eq(FormulaList)
}

impl Formula {
	pub fn lit(lit: Lit) -> Formula {
		Formula::Lit(lit)
	}

	pub fn paren(inner: Formula) -> Formula {
		Formula::Paren(Box::new(inner))
	}

	pub fn neg(inner: Formula) -> Formula {
		Formula::Neg(Box::new(inner))
	}

	pub fn and(params: Vec<Formula>) -> Formula {
		Formula::And(params.into_boxed_slice())
	}

	pub fn or(params: Vec<Formula>) -> Formula {
		Formula::Or(params.into_boxed_slice())
	}

	pub fn xor(params: Vec<Formula>) -> Formula {
		Formula::Xor(params.into_boxed_slice())
	}

	pub fn eq(params: Vec<Formula>) -> Formula {
		Formula::Eq(params.into_boxed_slice())
	}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Instance {
	Cnf{
		num_vars: u64,
		clauses: Box<[Clause]>
	},
	Sat{
		num_vars: u64,
		extensions: Extensions,
		formula: Formula
	}
}

impl Instance {
	pub fn cnf(num_vars: u64, clauses: Vec<Clause>) -> Instance {
		Instance::Cnf{num_vars: num_vars, clauses: clauses.into_boxed_slice()}
	}

	pub fn sat(num_vars: u64, extensions: Extensions, formula: Formula) -> Instance {
		Instance::Sat{num_vars: num_vars, extensions: extensions, formula: formula}
	}

	// pub fn sat(num_vars: u64, formula: Formula) -> Instance {
	// 	Instance::sat_with_ext(num_vars, vec![], formula)
	// }

	// pub fn satx(num_vars: u64, formula: Formula) -> Instance {
	// 	Instance::sat_with_ext(num_vars, vec![Extension::Xor], formula)
	// }

	// pub fn sate(num_vars: u64, formula: Formula) -> Instance {
	// 	Instance::sat_with_ext(num_vars, vec![Extension::Eq], formula)
	// }

	// pub fn satex(num_vars: u64, formula: Formula) -> Instance {
	// 	Instance::sat_with_ext(num_vars, vec![Extension::Eq, Extension::Xor], formula)
	// }
}

// #[derive(Debug, Copy, Clone, PartialEq, Eq)]
// pub enum Extension {
// 	Xor,
// 	Eq
// }

bitflags! {
    pub flags Extensions: u32 {
    	const NONE = 0b00000000,
        const XOR  = 0b00000001,
        const EQ   = 0b00000010
    }
}

// #[derive(Debug, Copy, Clone, PartialEq, Eq)]
// pub struct Extensions(Extension);

// impl Extensions {
// 	pub fn none() -> Extensions {
// 		Extensions(None)
// 	}

// 	pub fn from(ext: Extension) -> Extensions {}

// 	pub fn xor() -> Extensions {
// 		Extensions(Xor)
// 	}

// 	pub fn eq() -> Extensions {
// 		Extensions(Eq)
// 	}

// 	pub fn with_xor(self) -> Extensions {
// 		Extensions(self.0 | Xor)
// 	}

// 	pub fn with_eq(self) -> Extensions {
// 		Extensions(self.0 | Eq)
// 	}

// 	pub fn supports_xor(self) -> bool {
// 		self.0.contains(Xor)
// 	}

// 	pub fn supports_eq(self) -> bool {
// 		self.0.contains(Eq)
// 	}
// }

// #[derive(Debug, Clone, PartialEq, Eq)]
// pub enum Problem {
// 	Cnf{num_vars: u64, num_clauses: u64},
// 	Sat{num_vars: u64, extensions: Box<[Extension]>},
// }

// impl Problem {
// 	pub fn cnf(num_vars: u64, num_clauses: u64) -> Problem {
// 		Problem::Cnf{
// 			num_vars: num_vars,
// 			num_clauses: num_clauses
// 		}
// 	}

// 	fn with_extensions(num_vars: u64, extensions: &[Extension]) -> Problem {
// 		Problem::Sat{
// 			num_vars: num_vars,
// 			extensions: extensions.to_vec().into_boxed_slice()
// 		}
// 	}

// 	pub fn sat(num_vars: u64) -> Problem {
// 		Problem::with_extensions(num_vars, &[])
// 	}

// 	pub fn sat_eq(num_vars: u64) -> Problem {
// 		Problem::with_extensions(num_vars, &[Extension::Eq])
// 	}

// 	pub fn sat_xor(num_vars: u64) -> Problem {
// 		Problem::with_extensions(num_vars, &[Extension::Xor])
// 	}

// 	pub fn sat_ex(num_vars: u64) -> Problem {
// 		Problem::with_extensions(num_vars, &[Extension::Eq, Extension::Xor])
// 	}

// 	pub fn has_extension(&self, ext: Extension) -> bool {
// 		match self {
// 			&Problem::Cnf{..} => false,
// 			&Problem::Sat{ref extensions, ..} => extensions.contains(&ext)
// 		}
// 	}
// }
<commit_msg>removed some no-longer-required item definitions<commit_after>
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Var(pub u64);

impl Var {
	pub fn to_u64(self) -> u64 { self.0 }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Sign { Pos, Neg }

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

impl Lit {
	pub fn from_i64(val: i64) -> Lit { Lit(val) }
	pub fn var(self) -> Var { Var(self.0.abs() as u64) }
	pub fn sign(self) -> Sign {
		match self.0 >= 0 {
			true => Sign::Pos,
			_    => Sign::Neg
		}
	}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Clause {
	lits: Box<[Lit]>
}

impl Clause {
	pub fn from_vec(lits: Vec<Lit>) -> Clause {
		Clause{
			lits: lits.into_boxed_slice()
		}
	}

	pub fn len(&self) -> usize {
		self.lits.len()
	}

	pub fn lits(&self) -> &[Lit] {
		&self.lits
	}
}

type FormulaBox  = Box<Formula>;
type FormulaList = Box<[Formula]>;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Formula {
	Lit(Lit),
	Paren(FormulaBox),
	Neg(FormulaBox),
	And(FormulaList),
	Or(FormulaList),
	Xor(FormulaList),
	Eq(FormulaList)
}

impl Formula {
	pub fn lit(lit: Lit) -> Formula {
		Formula::Lit(lit)
	}

	pub fn paren(inner: Formula) -> Formula {
		Formula::Paren(Box::new(inner))
	}

	pub fn neg(inner: Formula) -> Formula {
		Formula::Neg(Box::new(inner))
	}

	pub fn and(params: Vec<Formula>) -> Formula {
		Formula::And(params.into_boxed_slice())
	}

	pub fn or(params: Vec<Formula>) -> Formula {
		Formula::Or(params.into_boxed_slice())
	}

	pub fn xor(params: Vec<Formula>) -> Formula {
		Formula::Xor(params.into_boxed_slice())
	}

	pub fn eq(params: Vec<Formula>) -> Formula {
		Formula::Eq(params.into_boxed_slice())
	}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Instance {
	Cnf{
		num_vars: u64,
		clauses: Box<[Clause]>
	},
	Sat{
		num_vars: u64,
		extensions: Extensions,
		formula: Formula
	}
}

impl Instance {
	pub fn cnf(num_vars: u64, clauses: Vec<Clause>) -> Instance {
		Instance::Cnf{num_vars: num_vars, clauses: clauses.into_boxed_slice()}
	}

	pub fn sat(num_vars: u64, extensions: Extensions, formula: Formula) -> Instance {
		Instance::Sat{num_vars: num_vars, extensions: extensions, formula: formula}
	}
}

bitflags! {
    pub flags Extensions: u32 {
    	const NONE = 0b00000000,
        const XOR  = 0b00000001,
        const EQ   = 0b00000010
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use regex::Regex;

#[repr(u32)]
#[derive(Debug, Clone)]
pub enum SubToken {
    Plus,
    Minus,
    Multiply,
    Divide,
    Power,
    Modulo,

    Number,

    LParen,
    RParen,

    End
}

#[derive(Debug, Clone)]
pub struct Token {
    kind: SubToken,
    value: Option<f64>
}

impl Token {
    pub fn new(kind: SubToken, value: Option<f64>) -> Self {
        Token{kind: kind, value: value}
    }
    pub fn set_kind(&mut self, kind: SubToken) {
        self.kind = kind;
    }
    pub fn set_value(&mut self, value: Option<f64>) {
        self.value = value;
    }
    pub fn get_kind(&self) -> SubToken {
        self.kind.clone()
    }
    pub fn get_value(&self) -> Option<f64> {
        self.value.clone()
    }
}

#[derive(Debug)]
pub struct Lexer {
    input: Option<String>,
    return_previous_token: bool,
    previous_token: Option<Token>,
}

impl Lexer {
    pub fn new() -> Self {
        Lexer{input: None, return_previous_token: false, previous_token: None}
    }
    pub fn set_input(&mut self, input: String) {
        self.input = Some(input);
    }
    pub fn get_next_token(&mut self) -> Result<Token, String> {
        if self.return_previous_token {
            self.return_previous_token = false;
            return match self.previous_token.clone() {
                Some(t) => Ok(t),
                None => Err(String::from("No previous token"))
            }
        }
        let mut strip_input = strip_white_space(self.input.clone().unwrap());
        lazy_static! {
            static ref PLUS_RE: Regex = Regex::new(r"\A\+").unwrap();
            static ref MINUS_RE: Regex = Regex::new(r"\A-").unwrap();
            static ref MULT_RE: Regex = Regex::new(r"\A\*").unwrap();
            static ref DIV_RE: Regex = Regex::new(r"\A/").unwrap();
            static ref POW_RE: Regex = Regex::new(r"\A\^").unwrap();
            static ref MOD_RE: Regex = Regex::new(r"\A%").unwrap();
            static ref NUM_RE: Regex = Regex::new(r"(\A\d+(\.\d+)?)|(\A(\.\d+))").unwrap();
            static ref LPAREN_RE: Regex = Regex::new(r"\A\(").unwrap();
            static ref RPAREN_RE: Regex = Regex::new(r"\A\)").unwrap();
        }
        let token: Token;
        let temp = &(strip_input.clone())[..];
        if PLUS_RE.is_match(temp) {
            strip_input = PLUS_RE.replace(temp, "");
            token = Token::new(SubToken::Plus, None);
        } else if MINUS_RE.is_match(temp) {
            strip_input = MINUS_RE.replace(temp, "");
            token = Token::new(SubToken::Minus, None);
        } else if MULT_RE.is_match(temp) {
            strip_input = MULT_RE.replace(temp, "");
            token = Token::new(SubToken::Multiply, None);
        } else if DIV_RE.is_match(temp) {
            strip_input = DIV_RE.replace(temp, "");
            token = Token::new(SubToken::Divide, None);
        } else if POW_RE.is_match(temp) {
            strip_input = POW_RE.replace(temp, "");
            token = Token::new(SubToken::Power, None);
        } else if MOD_RE.is_match(temp) {
            strip_input = MOD_RE.replace(temp, "");
            token = Token::new(SubToken::Modulo, None);
        } else if NUM_RE.is_match(temp) {
            use std::str::FromStr;
            let value: Option<f64> = f64::from_str(NUM_RE.captures(temp).unwrap().at(0).unwrap()).ok();
            strip_input = NUM_RE.replace(temp, "");
            token = Token::new(SubToken::Number, value);
        } else if LPAREN_RE.is_match(temp) {
            strip_input = LPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::LParen, None);
        } else if RPAREN_RE.is_match(temp) {
            strip_input = RPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::RParen, None);
        } else if strip_input.is_empty() {
            token = Token::new(SubToken::End, None);
        } else {
            let mut error: String = String::from("Unknown token: ");
            error.push_str(temp);
            return Err(error);
        }
        self.input = Some(strip_input);
        self.previous_token = Some(token.clone());
        Ok(token)
    }
    pub fn revert(&mut self) {
        self.return_previous_token = true;
    }
}

fn strip_white_space(input: String) -> String {
    input.split_whitespace().collect::<Vec<&str>>().join("")
}
<commit_msg>Remove white space stripping code. Move to Parser<commit_after>#![allow(dead_code)]

use regex::Regex;

#[repr(u32)]
#[derive(Debug, Clone)]
pub enum SubToken {
    Plus,
    Minus,
    Multiply,
    Divide,
    Power,
    Modulo,

    Number,

    LParen,
    RParen,

    End
}

#[derive(Debug, Clone)]
pub struct Token {
    kind: SubToken,
    value: Option<f64>
}

impl Token {
    pub fn new(kind: SubToken, value: Option<f64>) -> Self {
        Token{kind: kind, value: value}
    }
    pub fn set_kind(&mut self, kind: SubToken) {
        self.kind = kind;
    }
    pub fn set_value(&mut self, value: Option<f64>) {
        self.value = value;
    }
    pub fn get_kind(&self) -> SubToken {
        self.kind.clone()
    }
    pub fn get_value(&self) -> Option<f64> {
        self.value.clone()
    }
}

#[derive(Debug)]
pub struct Lexer {
    input: Option<String>,
    return_previous_token: bool,
    previous_token: Option<Token>,
}

impl Lexer {
    pub fn new() -> Self {
        Lexer{input: None, return_previous_token: false, previous_token: None}
    }
    pub fn set_input(&mut self, input: String) {
        self.input = Some(input);
    }
    pub fn get_next_token(&mut self) -> Result<Token, String> {
        if self.return_previous_token {
            self.return_previous_token = false;
            return match self.previous_token.clone() {
                Some(t) => Ok(t),
                None => Err(String::from("No previous token"))
            }
        }
        let mut strip_input = self.input.clone().unwrap();
        lazy_static! {
            static ref PLUS_RE: Regex = Regex::new(r"\A\+").unwrap();
            static ref MINUS_RE: Regex = Regex::new(r"\A-").unwrap();
            static ref MULT_RE: Regex = Regex::new(r"\A\*").unwrap();
            static ref DIV_RE: Regex = Regex::new(r"\A/").unwrap();
            static ref POW_RE: Regex = Regex::new(r"\A\^").unwrap();
            static ref MOD_RE: Regex = Regex::new(r"\A%").unwrap();
            static ref NUM_RE: Regex = Regex::new(r"(\A\d+(\.\d+)?)|(\A(\.\d+))").unwrap();
            static ref LPAREN_RE: Regex = Regex::new(r"\A\(").unwrap();
            static ref RPAREN_RE: Regex = Regex::new(r"\A\)").unwrap();
        }
        let token: Token;
        let temp = &(strip_input.clone())[..];
        if PLUS_RE.is_match(temp) {
            strip_input = PLUS_RE.replace(temp, "");
            token = Token::new(SubToken::Plus, None);
        } else if MINUS_RE.is_match(temp) {
            strip_input = MINUS_RE.replace(temp, "");
            token = Token::new(SubToken::Minus, None);
        } else if MULT_RE.is_match(temp) {
            strip_input = MULT_RE.replace(temp, "");
            token = Token::new(SubToken::Multiply, None);
        } else if DIV_RE.is_match(temp) {
            strip_input = DIV_RE.replace(temp, "");
            token = Token::new(SubToken::Divide, None);
        } else if POW_RE.is_match(temp) {
            strip_input = POW_RE.replace(temp, "");
            token = Token::new(SubToken::Power, None);
        } else if MOD_RE.is_match(temp) {
            strip_input = MOD_RE.replace(temp, "");
            token = Token::new(SubToken::Modulo, None);
        } else if NUM_RE.is_match(temp) {
            use std::str::FromStr;
            let value: Option<f64> = f64::from_str(NUM_RE.captures(temp).unwrap().at(0).unwrap()).ok();
            strip_input = NUM_RE.replace(temp, "");
            token = Token::new(SubToken::Number, value);
        } else if LPAREN_RE.is_match(temp) {
            strip_input = LPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::LParen, None);
        } else if RPAREN_RE.is_match(temp) {
            strip_input = RPAREN_RE.replace(temp, "");
            token = Token::new(SubToken::RParen, None);
        } else if strip_input.is_empty() {
            token = Token::new(SubToken::End, None);
        } else {
            let mut error: String = String::from("Unknown token: ");
            error.push_str(temp);
            return Err(error);
        }
        self.input = Some(strip_input);
        self.previous_token = Some(token.clone());
        Ok(token)
    }
    pub fn revert(&mut self) {
        self.return_previous_token = true;
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::{self, Error};
use std::mem;

use libc::{
    c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr, sockaddr_ll, socket,
    socklen_t, AF_AX25, AF_PACKET, SOCK_RAW,
};

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(":").next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = mem::transmute::<*const sockaddr_ll, *const sockaddr>(&sa);
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = mem::transmute::<*mut sockaddr_ll, *mut sockaddr>(&mut addr_struct);
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let ref valid_buf = buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf
            .into_iter()
            .skip_while(|&c| *c == 0)
            .cloned()
            .collect();
        Ok(filtered)
    }
}

fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Some(addr) = String::from_utf8(addr_utf8).ok() {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<commit_msg>Fix more lints, useless transmutes<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::{self, Error};
use std::mem;

use libc::{
    c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t,
    AF_AX25, AF_PACKET, SOCK_RAW,
};

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let ref valid_buf = buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf
            .into_iter()
            .skip_while(|&c| *c == 0)
            .cloned()
            .collect();
        Ok(filtered)
    }
}

fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Some(addr) = String::from_utf8(addr_utf8).ok() {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_ls"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jeremiah Peschka <jeremiah.peschka@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate pretty_bytes;
use pretty_bytes::converter::convert;

#[macro_use]
extern crate uucore;

use getopts::Options;
use std::fs;
use std::fs::{ReadDir, DirEntry, FileType, Metadata};
use std::ffi::{OsString};
use std::path::Path;
use std::io::Write;

#[derive(Copy, Clone, PartialEq)]
enum Mode {
    Help,
    Version,
    List
}

static NAME: &'static str = "ls";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");

    opts.optflag("a", "all", "Do not ignore hidden files (files with names that start with '.').");
    opts.optflag("A", "almost-all", "In a directory, do not ignore all file names that start with '.', only ignore '.' and '..'.");
    opts.optflag("B", "ignore-backups", "Ignore files that end with ~. Equivalent to using `--ignore='*~'` or `--ignore='.*~'.");
    opts.optflag("d", "directory", "Only list the names of directories, rather than listing directory contents. This will not follow symbolic links unless one of `--dereference-command-line (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is specified.");
    opts.optflag("H", "dereference-command-line", "If a command line argument specifies a symbolic link, show information about the linked file rather than the link itself.");
    opts.optflag("h", "human-readable", "Print human readable file sizes (e.g. 1K 234M 56G).");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            show_error!("{}", e);
            panic!()
        },
    };

    let mode = if matches.opt_present("version") {
        Mode::Version
    } else if matches.opt_present("help") {
        Mode::Help
    } else {
        Mode::List
    };

    match mode {
        Mode::Version => version(),
        Mode::Help    => help(),
        Mode::List    => list(matches)
    }

    0
}

fn version() {
     println!("{} {}", NAME, VERSION);
}

fn help() {
    let msg = format!("{0} {1}\n\n\
                       Usage:  {0} [OPTION]... DIRECTORY \n   \
                          or:  {0} [OPTION]... [FILE]... \n \
                       \n \
                       By default, ls will list the files and contents of any directories on \
                       the command line, expect that it will ignore files and directories \
                       whose names start with '.'. \n\
                       \n", NAME, VERSION);
    println!("{}", msg);
}

fn list(options: getopts::Matches) {
    let locs: Vec<String> = if options.free.is_empty() {
        vec![String::from(".")]
    } else {
        options.free.iter().cloned().collect()
    };

    for loc in locs {
        let p = Path::new(&loc);

        if !p.exists() {
            show_error!("Cannot find path '{}' because it does not exist.", loc);
            panic!();
        }

        if p.is_dir() {
            match fs::read_dir(p) {
                Err(e)      => {
                    show_error!("Cannot read directory '{}'. \n Reason: {}", loc, e);
                    panic!();
                },
                Ok(entries) => enter_directory(entries, &options),
            };
        }

        if p.is_file() {
            display_item(Path::new(p), &options)
        }
    }
}

fn enter_directory(contents: ReadDir, options: &getopts::Matches) {
    for entry in contents {
        let entry = match entry {
            Err(err) => {
                show_error!("{}", err);
                panic!();
            },
            Ok(en) => en
        };

        // Currently have a DirEntry that we can believe in.
        display_dir_entry(entry, options);
    }
}

fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) {
    let md = match entry.metadata() {
        Err(e) => {
            show_error!("Unable to retrieve metadata for {}. \n Error: {}",
                        display_file_name(entry.file_name()), e);
            panic!();
        },
        Ok(md) => md
    };

    println!(" {}{} {} somebody somegroup {: >9} {}",
             display_file_type(entry.file_type()),
             display_permissions(&md),
             display_symlink_count(&md),
             display_file_size(&md, options),
             display_file_name(entry.file_name())
            );
}

fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String {
    if options.opt_present("human-readable") {
        convert(metadata.len() as f64)
    } else {
        metadata.len().to_string()
    }
}

fn display_file_type(file_type: Result<FileType, std::io::Error>) -> String {
    let file_type = match file_type {
        Err(e) => {
            show_error!("{}", e);
            panic!()
        },
        Ok(ft) => ft
    };

    if file_type.is_dir() {
        "d".to_string()
    } else if file_type.is_symlink() {
        "l".to_string()
    } else {
        "-".to_string()
    }
}

fn display_file_name(name: OsString) -> String {
    name.to_string_lossy().into_owned()
}

#[cfg(target_family = "windows")]
#[allow(unused_variables)]
fn display_symlink_count(metadata: &Metadata) -> String {
    // Currently not sure of how to get this on Windows, so I'm punting.
    // Git Bash looks like it may do the same thing.
    String::from("1")
}

#[cfg(target_family = "unix")]
fn display_symlink_count(metadata: &Metadata) -> String {
    use std::os::unix::fs::MetadataExt;

    md.nlink().to_string()
}

#[cfg(target_family = "windows")]
#[allow(unused_variables)]
fn display_permissions(metadata: &Metadata) -> String {
    String::from("---------")
}

#[cfg(target_family = "unix")]
fn display_permissions(metadata: &Metadata) -> String {
    use std::os::unix::fs::PermissionsExt;

    "lolwtfbbq".to_string();
}

// fn list_directory_contents(directory: &Path, options: &getopts::Matches) {
//     let rd = fs::read_dir(directory);

//     match rd {
//         Err(err) => println!("ERROR! {}", err),
//         Ok(entries) => display_directory_contents(entries, &options),
//     }
// }

// fn display_directory_contents(contents: ReadDir, options: &getopts::Matches) {
//     for entry in contents {
//         let entry = match entry {
//             Err(err) => {
//                 println!("ERROR! {}", err);
//                 panic!()
//             },
//             Ok(en) => en
//         };
//         display_item(entry.path().as_path(), &options);
//     }
// }

fn display_item(item: &Path, options: &getopts::Matches) {
    // let fileType = item.file
    // let mut fileMeta = String::new();

    // fileMeta = fileMeta + if item.is_dir() {
    //                             "d"
    // } else if item.sy
    //                         } else {
    //                             "-"
    //                         };

    // println!("{}{}", displayString, item.display());
}<commit_msg>Changed display_symlink_count to use the right variable name. Removed dead code.<commit_after>#![crate_name = "uu_ls"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jeremiah Peschka <jeremiah.peschka@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate pretty_bytes;
use pretty_bytes::converter::convert;

#[macro_use]
extern crate uucore;

use getopts::Options;
use std::fs;
use std::fs::{ReadDir, DirEntry, FileType, Metadata};
use std::ffi::{OsString};
use std::path::Path;
use std::io::Write;

#[derive(Copy, Clone, PartialEq)]
enum Mode {
    Help,
    Version,
    List
}

static NAME: &'static str = "ls";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("", "help", "display this help and exit");
    opts.optflag("", "version", "output version information and exit");

    opts.optflag("a", "all", "Do not ignore hidden files (files with names that start with '.').");
    opts.optflag("A", "almost-all", "In a directory, do not ignore all file names that start with '.', only ignore '.' and '..'.");
    opts.optflag("B", "ignore-backups", "Ignore files that end with ~. Equivalent to using `--ignore='*~'` or `--ignore='.*~'.");
    opts.optflag("d", "directory", "Only list the names of directories, rather than listing directory contents. This will not follow symbolic links unless one of `--dereference-command-line (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is specified.");
    opts.optflag("H", "dereference-command-line", "If a command line argument specifies a symbolic link, show information about the linked file rather than the link itself.");
    opts.optflag("h", "human-readable", "Print human readable file sizes (e.g. 1K 234M 56G).");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            show_error!("{}", e);
            panic!()
        },
    };

    let mode = if matches.opt_present("version") {
        Mode::Version
    } else if matches.opt_present("help") {
        Mode::Help
    } else {
        Mode::List
    };

    match mode {
        Mode::Version => version(),
        Mode::Help    => help(),
        Mode::List    => list(matches)
    }

    0
}

fn version() {
     println!("{} {}", NAME, VERSION);
}

fn help() {
    let msg = format!("{0} {1}\n\n\
                       Usage:  {0} [OPTION]... DIRECTORY \n   \
                          or:  {0} [OPTION]... [FILE]... \n \
                       \n \
                       By default, ls will list the files and contents of any directories on \
                       the command line, expect that it will ignore files and directories \
                       whose names start with '.'. \n\
                       \n", NAME, VERSION);
    println!("{}", msg);
}

fn list(options: getopts::Matches) {
    let locs: Vec<String> = if options.free.is_empty() {
        vec![String::from(".")]
    } else {
        options.free.iter().cloned().collect()
    };

    for loc in locs {
        let p = Path::new(&loc);

        if !p.exists() {
            show_error!("Cannot find path '{}' because it does not exist.", loc);
            panic!();
        }

        if p.is_dir() {
            match fs::read_dir(p) {
                Err(e)      => {
                    show_error!("Cannot read directory '{}'. \n Reason: {}", loc, e);
                    panic!();
                },
                Ok(entries) => enter_directory(entries, &options),
            };
        }

        if p.is_file() {
            display_item(Path::new(p), &options)
        }
    }
}

fn enter_directory(contents: ReadDir, options: &getopts::Matches) {
    for entry in contents {
        let entry = match entry {
            Err(err) => {
                show_error!("{}", err);
                panic!();
            },
            Ok(en) => en
        };

        // Currently have a DirEntry that we can believe in.
        display_dir_entry(entry, options);
    }
}

fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) {
    let md = match entry.metadata() {
        Err(e) => {
            show_error!("Unable to retrieve metadata for {}. \n Error: {}",
                        display_file_name(entry.file_name()), e);
            panic!();
        },
        Ok(md) => md
    };

    println!(" {}{} {} somebody somegroup {: >9} {}",
             display_file_type(entry.file_type()),
             display_permissions(&md),
             display_symlink_count(&md),
             display_file_size(&md, options),
             display_file_name(entry.file_name())
            );
}

fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String {
    if options.opt_present("human-readable") {
        convert(metadata.len() as f64)
    } else {
        metadata.len().to_string()
    }
}

fn display_file_type(file_type: Result<FileType, std::io::Error>) -> String {
    let file_type = match file_type {
        Err(e) => {
            show_error!("{}", e);
            panic!()
        },
        Ok(ft) => ft
    };

    if file_type.is_dir() {
        "d".to_string()
    } else if file_type.is_symlink() {
        "l".to_string()
    } else {
        "-".to_string()
    }
}

fn display_file_name(name: OsString) -> String {
    name.to_string_lossy().into_owned()
}

#[cfg(target_family = "windows")]
#[allow(unused_variables)]
fn display_symlink_count(metadata: &Metadata) -> String {
    // Currently not sure of how to get this on Windows, so I'm punting.
    // Git Bash looks like it may do the same thing.
    String::from("1")
}

#[cfg(target_family = "unix")]
fn display_symlink_count(metadata: &Metadata) -> String {
    use std::os::unix::fs::MetadataExt;

    metadata.nlink().to_string()
}

#[cfg(target_family = "windows")]
#[allow(unused_variables)]
fn display_permissions(metadata: &Metadata) -> String {
    String::from("---------")
}

#[cfg(target_family = "unix")]
fn display_permissions(metadata: &Metadata) -> String {
    use std::os::unix::fs::PermissionsExt;

    "xxxxxxxxx".to_string();
}

fn display_item(item: &Path, options: &getopts::Matches) {
    // let fileType = item.file
    // let mut fileMeta = String::new();

    // fileMeta = fileMeta + if item.is_dir() {
    //                             "d"
    // } else if item.sy
    //                         } else {
    //                             "-"
    //                         };

    // println!("{}{}", displayString, item.display());
}<|endoftext|>