<commit_before>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;

use base64;

use error::{HubError, HubResult};

#[derive(Debug, Deserialize, Serialize)]
pub struct App {
    pub id: u32,
    pub owner: AppOwner,
    pub name: String,
    pub description: String,
    pub external_url: String,
    pub html_url: String,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Deserialize, Serialize)]
pub struct AppInstallationToken {
    pub token: String,
    pub expires_at: String,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct AppAuthErr {
    pub message: String,
    pub documentation_url: String,
}

impl fmt::Display for AppAuthErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "message={}, documentation_url={}",
            self.message,
            self.documentation_url
        )
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuthOk {
    pub access_token: String,
    pub scope: String,
    pub token_type: String,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct AuthErr {
    pub error: String,
    pub error_description: String,
    pub error_uri: String,
}

impl fmt::Display for AuthErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "err={}, desc={}, uri={}",
            self.error,
            self.error_description,
            self.error_uri
        )
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AppOwner {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub gravatar_id: String,
    pub url: String,
    pub html_url: String,
    pub followers_url: String,
    pub following_url: String,
    pub gists_url: String,
    pub starred_url: String,
    pub subscriptions_url: String,
    pub organizations_url: String,
    pub repos_url: String,
    pub events_url: String,
    pub received_events_url: String,
    #[serde(rename = "type")]
    pub _type: String,
    pub site_admin: bool,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Contents {
    pub name: String,
    pub path: String,
    pub sha: String,
    pub size: usize,
    pub url: String,
    pub html_url: String,
    pub git_url: String,
    pub download_url: String,
    pub content: String,
    pub encoding: String,
}

impl Contents {
    pub fn decode(&self) -> HubResult<Vec<u8>> {
        base64::decode(&self.content).map_err(HubError::ContentDecode)
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubWebhookPush {
    /// The full Git ref that was pushed. Example: "refs/heads/master"
    #[serde(rename = "ref")]
    pub git_ref: String,
    /// The SHA of the most recent commit on ref before the push
    pub before: String,
    /// The SHA of the most recent commit on ref after the push
    pub after: String,
    pub created: bool,
    pub deleted: bool,
    pub forced: bool,
    pub base_ref: Option<String>,
    pub compare: String,
    /// An array of commit objects describing the pushed commits (The array includes a maximum
    /// of 20 commits. If necessary, you can use the Commits API to fetch additional commits.
    /// This limit is applied to timeline events only and isn't applied to webhook deliveries)
    pub commits: Vec<GitHubWebhookCommit>,
    pub head_commit: GitHubWebhookCommit,
    pub repository: PushRepository,
    pub pusher: GitHubOwner,
    pub sender: GitHubWebhookSender,
    pub installation: GitHubAppInstallation,
}

impl GitHubWebhookPush {
    pub fn changed(&self) -> Vec<&String> {
        let mut paths = vec![];
        for commit in self.commits.iter() {
            paths.extend(&commit.added);
            paths.extend(&commit.removed);
            paths.extend(&commit.modified);
        }
        paths.sort();
        paths.dedup();
        paths
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubWebhookCommit {
    pub id: String,
    pub tree_id: String,
    /// Whether this commit is distinct from any that have been pushed before
    pub distinct: bool,
    /// The commit message
    pub message: String,
    pub timestamp: String,
    /// Points to the commit API resource
    pub url: String,
    /// The git author of the commit
    pub author: GitHubAuthor,
    pub committer: GitHubAuthor,
    pub added: Vec<String>,
    pub removed: Vec<String>,
    pub modified: Vec<String>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubAuthor {
    /// Public name of commit author
    pub name: String,
    /// Public email of commit author
    pub email: String,
    /// Display name of commit author
    pub username: String,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct GitHubAppInstallation {
    pub id: u32,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubWebhookSender {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub gravatar_id: Option<String>,
    pub url: String,
    pub html_url: String,
    pub followers_url: String,
    pub following_url: String,
    pub gists_url: String,
    pub starred_url: String,
    pub subscriptions_url: String,
    pub organizations_url: String,
    pub repos_url: String,
    pub events_url: String,
    pub received_events_url: String,
    pub site_admin: bool,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubOwner {
    /// Public name of commit author
    pub name: String,
    /// Public email of commit author
    pub email: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct PushRepository {
    pub id: u32,
    pub name: String,
    pub full_name: String,
    pub owner: Organization,
    pub private: bool,
    pub html_url: String,
    pub description: Option<String>,
    pub fork: bool,
    pub git_url: String,
    pub ssh_url: String,
    pub clone_url: String,
    pub default_branch: String,
    pub master_branch: String,
    pub organization: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Repository {
    pub id: u32,
    pub name: String,
    pub full_name: String,
    pub owner: User,
    pub private: bool,
    pub html_url: String,
    pub description: Option<String>,
    pub fork: bool,
    pub git_url: String,
    pub ssh_url: String,
    pub clone_url: String,
    pub default_branch: String,
    pub master_branch: String,
    pub organization: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Organization {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub url: String,
    pub company: Option<String>,
    pub description: Option<String>,
    pub gravatar_id: Option<String>,
    pub hooks_url: Option<String>,
    pub html_url: Option<String>,
    pub followers_url: Option<String>,
    pub following_url: Option<String>,
    pub gists_url: Option<String>,
    pub starred_url: Option<String>,
    pub subscriptions_url: Option<String>,
    pub organizations_url: Option<String>,
    pub repos_url: Option<String>,
    pub events_url: Option<String>,
    pub received_events_url: Option<String>,
    pub members_url: Option<String>,
    pub site_admin: Option<bool>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Team {
    pub id: u32,
    pub url: String,
    pub name: String,
    pub slug: String,
    pub description: Option<String>,
    pub privacy: String,
    pub permission: String,
    pub members_url: String,
    pub repositories_url: String,
    pub members_count: u32,
    pub repos_count: u32,
    pub organization: Organization,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct User {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub gravatar_id: String,
    pub url: String,
    pub html_url: String,
    pub followers_url: String,
    pub following_url: String,
    pub gists_url: String,
    pub starred_url: String,
    pub subscriptions_url: String,
    pub organizations_url: String,
    pub repos_url: String,
    pub events_url: String,
    pub received_events_url: String,
    pub name: Option<String>,
    pub company: Option<String>,
    pub blog: Option<String>,
    pub location: Option<String>,
    pub email: Option<String>,
    pub hireable: Option<bool>,
    pub bio: Option<String>,
    pub public_repos: Option<u32>,
    pub public_gists: Option<u32>,
    pub followers: Option<u32>,
    pub following: Option<u32>,
    pub created_at: Option<String>,
    pub updated_at: Option<String>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct UserPlan {
    pub name: String,
    pub space: u32,
    pub private_repos: u32,
    pub collaborators: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Search {
    pub total_count: u32,
    pub incomplete_results: bool,
    pub items: Vec<SearchItem>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct SearchItem {
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub repository: Repository,
    pub score: f32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TeamMembership {
    pub url: String,
    pub role: String,
    pub state: String,
}

impl TeamMembership {
    pub fn active(&self) -> bool {
        self.state == "active"
    }
}
<commit_msg>GitHub type fix<commit_after>// Copyright (c) 2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;

use base64;

use error::{HubError, HubResult};

#[derive(Debug, Deserialize, Serialize)]
pub struct App {
    pub id: u32,
    pub owner: AppOwner,
    pub name: String,
    pub description: String,
    pub external_url: String,
    pub html_url: String,
    pub created_at: String,
    pub updated_at: String,
}

#[derive(Deserialize, Serialize)]
pub struct AppInstallationToken {
    pub token: String,
    pub expires_at: String,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct AppAuthErr {
    pub message: String,
    pub documentation_url: String,
}

impl fmt::Display for AppAuthErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "message={}, documentation_url={}",
            self.message,
            self.documentation_url
        )
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AuthOk {
    pub access_token: String,
    pub scope: String,
    pub token_type: String,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct AuthErr {
    pub error: String,
    pub error_description: String,
    pub error_uri: String,
}

impl fmt::Display for AuthErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "err={}, desc={}, uri={}",
            self.error,
            self.error_description,
            self.error_uri
        )
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AppOwner {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub gravatar_id: String,
    pub url: String,
    pub html_url: String,
    pub followers_url: String,
    pub following_url: String,
    pub gists_url: String,
    pub starred_url: String,
    pub subscriptions_url: String,
    pub organizations_url: String,
    pub repos_url: String,
    pub events_url: String,
    pub received_events_url: String,
    #[serde(rename = "type")]
    pub _type: String,
    pub site_admin: bool,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Contents {
    pub name: String,
    pub path: String,
    pub sha: String,
    pub size: usize,
    pub url: String,
    pub html_url: String,
    pub git_url: String,
    pub download_url: String,
    pub content: String,
    pub encoding: String,
}

impl Contents {
    pub fn decode(&self) -> HubResult<Vec<u8>> {
        base64::decode(&self.content).map_err(HubError::ContentDecode)
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubWebhookPush {
    /// The full Git ref that was pushed. Example: "refs/heads/master"
    #[serde(rename = "ref")]
    pub git_ref: String,
    /// The SHA of the most recent commit on ref before the push
    pub before: String,
    /// The SHA of the most recent commit on ref after the push
    pub after: String,
    pub created: bool,
    pub deleted: bool,
    pub forced: bool,
    pub base_ref: Option<String>,
    pub compare: String,
    /// An array of commit objects describing the pushed commits (The array includes a maximum
    /// of 20 commits. If necessary, you can use the Commits API to fetch additional commits.
    /// This limit is applied to timeline events only and isn't applied to webhook deliveries)
    pub commits: Vec<GitHubWebhookCommit>,
    pub head_commit: GitHubWebhookCommit,
    pub repository: PushRepository,
    pub pusher: GitHubOwner,
    pub sender: GitHubWebhookSender,
    pub installation: GitHubAppInstallation,
}

impl GitHubWebhookPush {
    pub fn changed(&self) -> Vec<&String> {
        let mut paths = vec![];
        for commit in self.commits.iter() {
            paths.extend(&commit.added);
            paths.extend(&commit.removed);
            paths.extend(&commit.modified);
        }
        paths.sort();
        paths.dedup();
        paths
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubWebhookCommit {
    pub id: String,
    pub tree_id: String,
    /// Whether this commit is distinct from any that have been pushed before
    pub distinct: bool,
    /// The commit message
    pub message: String,
    pub timestamp: String,
    /// Points to the commit API resource
    pub url: String,
    /// The git author of the commit
    pub author: GitHubAuthor,
    pub committer: GitHubAuthor,
    pub added: Vec<String>,
    pub removed: Vec<String>,
    pub modified: Vec<String>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubAuthor {
    /// Public name of commit author
    pub name: String,
    /// Public email of commit author
    pub email: String,
    /// Display name of commit author
    pub username: String,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct GitHubAppInstallation {
    pub id: u32,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubWebhookSender {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub gravatar_id: Option<String>,
    pub url: String,
    pub html_url: String,
    pub followers_url: String,
    pub following_url: String,
    pub gists_url: String,
    pub starred_url: String,
    pub subscriptions_url: String,
    pub organizations_url: String,
    pub repos_url: String,
    pub events_url: String,
    pub received_events_url: String,
    pub site_admin: bool,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct GitHubOwner {
    /// Public name of commit author
    pub name: String,
    /// Public email of commit author
    pub email: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct PushRepository {
    pub id: u32,
    pub name: String,
    pub full_name: String,
    pub owner: Organization,
    pub private: bool,
    pub html_url: String,
    pub description: Option<String>,
    pub fork: bool,
    pub git_url: String,
    pub ssh_url: String,
    pub clone_url: String,
    pub default_branch: String,
    pub master_branch: String,
    pub organization: String,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Repository {
    pub id: u32,
    pub name: String,
    pub full_name: String,
    pub owner: User,
    pub private: bool,
    pub html_url: String,
    pub description: Option<String>,
    pub fork: bool,
    pub git_url: String,
    pub ssh_url: String,
    pub clone_url: String,
    pub default_branch: String,
    pub master_branch: String,
    pub organization: Organization,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Organization {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub url: String,
    pub company: Option<String>,
    pub description: Option<String>,
    pub gravatar_id: Option<String>,
    pub hooks_url: Option<String>,
    pub html_url: Option<String>,
    pub followers_url: Option<String>,
    pub following_url: Option<String>,
    pub gists_url: Option<String>,
    pub starred_url: Option<String>,
    pub subscriptions_url: Option<String>,
    pub organizations_url: Option<String>,
    pub repos_url: Option<String>,
    pub events_url: Option<String>,
    pub received_events_url: Option<String>,
    pub members_url: Option<String>,
    pub site_admin: Option<bool>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Team {
    pub id: u32,
    pub url: String,
    pub name: String,
    pub slug: String,
    pub description: Option<String>,
    pub privacy: String,
    pub permission: String,
    pub members_url: String,
    pub repositories_url: String,
    pub members_count: u32,
    pub repos_count: u32,
    pub organization: Organization,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct User {
    pub login: String,
    pub id: u32,
    pub avatar_url: String,
    pub gravatar_id: String,
    pub url: String,
    pub html_url: String,
    pub followers_url: String,
    pub following_url: String,
    pub gists_url: String,
    pub starred_url: String,
    pub subscriptions_url: String,
    pub organizations_url: String,
    pub repos_url: String,
    pub events_url: String,
    pub received_events_url: String,
    pub name: Option<String>,
    pub company: Option<String>,
    pub blog: Option<String>,
    pub location: Option<String>,
    pub email: Option<String>,
    pub hireable: Option<bool>,
    pub bio: Option<String>,
    pub public_repos: Option<u32>,
    pub public_gists: Option<u32>,
    pub followers: Option<u32>,
    pub following: Option<u32>,
    pub created_at: Option<String>,
    pub updated_at: Option<String>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct UserPlan {
    pub name: String,
    pub space: u32,
    pub private_repos: u32,
    pub collaborators: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Search {
    pub total_count: u32,
    pub incomplete_results: bool,
    pub items: Vec<SearchItem>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct SearchItem {
    pub name: String,
    pub path: String,
    pub sha: String,
    pub url: String,
    pub git_url: String,
    pub html_url: String,
    pub repository: Repository,
    pub score: f32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TeamMembership {
    pub url: String,
    pub role: String,
    pub state: String,
}

impl TeamMembership {
    pub fn active(&self) -> bool {
        self.state == "active"
    }
}
<|endoftext|>


<commit_before>//! Enabling and disabling interrupts

/// Returns whether interrupts are enabled.
pub fn are_enabled() -> bool {
    use registers::rflags::{self, RFlags};

    rflags::read().contains(RFlags::INTERRUPT_FLAG)
}

/// Enable interrupts.
///
/// This is a wrapper around the `sti` instruction.
pub fn enable() {
    unsafe {
        asm!("sti");
    }
}

/// Disable interrupts.
///
/// This is a wrapper around the `cli` instruction.
pub fn disable() {
    unsafe {
        asm!("cli");
    }
}

/// Run a closue with disabled interrupts.
///
/// Run the given closure, disabling interrupts before running it (if they aren't already disabled).
/// Afterwards, interrupts are enabling again if they were enabled before.
///
/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected.
///
/// # Examples
///
/// ```rust
/// // interrupts are enabled
/// without_interrupts(|| {
///     // interrupts are disabled
///     without_interrupts(|| {
///         // interrupts are disabled
///     });
///     // interrupts are still disabled
/// });
/// // interrupts are enabled again
/// ```
pub fn without_interrupts<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    // true if the interrupt flag is set (i.e. interrupts are enabled)
    let saved_intpt_flag = are_enabled();

    // if interrupts are enabled, disable them for now
    if saved_intpt_flag {
        disable();
    }

    // do `f` while interrupts are disabled
    let ret = f();

    // re-enable interrupts if they were previously enabled
    if saved_intpt_flag {
        enable();
    }

    // return the result of `f` to the caller
    ret
}
<commit_msg>Don't test example of interrupt documentation<commit_after>//! Enabling and disabling interrupts

/// Returns whether interrupts are enabled.
pub fn are_enabled() -> bool {
    use registers::rflags::{self, RFlags};

    rflags::read().contains(RFlags::INTERRUPT_FLAG)
}

/// Enable interrupts.
///
/// This is a wrapper around the `sti` instruction.
pub fn enable() {
    unsafe {
        asm!("sti");
    }
}

/// Disable interrupts.
///
/// This is a wrapper around the `cli` instruction.
pub fn disable() {
    unsafe {
        asm!("cli");
    }
}

/// Run a closue with disabled interrupts.
///
/// Run the given closure, disabling interrupts before running it (if they aren't already disabled).
/// Afterwards, interrupts are enabling again if they were enabled before.
///
/// If you have other `enable` and `disable` calls _within_ the closure, things may not work as expected.
///
/// # Examples
///
/// ```ignore
/// // interrupts are enabled
/// without_interrupts(|| {
///     // interrupts are disabled
///     without_interrupts(|| {
///         // interrupts are disabled
///     });
///     // interrupts are still disabled
/// });
/// // interrupts are enabled again
/// ```
pub fn without_interrupts<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    // true if the interrupt flag is set (i.e. interrupts are enabled)
    let saved_intpt_flag = are_enabled();

    // if interrupts are enabled, disable them for now
    if saved_intpt_flag {
        disable();
    }

    // do `f` while interrupts are disabled
    let ret = f();

    // re-enable interrupts if they were previously enabled
    if saved_intpt_flag {
        enable();
    }

    // return the result of `f` to the caller
    ret
}
<|endoftext|>


<commit_before>// ref: https://github.com/memcached/memcached/blob/master/doc/protocol.txt

// Request structs

#[derive(Debug, PartialEq, Clone)]
pub struct Get {
    pub key: String,
}

impl Get {
    pub fn new(key: &str) -> Get {
        Get { key: key.to_string() }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Set {
    pub key: String, // alphanumeric characters
    pub flags: u16, // arbitrary bit pattern chosen by the client
    pub exptime: u32, // relative (secs) or absolute (unixtime) expiry time
    pub data: Vec<u8>, // binary data
    pub noreply: bool, // indicates whether the server should reply to the set
}

impl Set {
    pub fn new(key: &str,
               flags: u16,
               exptime: u32,
               data: Vec<u8>,
               noreply: bool)
               -> Set {
        Set {
            key: key.to_string(),
            flags: flags,
            exptime: exptime,
            data: data,
            noreply: noreply,
        }
    }
}

// Response structs

#[derive(Debug, PartialEq, Clone)]
pub struct ClientError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ServerError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Stat {
    pub key: String,
    pub value: String,
}

impl Stat {
    pub fn new(key: &str, value: String) -> Stat {
        Stat {
            key: key.to_string(),
            value: value,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Value {
    pub key: String,
    pub flags: u16,
    pub data: Vec<u8>,
}

impl Value {
    pub fn new(key: &str, flags: u16, data: Vec<u8>) -> Value {
        Value {
            key: key.to_string(),
            flags: flags,
            data: data,
        }
    }
}

// High level groupings

#[derive(Debug, PartialEq, Clone)]
pub enum Cmd {
    Get(Get),
    Set(Set),
    Stats,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Resp {
    // A sentinel value to indicate that there is nothing to return to the
    // client (in case of noreply)
    Empty,

    Error,
    ClientError(ClientError),
    ServerError(ServerError),

    Stats(Vec<Stat>),
    Stored,
    Value(Value),
}
<commit_msg>flesh out response codes<commit_after>// ref: https://github.com/memcached/memcached/blob/master/doc/protocol.txt

// Request structs

#[derive(Debug, PartialEq, Clone)]
pub struct Get {
    pub key: String,
}

impl Get {
    pub fn new(key: &str) -> Get {
        Get { key: key.to_string() }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Set {
    pub key: String, // alphanumeric characters
    pub flags: u16, // arbitrary bit pattern chosen by the client
    pub exptime: u32, // relative (secs) or absolute (unixtime) expiry time
    pub data: Vec<u8>, // binary data
    pub noreply: bool, // indicates whether the server should reply to the set
}

impl Set {
    pub fn new(key: &str,
               flags: u16,
               exptime: u32,
               data: Vec<u8>,
               noreply: bool)
               -> Set {
        Set {
            key: key.to_string(),
            flags: flags,
            exptime: exptime,
            data: data,
            noreply: noreply,
        }
    }
}

// Response structs

#[derive(Debug, PartialEq, Clone)]
pub struct ClientError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ServerError {
    pub error: String,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Stat {
    pub key: String,
    pub value: String,
}

impl Stat {
    pub fn new(key: &str, value: String) -> Stat {
        Stat {
            key: key.to_string(),
            value: value,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Value {
    pub key: String,
    pub flags: u16,
    pub data: Vec<u8>,
}

impl Value {
    pub fn new(key: &str, flags: u16, data: Vec<u8>) -> Value {
        Value {
            key: key.to_string(),
            flags: flags,
            data: data,
        }
    }
}

// High level groupings

#[derive(Debug, PartialEq, Clone)]
pub enum Cmd {
    Get(Get),
    Set(Set),
    Stats,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Resp {
    // A sentinel value to indicate that there is nothing to return to the
    // client (in case of noreply)
    Empty,

    Error,
    ClientError(ClientError),
    ServerError(ServerError),

    Deleted, // The item was deleted successfully
    Exists, // The cas item has been modified
    NotFound, // The cas item does not exist
    NotStored, // Precondition not met
    Stored, // The item was stored successfully
    Touched, // The item was touched successfully

    Stats(Vec<Stat>),
    Value(Value),
}
<|endoftext|>


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

//! Dragonfly-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]

use os::raw::c_long;
use os::unix::raw::{uid_t, gid_t};

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[repr(C)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: ino_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: nlink_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: mode_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_padding1: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: uid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: gid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: off_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: blkcnt_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: blksize_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: fflags_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: uint32_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: int32_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare1: int64_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare2: int64_t,
}
<commit_msg>Fix compile on DragonFly: Replace unknown uint32_t/in64_t by u32/i64.<commit_after>// Copyright 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.

//! Dragonfly-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]

use os::raw::c_long;
use os::unix::raw::{uid_t, gid_t};

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[repr(C)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: ino_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: nlink_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: mode_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_padding1: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: uid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: gid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: off_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: blkcnt_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: blksize_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: fflags_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: i32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare1: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare2: i64,
}
<|endoftext|>


<commit_before>use fallible_iterator::FallibleIterator;
use std::cmp::Ordering;
use std::marker::PhantomData;

use crate::common::{DebugInfoOffset, Encoding, SectionId};
use crate::endianity::Endianity;
use crate::read::lookup::{DebugLookup, LookupEntryIter, LookupParser};
use crate::read::{
    parse_debug_info_offset, EndianSlice, Error, Reader, ReaderOffset, Result, Section,
};

#[derive(Debug, Clone, PartialEq, Eq)]
struct ArangeHeader<T = usize> {
    encoding: Encoding,
    length: T,
    offset: DebugInfoOffset<T>,
    segment_size: u8,
}

/// A single parsed arange.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArangeEntry<T: Copy = usize> {
    segment: Option<u64>,
    address: u64,
    length: u64,
    unit_header_offset: DebugInfoOffset<T>,
}

impl<T: Copy> ArangeEntry<T> {
    /// Return the segment selector of this arange.
    #[inline]
    pub fn segment(&self) -> Option<u64> {
        self.segment
    }

    /// Return the beginning address of this arange.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Return the length of this arange.
    #[inline]
    pub fn length(&self) -> u64 {
        self.length
    }

    /// Return the offset into the .debug_info section for this arange.
    #[inline]
    pub fn debug_info_offset(&self) -> DebugInfoOffset<T> {
        self.unit_header_offset
    }
}

impl<T: Copy + Ord> PartialOrd for ArangeEntry<T> {
    fn partial_cmp(&self, other: &ArangeEntry<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: Copy + Ord> Ord for ArangeEntry<T> {
    fn cmp(&self, other: &ArangeEntry<T>) -> Ordering {
        // The expected comparison, but ignore header.
        match (
            self.segment.cmp(&other.segment),
            self.address.cmp(&other.address),
            self.length.cmp(&other.length),
        ) {
            (Ordering::Equal, Ordering::Equal, Ordering::Equal) => Ordering::Equal,
            (Ordering::Less, _, _)
            | (Ordering::Equal, Ordering::Less, _)
            | (Ordering::Equal, Ordering::Equal, Ordering::Less) => Ordering::Less,
            (Ordering::Greater, _, _)
            | (Ordering::Equal, Ordering::Greater, _)
            | (Ordering::Equal, Ordering::Equal, Ordering::Greater) => Ordering::Greater,
        }
    }
}

#[derive(Clone, Debug)]
struct ArangeParser<R: Reader> {
    // This struct is never instantiated.
    phantom: PhantomData<R>,
}

impl<R: Reader> LookupParser<R> for ArangeParser<R> {
    type Header = ArangeHeader<R::Offset>;
    type Entry = ArangeEntry<R::Offset>;

    /// Parse an arange set header. Returns a tuple of the aranges to be
    /// parsed for this set, and the newly created ArangeHeader struct.
    fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
        let (length, format) = input.read_initial_length()?;
        let mut rest = input.split(length)?;

        let version = rest.read_u16()?;
        if version != 2 {
            return Err(Error::UnknownVersion(u64::from(version)));
        }

        let offset = parse_debug_info_offset(&mut rest, format)?;
        let address_size = rest.read_u8()?;
        let segment_size = rest.read_u8()?;

        // unit_length + version + offset + address_size + segment_size
        let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1;

        // The first tuple following the header in each set begins at an offset that is
        // a multiple of the size of a single tuple (that is, the size of a segment selector
        // plus twice the size of an address).
        let tuple_length = 2 * address_size + segment_size;
        let padding = if header_length % tuple_length == 0 {
            0
        } else {
            tuple_length - header_length % tuple_length
        };
        rest.skip(R::Offset::from_u8(padding))?;

        let encoding = Encoding {
            format,
            version,
            address_size,
            // TODO: segment_size
        };
        Ok((
            rest,
            ArangeHeader {
                encoding,
                length,
                offset,
                segment_size,
            },
        ))
    }

    /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange.
    fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
        let address_size = header.encoding.address_size;
        let segment_size = header.segment_size; // May be zero!

        let tuple_length = R::Offset::from_u8(2 * address_size + segment_size);
        if tuple_length > input.len() {
            input.empty();
            return Ok(None);
        }

        let segment = if segment_size != 0 {
            input.read_address(segment_size)?
        } else {
            0
        };
        let address = input.read_address(address_size)?;
        let length = input.read_address(address_size)?;

        match (segment, address, length) {
            // There may be multiple sets of tuples, each terminated by a zero tuple.
            // It's not clear what purpose these zero tuples serve.  For now, we
            // simply skip them.
            (0, 0, 0) => Self::parse_entry(input, header),
            _ => Ok(Some(ArangeEntry {
                segment: if segment_size != 0 {
                    Some(segment)
                } else {
                    None
                },
                address,
                length,
                unit_header_offset: header.offset,
            })),
        }
    }
}

/// The `DebugAranges` struct represents the DWARF address range information
/// found in the `.debug_aranges` section.
#[derive(Debug, Clone)]
pub struct DebugAranges<R: Reader>(DebugLookup<R, ArangeParser<R>>);

impl<'input, Endian> DebugAranges<EndianSlice<'input, Endian>>
where
    Endian: Endianity,
{
    /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges`
    /// section.
    ///
    /// It is the caller's responsibility to read the `.debug_aranges` section and
    /// present it as a `&[u8]` slice. That means using some ELF loader on
    /// Linux, a Mach-O loader on OSX, etc.
    ///
    /// ```
    /// use gimli::{DebugAranges, LittleEndian};
    ///
    /// # let buf = [];
    /// # let read_debug_aranges_section = || &buf;
    /// let debug_aranges =
    ///     DebugAranges::new(read_debug_aranges_section(), LittleEndian);
    /// ```
    pub fn new(debug_aranges_section: &'input [u8], endian: Endian) -> Self {
        Self::from(EndianSlice::new(debug_aranges_section, endian))
    }
}

impl<R: Reader> DebugAranges<R> {
    /// Iterate the aranges in the `.debug_aranges` section.
    ///
    /// ```
    /// use gimli::{DebugAranges, EndianSlice, LittleEndian};
    ///
    /// # let buf = [];
    /// # let read_debug_aranges_section = || &buf;
    /// let debug_aranges = DebugAranges::new(read_debug_aranges_section(), LittleEndian);
    ///
    /// let mut iter = debug_aranges.items();
    /// while let Some(arange) = iter.next().unwrap() {
    ///     println!("arange starts at {}, has length {}", arange.address(), arange.length());
    /// }
    /// ```
    pub fn items(&self) -> ArangeEntryIter<R> {
        ArangeEntryIter(self.0.items())
    }
}

impl<R: Reader> Section<R> for DebugAranges<R> {
    fn id() -> SectionId {
        SectionId::DebugAranges
    }

    fn reader(&self) -> &R {
        self.0.reader()
    }
}

impl<R: Reader> From<R> for DebugAranges<R> {
    fn from(debug_aranges_section: R) -> Self {
        DebugAranges(DebugLookup::from(debug_aranges_section))
    }
}

/// An iterator over the aranges from a `.debug_aranges` section.
///
/// Can be [used with
/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
#[derive(Debug, Clone)]
pub struct ArangeEntryIter<R: Reader>(LookupEntryIter<R, ArangeParser<R>>);

impl<R: Reader> ArangeEntryIter<R> {
    /// Advance the iterator and return the next arange.
    ///
    /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)`
    /// when iteration is complete and all aranges have already been parsed and
    /// yielded. If an error occurs while parsing the next arange, then this error
    /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`.
    pub fn next(&mut self) -> Result<Option<ArangeEntry<R::Offset>>> {
        self.0.next()
    }
}

impl<R: Reader> FallibleIterator for ArangeEntryIter<R> {
    type Item = ArangeEntry<R::Offset>;
    type Error = Error;

    fn next(&mut self) -> ::std::result::Result<Option<Self::Item>, Self::Error> {
        self.0.next()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::common::{DebugInfoOffset, Format};
    use crate::endianity::LittleEndian;
    use crate::read::lookup::LookupParser;
    use crate::read::EndianSlice;

    #[test]
    fn test_parse_header_ok() {
        #[rustfmt::skip]
        let buf = [
            // 32-bit length = 32.
            0x20, 0x00, 0x00, 0x00,
            // Version.
            0x02, 0x00,
            // Offset.
            0x01, 0x02, 0x03, 0x04,
            // Address size.
            0x08,
            // Segment size.
            0x04,
            // Length to here = 12, tuple length = 20.
            // Padding to tuple length multiple = 4.
            0x10, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,

            // Dummy arange tuple data.
            0x20, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,

            // Dummy next arange.
            0x30, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ];

        let rest = &mut EndianSlice::new(&buf, LittleEndian);

        let (tuples, header) = ArangeParser::parse_header(rest).expect("should parse header ok");

        assert_eq!(
            *rest,
            EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
        );
        assert_eq!(
            tuples,
            EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian)
        );
        assert_eq!(
            header,
            ArangeHeader {
                encoding: Encoding {
                    format: Format::Dwarf32,
                    version: 2,
                    address_size: 8,
                },
                length: 0x20,
                offset: DebugInfoOffset(0x0403_0201),
                segment_size: 4,
            }
        );
    }

    #[test]
    fn test_parse_entry_ok() {
        let header = ArangeHeader {
            encoding: Encoding {
                format: Format::Dwarf32,
                version: 2,
                address_size: 4,
            },
            length: 0,
            offset: DebugInfoOffset(0),
            segment_size: 0,
        };
        let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
        let rest = &mut EndianSlice::new(&buf, LittleEndian);
        let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok");
        assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
        assert_eq!(
            entry,
            Some(ArangeEntry {
                segment: None,
                address: 0x0403_0201,
                length: 0x0807_0605,
                unit_header_offset: header.offset,
            })
        );
    }

    #[test]
    fn test_parse_entry_segment() {
        let header = ArangeHeader {
            encoding: Encoding {
                format: Format::Dwarf32,
                version: 2,
                address_size: 4,
            },
            length: 0,
            offset: DebugInfoOffset(0),
            segment_size: 8,
        };
        #[rustfmt::skip]
        let buf = [
            // Segment.
            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
            // Address.
            0x01, 0x02, 0x03, 0x04,
            // Length.
            0x05, 0x06, 0x07, 0x08,
            // Next tuple.
            0x09
        ];
        let rest = &mut EndianSlice::new(&buf, LittleEndian);
        let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok");
        assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
        assert_eq!(
            entry,
            Some(ArangeEntry {
                segment: Some(0x1817_1615_1413_1211),
                address: 0x0403_0201,
                length: 0x0807_0605,
                unit_header_offset: header.offset,
            })
        );
    }

    #[test]
    fn test_parse_entry_zero() {
        let header = ArangeHeader {
            encoding: Encoding {
                format: Format::Dwarf32,
                version: 2,
                address_size: 4,
            },
            length: 0,
            offset: DebugInfoOffset(0),
            segment_size: 0,
        };
        #[rustfmt::skip]
        let buf = [
            // Zero tuple.
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            // Address.
            0x01, 0x02, 0x03, 0x04,
            // Length.
            0x05, 0x06, 0x07, 0x08,
            // Next tuple.
            0x09
        ];
        let rest = &mut EndianSlice::new(&buf, LittleEndian);
        let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok");
        assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
        assert_eq!(
            entry,
            Some(ArangeEntry {
                segment: None,
                address: 0x0403_0201,
                length: 0x0807_0605,
                unit_header_offset: header.offset,
            })
        );
    }
}
<commit_msg>Simplify implementation of Ord for ArangeEntry<commit_after>use fallible_iterator::FallibleIterator;
use std::cmp::Ordering;
use std::marker::PhantomData;

use crate::common::{DebugInfoOffset, Encoding, SectionId};
use crate::endianity::Endianity;
use crate::read::lookup::{DebugLookup, LookupEntryIter, LookupParser};
use crate::read::{
    parse_debug_info_offset, EndianSlice, Error, Reader, ReaderOffset, Result, Section,
};

#[derive(Debug, Clone, PartialEq, Eq)]
struct ArangeHeader<T = usize> {
    encoding: Encoding,
    length: T,
    offset: DebugInfoOffset<T>,
    segment_size: u8,
}

/// A single parsed arange.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArangeEntry<T: Copy = usize> {
    segment: Option<u64>,
    address: u64,
    length: u64,
    unit_header_offset: DebugInfoOffset<T>,
}

impl<T: Copy> ArangeEntry<T> {
    /// Return the segment selector of this arange.
    #[inline]
    pub fn segment(&self) -> Option<u64> {
        self.segment
    }

    /// Return the beginning address of this arange.
    #[inline]
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Return the length of this arange.
    #[inline]
    pub fn length(&self) -> u64 {
        self.length
    }

    /// Return the offset into the .debug_info section for this arange.
    #[inline]
    pub fn debug_info_offset(&self) -> DebugInfoOffset<T> {
        self.unit_header_offset
    }
}

impl<T: Copy + Ord> PartialOrd for ArangeEntry<T> {
    fn partial_cmp(&self, other: &ArangeEntry<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: Copy + Ord> Ord for ArangeEntry<T> {
    fn cmp(&self, other: &ArangeEntry<T>) -> Ordering {
        // The expected comparison, but ignore header.
        self.segment.cmp(&other.segment)
            .then(self.address.cmp(&other.address))
            .then(self.length.cmp(&other.length))
    }
}

#[derive(Clone, Debug)]
struct ArangeParser<R: Reader> {
    // This struct is never instantiated.
    phantom: PhantomData<R>,
}

impl<R: Reader> LookupParser<R> for ArangeParser<R> {
    type Header = ArangeHeader<R::Offset>;
    type Entry = ArangeEntry<R::Offset>;

    /// Parse an arange set header. Returns a tuple of the aranges to be
    /// parsed for this set, and the newly created ArangeHeader struct.
    fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
        let (length, format) = input.read_initial_length()?;
        let mut rest = input.split(length)?;

        let version = rest.read_u16()?;
        if version != 2 {
            return Err(Error::UnknownVersion(u64::from(version)));
        }

        let offset = parse_debug_info_offset(&mut rest, format)?;
        let address_size = rest.read_u8()?;
        let segment_size = rest.read_u8()?;

        // unit_length + version + offset + address_size + segment_size
        let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1;

        // The first tuple following the header in each set begins at an offset that is
        // a multiple of the size of a single tuple (that is, the size of a segment selector
        // plus twice the size of an address).
        let tuple_length = 2 * address_size + segment_size;
        let padding = if header_length % tuple_length == 0 {
            0
        } else {
            tuple_length - header_length % tuple_length
        };
        rest.skip(R::Offset::from_u8(padding))?;

        let encoding = Encoding {
            format,
            version,
            address_size,
            // TODO: segment_size
        };
        Ok((
            rest,
            ArangeHeader {
                encoding,
                length,
                offset,
                segment_size,
            },
        ))
    }

    /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange.
    fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
        let address_size = header.encoding.address_size;
        let segment_size = header.segment_size; // May be zero!

        let tuple_length = R::Offset::from_u8(2 * address_size + segment_size);
        if tuple_length > input.len() {
            input.empty();
            return Ok(None);
        }

        let segment = if segment_size != 0 {
            input.read_address(segment_size)?
        } else {
            0
        };
        let address = input.read_address(address_size)?;
        let length = input.read_address(address_size)?;

        match (segment, address, length) {
            // There may be multiple sets of tuples, each terminated by a zero tuple.
            // It's not clear what purpose these zero tuples serve.  For now, we
            // simply skip them.
            (0, 0, 0) => Self::parse_entry(input, header),
            _ => Ok(Some(ArangeEntry {
                segment: if segment_size != 0 {
                    Some(segment)
                } else {
                    None
                },
                address,
                length,
                unit_header_offset: header.offset,
            })),
        }
    }
}

/// The `DebugAranges` struct represents the DWARF address range information
/// found in the `.debug_aranges` section.
#[derive(Debug, Clone)]
pub struct DebugAranges<R: Reader>(DebugLookup<R, ArangeParser<R>>);

impl<'input, Endian> DebugAranges<EndianSlice<'input, Endian>>
where
    Endian: Endianity,
{
    /// Construct a new `DebugAranges` instance from the data in the `.debug_aranges`
    /// section.
    ///
    /// It is the caller's responsibility to read the `.debug_aranges` section and
    /// present it as a `&[u8]` slice. That means using some ELF loader on
    /// Linux, a Mach-O loader on OSX, etc.
    ///
    /// ```
    /// use gimli::{DebugAranges, LittleEndian};
    ///
    /// # let buf = [];
    /// # let read_debug_aranges_section = || &buf;
    /// let debug_aranges =
    ///     DebugAranges::new(read_debug_aranges_section(), LittleEndian);
    /// ```
    pub fn new(debug_aranges_section: &'input [u8], endian: Endian) -> Self {
        Self::from(EndianSlice::new(debug_aranges_section, endian))
    }
}

impl<R: Reader> DebugAranges<R> {
    /// Iterate the aranges in the `.debug_aranges` section.
    ///
    /// ```
    /// use gimli::{DebugAranges, EndianSlice, LittleEndian};
    ///
    /// # let buf = [];
    /// # let read_debug_aranges_section = || &buf;
    /// let debug_aranges = DebugAranges::new(read_debug_aranges_section(), LittleEndian);
    ///
    /// let mut iter = debug_aranges.items();
    /// while let Some(arange) = iter.next().unwrap() {
    ///     println!("arange starts at {}, has length {}", arange.address(), arange.length());
    /// }
    /// ```
    pub fn items(&self) -> ArangeEntryIter<R> {
        ArangeEntryIter(self.0.items())
    }
}

impl<R: Reader> Section<R> for DebugAranges<R> {
    fn id() -> SectionId {
        SectionId::DebugAranges
    }

    fn reader(&self) -> &R {
        self.0.reader()
    }
}

impl<R: Reader> From<R> for DebugAranges<R> {
    fn from(debug_aranges_section: R) -> Self {
        DebugAranges(DebugLookup::from(debug_aranges_section))
    }
}

/// An iterator over the aranges from a `.debug_aranges` section.
///
/// Can be [used with
/// `FallibleIterator`](./index.html#using-with-fallibleiterator).
#[derive(Debug, Clone)]
pub struct ArangeEntryIter<R: Reader>(LookupEntryIter<R, ArangeParser<R>>);

impl<R: Reader> ArangeEntryIter<R> {
    /// Advance the iterator and return the next arange.
    ///
    /// Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)`
    /// when iteration is complete and all aranges have already been parsed and
    /// yielded. If an error occurs while parsing the next arange, then this error
    /// is returned as `Err(e)`, and all subsequent calls return `Ok(None)`.
    pub fn next(&mut self) -> Result<Option<ArangeEntry<R::Offset>>> {
        self.0.next()
    }
}

impl<R: Reader> FallibleIterator for ArangeEntryIter<R> {
    type Item = ArangeEntry<R::Offset>;
    type Error = Error;

    fn next(&mut self) -> ::std::result::Result<Option<Self::Item>, Self::Error> {
        self.0.next()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::common::{DebugInfoOffset, Format};
    use crate::endianity::LittleEndian;
    use crate::read::lookup::LookupParser;
    use crate::read::EndianSlice;

    #[test]
    fn test_parse_header_ok() {
        #[rustfmt::skip]
        let buf = [
            // 32-bit length = 32.
            0x20, 0x00, 0x00, 0x00,
            // Version.
            0x02, 0x00,
            // Offset.
            0x01, 0x02, 0x03, 0x04,
            // Address size.
            0x08,
            // Segment size.
            0x04,
            // Length to here = 12, tuple length = 20.
            // Padding to tuple length multiple = 4.
            0x10, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,

            // Dummy arange tuple data.
            0x20, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,

            // Dummy next arange.
            0x30, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ];

        let rest = &mut EndianSlice::new(&buf, LittleEndian);

        let (tuples, header) = ArangeParser::parse_header(rest).expect("should parse header ok");

        assert_eq!(
            *rest,
            EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
        );
        assert_eq!(
            tuples,
            EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian)
        );
        assert_eq!(
            header,
            ArangeHeader {
                encoding: Encoding {
                    format: Format::Dwarf32,
                    version: 2,
                    address_size: 8,
                },
                length: 0x20,
                offset: DebugInfoOffset(0x0403_0201),
                segment_size: 4,
            }
        );
    }

    #[test]
    fn test_parse_entry_ok() {
        let header = ArangeHeader {
            encoding: Encoding {
                format: Format::Dwarf32,
                version: 2,
                address_size: 4,
            },
            length: 0,
            offset: DebugInfoOffset(0),
            segment_size: 0,
        };
        let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
        let rest = &mut EndianSlice::new(&buf, LittleEndian);
        let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok");
        assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
        assert_eq!(
            entry,
            Some(ArangeEntry {
                segment: None,
                address: 0x0403_0201,
                length: 0x0807_0605,
                unit_header_offset: header.offset,
            })
        );
    }

    #[test]
    fn test_parse_entry_segment() {
        let header = ArangeHeader {
            encoding: Encoding {
                format: Format::Dwarf32,
                version: 2,
                address_size: 4,
            },
            length: 0,
            offset: DebugInfoOffset(0),
            segment_size: 8,
        };
        #[rustfmt::skip]
        let buf = [
            // Segment.
            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
            // Address.
            0x01, 0x02, 0x03, 0x04,
            // Length.
            0x05, 0x06, 0x07, 0x08,
            // Next tuple.
            0x09
        ];
        let rest = &mut EndianSlice::new(&buf, LittleEndian);
        let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok");
        assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
        assert_eq!(
            entry,
            Some(ArangeEntry {
                segment: Some(0x1817_1615_1413_1211),
                address: 0x0403_0201,
                length: 0x0807_0605,
                unit_header_offset: header.offset,
            })
        );
    }

    #[test]
    fn test_parse_entry_zero() {
        let header = ArangeHeader {
            encoding: Encoding {
                format: Format::Dwarf32,
                version: 2,
                address_size: 4,
            },
            length: 0,
            offset: DebugInfoOffset(0),
            segment_size: 0,
        };
        #[rustfmt::skip]
        let buf = [
            // Zero tuple.
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            // Address.
            0x01, 0x02, 0x03, 0x04,
            // Length.
            0x05, 0x06, 0x07, 0x08,
            // Next tuple.
            0x09
        ];
        let rest = &mut EndianSlice::new(&buf, LittleEndian);
        let entry = ArangeParser::parse_entry(rest, &header).expect("should parse entry ok");
        assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
        assert_eq!(
            entry,
            Some(ArangeEntry {
                segment: None,
                address: 0x0403_0201,
                length: 0x0807_0605,
                unit_header_offset: header.offset,
            })
        );
    }
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::collections::{ BTreeMap, HashMap };
use std::collections::btree_map::{ Occupied, Vacant };

use metafactory::{ ToMetaFactory, MetaFactory };

use super::container::Container;

use self::one_of::{ OneOf };
use self::one::{ One };
use self::group_candidate::{ GroupCandidateKey, GroupCandidate };
use self::definition_candidate::{ DefinitionCandidateKey, DefinitionCandidate };
use self::error::{ CompileError, DuplicateDefinitions };

mod group_candidate;
mod definition_candidate;

pub mod argument_builder;
pub mod one_of;
pub mod one;
pub mod error;
pub mod validator;

pub struct Registry {
    /// Contains a list of group candidates that are unique for
    /// id+type.
    maybe_groups: BTreeMap<GroupCandidateKey, GroupCandidate>,
    /// Contains a list of definition candidates that are unique for
    /// id+collection_id+type.
    maybe_definitions: BTreeMap<DefinitionCandidateKey, DefinitionCandidate>,
    /// Contains a list of definitions that were overriden while building
    /// the registry - so we can at least show some kind of warning.
    overriden_definitions: BTreeMap<DefinitionCandidateKey, Vec<DefinitionCandidate>>,

    validators: Vec<Box<validator::Validator + 'static>>,
}

impl Registry {
    pub fn new() -> Registry {
        let mut validators = Vec::new();

        let mut registry = Registry {
            maybe_groups: BTreeMap::new(),
            maybe_definitions: BTreeMap::new(),
            overriden_definitions: BTreeMap::new(),
            validators: validators,
        };

        registry.push_validator(validator::overrides::NoOverridesValidator);

        registry
    }

    pub fn push_validator<T: validator::Validator + 'static>(
        &mut self,
        validator: T
    ) {
        self.validators.push(box validator);
    }

    pub fn compile(&self) -> Result<Container, Vec<CompileError>> {
        let mut error_summary = Vec::<CompileError>::new();

        for validator in self.validators.iter() {
            validator.validate(self, &mut error_summary);
        }

        let factory_map = HashMap::<String, Box<Any>>::new();

        if error_summary.len() == 0 {
            Ok(Container::new(factory_map))
        } else {
            Err(error_summary)
        }
    }

    pub fn has_many<T: 'static>(&mut self, collection_id: &str) {
        let group_candidate_key = GroupCandidateKey::new::<T>(collection_id);
        if !self.maybe_groups.contains_key(&group_candidate_key) {
            self.maybe_groups.insert(
                group_candidate_key,
                GroupCandidate::new::<T>()
            );
        }
    }

    pub fn one_of<'r, T: 'static + ToMetaFactory>(&'r mut self, collection_id: &str, id: &str, value: T)
        -> OneOf<'r>
    {
        self.has_many::<T>(collection_id);

        OneOf::new(
            self,
            collection_id,
            id,
            value.to_metafactory()
        )
    }

    pub fn one<'r, T: 'static + ToMetaFactory>(&'r mut self, id: &str, value: T)
        -> One<'r>
    {
        One::new(
            self,
            id,
            value.to_metafactory()
        )
    }

    pub fn insert_one<T: 'static + ToMetaFactory>(&mut self, id: &str, value: T) {
        self.finalize(
            None,
            id,
            value.to_metafactory(),
            Vec::new()
        );
    }

    pub fn insert_with_args_one<T: 'static + ToMetaFactory>(&mut self, id: &str, arg_sources: &[&str], value: T) {
        self.finalize(
            None,
            id,
            value.to_metafactory(),
            arg_sources.iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    pub fn insert_with_arg_one<T: 'static + ToMetaFactory>(&mut self, id: &str, arg_source: &str, value: T) {
        self.finalize(
            None,
            id,
            value.to_metafactory(),
            [arg_source].iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    pub fn insert_one_of<T: 'static + ToMetaFactory>(&mut self, collection_id: &str, id: &str, value: T) {
        self.finalize(
            Some(collection_id),
            id,
            value.to_metafactory(),
            Vec::new()
        );
    }

    pub fn insert_with_args_one_of<T: 'static + ToMetaFactory>(&mut self, collection_id: &str, id: &str, arg_sources: &[&str], value: T) {
        self.finalize(
            Some(collection_id),
            id,
            value.to_metafactory(),
            arg_sources.iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    pub fn insert_with_arg_one_of<T: 'static + ToMetaFactory>(&mut self, collection_id: &str, id: &str, arg_source: &str, value: T) {
        self.finalize(
            Some(collection_id),
            id,
            value.to_metafactory(),
            [arg_source].iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    fn finalize(&mut self, collection_id: Option<&str>, id: &str, value: Box<MetaFactory + 'static>, args: Vec<String>) {
        let candidate_key = DefinitionCandidateKey::new(
            id,
            collection_id,
            value.get_type().get_str()
        );

        if let Some(overriden_candidate) = self.maybe_definitions.remove(&candidate_key) {
            match self.overriden_definitions.entry(candidate_key.clone()) {
                Vacant(entry) => { entry.set(vec![overriden_candidate]); },
                Occupied(mut entry) => { entry.get_mut().push(overriden_candidate); },
            };
        }

        let candidate = DefinitionCandidate::new(
            value,
            args
        );

        self.maybe_definitions.insert(
            candidate_key,
            candidate
        );
    }
}
<commit_msg>Simplify init.<commit_after>use std::any::Any;
use std::collections::{ BTreeMap, HashMap };
use std::collections::btree_map::{ Occupied, Vacant };

use metafactory::{ ToMetaFactory, MetaFactory };

use super::container::Container;

use self::one_of::{ OneOf };
use self::one::{ One };
use self::group_candidate::{ GroupCandidateKey, GroupCandidate };
use self::definition_candidate::{ DefinitionCandidateKey, DefinitionCandidate };
use self::error::{ CompileError, DuplicateDefinitions };

mod group_candidate;
mod definition_candidate;

pub mod argument_builder;
pub mod one_of;
pub mod one;
pub mod error;
pub mod validator;

pub struct Registry {
    /// Contains a list of group candidates that are unique for
    /// id+type.
    maybe_groups: BTreeMap<GroupCandidateKey, GroupCandidate>,
    /// Contains a list of definition candidates that are unique for
    /// id+collection_id+type.
    maybe_definitions: BTreeMap<DefinitionCandidateKey, DefinitionCandidate>,
    /// Contains a list of definitions that were overriden while building
    /// the registry - so we can at least show some kind of warning.
    overriden_definitions: BTreeMap<DefinitionCandidateKey, Vec<DefinitionCandidate>>,

    validators: Vec<Box<validator::Validator + 'static>>,
}

impl Registry {
    pub fn new() -> Registry {
        let mut registry = Registry {
            maybe_groups: BTreeMap::new(),
            maybe_definitions: BTreeMap::new(),
            overriden_definitions: BTreeMap::new(),
            validators: Vec::new(),
        };

        registry.push_validator(validator::overrides::NoOverridesValidator);

        registry
    }

    pub fn push_validator<T: validator::Validator + 'static>(
        &mut self,
        validator: T
    ) {
        self.validators.push(box validator);
    }

    pub fn compile(&self) -> Result<Container, Vec<CompileError>> {
        let mut error_summary = Vec::<CompileError>::new();

        for validator in self.validators.iter() {
            validator.validate(self, &mut error_summary);
        }

        let factory_map = HashMap::<String, Box<Any>>::new();

        if error_summary.len() == 0 {
            Ok(Container::new(factory_map))
        } else {
            Err(error_summary)
        }
    }

    pub fn has_many<T: 'static>(&mut self, collection_id: &str) {
        let group_candidate_key = GroupCandidateKey::new::<T>(collection_id);
        if !self.maybe_groups.contains_key(&group_candidate_key) {
            self.maybe_groups.insert(
                group_candidate_key,
                GroupCandidate::new::<T>()
            );
        }
    }

    pub fn one_of<'r, T: 'static + ToMetaFactory>(&'r mut self, collection_id: &str, id: &str, value: T)
        -> OneOf<'r>
    {
        self.has_many::<T>(collection_id);

        OneOf::new(
            self,
            collection_id,
            id,
            value.to_metafactory()
        )
    }

    pub fn one<'r, T: 'static + ToMetaFactory>(&'r mut self, id: &str, value: T)
        -> One<'r>
    {
        One::new(
            self,
            id,
            value.to_metafactory()
        )
    }

    pub fn insert_one<T: 'static + ToMetaFactory>(&mut self, id: &str, value: T) {
        self.finalize(
            None,
            id,
            value.to_metafactory(),
            Vec::new()
        );
    }

    pub fn insert_with_args_one<T: 'static + ToMetaFactory>(&mut self, id: &str, arg_sources: &[&str], value: T) {
        self.finalize(
            None,
            id,
            value.to_metafactory(),
            arg_sources.iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    pub fn insert_with_arg_one<T: 'static + ToMetaFactory>(&mut self, id: &str, arg_source: &str, value: T) {
        self.finalize(
            None,
            id,
            value.to_metafactory(),
            [arg_source].iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    pub fn insert_one_of<T: 'static + ToMetaFactory>(&mut self, collection_id: &str, id: &str, value: T) {
        self.finalize(
            Some(collection_id),
            id,
            value.to_metafactory(),
            Vec::new()
        );
    }

    pub fn insert_with_args_one_of<T: 'static + ToMetaFactory>(&mut self, collection_id: &str, id: &str, arg_sources: &[&str], value: T) {
        self.finalize(
            Some(collection_id),
            id,
            value.to_metafactory(),
            arg_sources.iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    pub fn insert_with_arg_one_of<T: 'static + ToMetaFactory>(&mut self, collection_id: &str, id: &str, arg_source: &str, value: T) {
        self.finalize(
            Some(collection_id),
            id,
            value.to_metafactory(),
            [arg_source].iter()
                .map(|s| s.to_string())
                .collect()
        );
    }

    fn finalize(&mut self, collection_id: Option<&str>, id: &str, value: Box<MetaFactory + 'static>, args: Vec<String>) {
        let candidate_key = DefinitionCandidateKey::new(
            id,
            collection_id,
            value.get_type().get_str()
        );

        if let Some(overriden_candidate) = self.maybe_definitions.remove(&candidate_key) {
            match self.overriden_definitions.entry(candidate_key.clone()) {
                Vacant(entry) => { entry.set(vec![overriden_candidate]); },
                Occupied(mut entry) => { entry.get_mut().push(overriden_candidate); },
            };
        }

        let candidate = DefinitionCandidate::new(
            value,
            args
        );

        self.maybe_definitions.insert(
            candidate_key,
            candidate
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::prelude::*;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error::Error;
use std::rc::Rc;
use std::cell::RefCell;

use polygon::gl_render::{GLRender, GLMeshData, ShaderProgram};
use polygon::geometry::mesh::Mesh;

use wav::Wave;
use scene::Scene;
use ecs::Entity;
use component::{MeshManager, TransformManager};
use self::collada::{Collada, Geometry, Node, VisualScene};
use self::shader::*;

pub mod collada;
pub mod shader;

#[derive(Debug, Clone)]
pub struct ResourceManager {
    renderer: Rc<GLRender>,
    meshes: RefCell<HashMap<String, GLMeshData>>,
    shaders: RefCell<HashMap<String, ShaderProgram>>,
    audio_clips: RefCell<HashMap<String, Rc<Wave>>>,

    visual_scenes: RefCell<HashMap<String, VisualScene>>,
    geometries: RefCell<HashMap<String, Geometry>>,

    resource_path: RefCell<PathBuf>,
}

impl ResourceManager {
    pub fn new(renderer: Rc<GLRender>) -> ResourceManager {
        ResourceManager {
            renderer: renderer,
            meshes: RefCell::new(HashMap::new()),
            shaders: RefCell::new(HashMap::new()),
            audio_clips: RefCell::new(HashMap::new()),

            visual_scenes: RefCell::new(HashMap::new()),
            geometries: RefCell::new(HashMap::new()),

            resource_path: RefCell::new(PathBuf::new()),
        }
    }

    /// TODO: Perform validity checking on data when loading (e.g. make sure all nodes have an id).
    pub fn load_model<P: AsRef<Path>>(&self, path: P) -> Result<(), String> {
        let mut visual_scenes = self.visual_scenes.borrow_mut();
        let mut geometries = self.geometries.borrow_mut();

        let mut full_path = self.resource_path.borrow().clone();
        full_path.push(path);
        let metadata = match fs::metadata(&full_path) {
            Err(why) => return Err(format!(
                "Unable to read metadata for {}, either it doesn't exist or the user lacks permissions, {}",
                full_path.display(),
                &why)),
            Ok(metadata) => metadata,
        };
        if !metadata.is_file() {
            return Err(format!(
                "{} could not be loaded because it is not a file",
                full_path.display()));
        }
        let collada_data = match Collada::load(&full_path) {
            Err(why) => return Err(format!(
                "couldn't open {}: {:?}",
                full_path.display(),
                &why)),
            Ok(data) => data,
        };

        // Store each of the visual scenes from the collada file.
        for visual_scene in collada_data.library_visual_scenes.as_ref().unwrap().visual_scene.iter() {
            let id = match visual_scene.id {
                None => return Err(format!(
                    "COLLADA file {} contained a <visual_scene> with no \"id\" attribute, this is unsupported.",
                    full_path.display())),
                Some(ref id) => id.clone(),
            };
            visual_scenes.insert(id, visual_scene.clone());
        }

        // Store each of the geometries so they can be referenced later.
        for geometry in collada_data.library_geometries.as_ref().unwrap().geometry.iter() {
            let id = match geometry.id {
                None => return Err(format!(
                    "COLLADA file {} contained a <geometry> with no \"id\" attribute, this is unsupported",
                    full_path.display())),
                Some(ref id) => id.clone(),
            };
            geometries.insert(id, geometry.clone());
        }

        Ok(())
    }

    /// Sets the path to the resources directory.
    ///
    /// # Details
    ///
    /// The resource manager is configured to look in the specified directory when loading
    /// resources such as meshes and shaders.
    pub fn set_resource_path<P: AsRef<Path>>(&self, path: P) {
        let mut resource_path = self.resource_path.borrow_mut();
        *resource_path = PathBuf::new();
        resource_path.push(path);
    }

    pub fn get_mesh(&self, uri: &str) -> Result<GLMeshData, String> {
        // Use cached mesh data if possible.
        if let Some(mesh) = self.get_cached_mesh(uri) {
            return Ok(mesh);
        }

        // Generate mesh data since none has ben created previously.
        let visual_scenes = self.visual_scenes.borrow();

        // TODO: Handle invalid URIs (empty, invalid characters?).
        let mut uri_segments = uri.split(".");
        let root = uri_segments.next().unwrap();
        let visual_scene = match visual_scenes.get(root) {
            None => return Err(format!(
                "No source file {} found from which to load {}",
                root,
                uri)),
            Some(visual_scene) => visual_scene,
        };

        // Get the first node in the URI.
        let mut node = {
            let name = uri_segments.next().unwrap();
            let mut result: Option<&Node> = None;
            for node in &visual_scene.node {
                if node.id.as_ref().unwrap() == name {
                    result = Some(node);
                    break;
                }
            }

            match result {
                None => return Err(format!(
                    "No node named {} found in scene {}",
                    name,
                    root)),
                Some(node) => node,
            }
        };

        for name in uri_segments {
            let mut result: Option<&Node> = None;
            for next_node in &node.nodes {
                if next_node.id.as_ref().unwrap() == name {
                    result = Some(next_node);
                    break;
                }
            }

            match result {
                None => return Err(format!(
                    "No node named {} found when parsing {}",
                    name,
                    uri)),
                Some(next_node) =>
                    node = next_node,
            }
        }

        let mesh_data = self.gen_mesh_from_node(node, uri).unwrap();
        Ok(mesh_data)
    }

    pub fn get_audio_clip(&self, path_text: &str) -> Rc<Wave> {
        let mut audio_clips = self.audio_clips.borrow_mut();

        if !audio_clips.contains_key(path_text) {
            let wave = Wave::from_file(path_text).unwrap();
            audio_clips.insert(path_text.into(), Rc::new(wave));
        }

        audio_clips.get(path_text).unwrap().clone()
    }

    pub fn instantiate_model(&self, resource: &str, scene: &Scene) -> Result<Entity, String> {
        if resource.contains(".") {
            println!("WARNING: ResourceManager::instantiate_model() doesn't yet support fully qualified URIs, only root assets may be instantiated.");
        }

        let mut uri_segments = resource.split(".");
        let root = uri_segments.next().unwrap();
        let visual_scenes = self.visual_scenes.borrow();
        let visual_scene = {
            match visual_scenes.get(root) {
                None => return Err(format!(
                    "No source file {} found from which to load {}",
                    root,
                    resource)),
                Some(visual_scene) => visual_scene,
            }
        };

        let node = {
            if visual_scene.node.len() == 0 {
                return Err(format!(
                    "No nodes associated with model {}",
                    resource));
            }

            if visual_scene.node.len() > 1 {
                println!(
                    "WARNING: Model {} has more than one node at the root level. This is not currenlty supported, only the first node will be used.",
                    resource);
            }

            &visual_scene.node[0]
        };

        let mut uri = String::from(resource);
        uri.push_str(".");
        uri.push_str(node.id.as_ref().unwrap());

        let mesh_data = if let Some(mesh_data) = self.get_cached_mesh(&uri) {
            mesh_data
        } else {
            match self.gen_mesh_from_node(node, &uri) {
                Err(message) => return Err(message),
                Ok(mesh_data) => mesh_data,
            }
        };

        let entity = scene.create_entity();
        {
            let mut transform_manager = scene.get_manager_mut::<TransformManager>();
            transform_manager.assign(entity);
            scene.get_manager_mut::<MeshManager>()
                .give_mesh(entity, mesh_data);
        }

        // Instantiate each of the children and set the current node as their parent.

        return Ok(entity);
    }

    pub fn get_shader<P: AsRef<Path> + ::std::fmt::Debug>(
        &self,
        shader_path: P
    ) -> Result<ShaderProgram, ParseShaderError> {
        {
            let path_str = shader_path.as_ref().to_str().expect(&*format!(
                "shader path {:?} contains invalid unicode characters",
                shader_path));
            if let Some(shader) = self.shaders.borrow().get(path_str) {
                return Ok(shader.clone());
            }
        }

        // This should be an else block on the above if block, but that doesn't work until MIR has
        // dropped, so for now we have to settle for manual case analysis.
        {
            let path_string: String = shader_path.as_ref()
                .to_str()
                .expect(&*format!(
                    "shader path {:?} contains invalid unicode characters",
                    shader_path))
                .into();

            let mut full_path = self.resource_path.borrow().clone();
            full_path.push(shader_path);
            let program_src = load_file_text(full_path);

            let programs = try!(ShaderParser::parse(&*program_src));
            let vert_src = match programs.iter().find(|program| program.name == "vert") {
                None => return Err(ParseShaderError::NoVertProgram),
                Some(program) => program.src,
            };

            let frag_src = match programs.iter().find(|program| program.name == "frag") {
                None => return Err(ParseShaderError::NoFragProgram),
                Some(program) => program.src,
            };

            let shader = self.renderer.compile_shader_program(vert_src, frag_src);
            self.shaders.borrow_mut().insert(path_string, shader.clone());

            Ok(shader)
        }
    }

    fn gen_mesh_from_node(&self, node: &collada::Node, uri: &str) -> Result<GLMeshData, String> {
        let geometry_name = {
            if node.geometry_instances.len() == 0 {
                return Err(format!("No geometry is identified by {}", uri));
            }
            if node.geometry_instances.len() > 1 {
                return Err(format!("More than one geometry is identified by {}", uri));
            }

            let url = &node.geometry_instances[0].url;
            &url[1..] // Skip the leading "#" character that starts all URLs.
        };

        let geometries = self.geometries.borrow();
        let geometry = geometries.get(geometry_name).unwrap();
        self.gen_mesh(geometry, uri)
    }

    fn has_cached_mesh(&self, uri: &str) -> bool {
        self.meshes.borrow().contains_key(uri)
    }

    fn get_cached_mesh(&self, uri: &str) -> Option<GLMeshData> {
        match self.meshes.borrow().get(uri) {
            None => None,
            Some(mesh_ref) => Some(*mesh_ref),
        }
    }

    fn gen_mesh(&self, geometry: &Geometry, uri: &str) -> Result<GLMeshData, String> {
        assert!(!self.has_cached_mesh(uri), "Attempting to create a new mesh for {} when the uri is already in the meshes map", uri);

        println!("generating mesh: {}", uri);

        let mesh = collada::geometry_to_mesh(geometry).unwrap(); // TODO: Don't panic!

        let mesh_data = self.renderer.gen_mesh(&mesh);
        self.meshes.borrow_mut().insert(uri.into(), mesh_data);

        Ok(mesh_data)
    }
}

pub fn load_file_text<P: AsRef<Path>>(file_path: P) -> String {
    let mut file = match File::open(&file_path) {
        // The `desc` field of `IoError` is a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", file_path.as_ref().display(), Error::description(&why)),
        Ok(file) => file,
    };
    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Err(why) => panic!("couldn't read {}: {}", file_path.as_ref().display(), Error::description(&why)),
        Ok(_) => ()
    }
    contents
}
<commit_msg>fix(instantiate_model): fix issue where whole model wasn't instantiated<commit_after>use std::collections::HashMap;
use std::io::prelude::*;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::error::Error;
use std::rc::Rc;
use std::cell::RefCell;

use polygon::gl_render::{GLRender, GLMeshData, ShaderProgram};
use polygon::geometry::mesh::Mesh;

use wav::Wave;
use scene::Scene;
use ecs::Entity;
use component::{MeshManager, TransformManager};
use self::collada::{Collada, Geometry, Node, VisualScene};
use self::shader::*;

pub mod collada;
pub mod shader;

#[derive(Debug, Clone)]
pub struct ResourceManager {
    renderer: Rc<GLRender>,
    meshes: RefCell<HashMap<String, GLMeshData>>,
    shaders: RefCell<HashMap<String, ShaderProgram>>,
    audio_clips: RefCell<HashMap<String, Rc<Wave>>>,

    visual_scenes: RefCell<HashMap<String, VisualScene>>,
    geometries: RefCell<HashMap<String, Geometry>>,

    resource_path: RefCell<PathBuf>,
}

impl ResourceManager {
    pub fn new(renderer: Rc<GLRender>) -> ResourceManager {
        ResourceManager {
            renderer: renderer,
            meshes: RefCell::new(HashMap::new()),
            shaders: RefCell::new(HashMap::new()),
            audio_clips: RefCell::new(HashMap::new()),

            visual_scenes: RefCell::new(HashMap::new()),
            geometries: RefCell::new(HashMap::new()),

            resource_path: RefCell::new(PathBuf::new()),
        }
    }

    /// TODO: Perform validity checking on data when loading (e.g. make sure all nodes have an id).
    pub fn load_model<P: AsRef<Path>>(&self, path: P) -> Result<(), String> {
        let mut visual_scenes = self.visual_scenes.borrow_mut();
        let mut geometries = self.geometries.borrow_mut();

        let mut full_path = self.resource_path.borrow().clone();
        full_path.push(path);
        let metadata = match fs::metadata(&full_path) {
            Err(why) => return Err(format!(
                "Unable to read metadata for {}, either it doesn't exist or the user lacks permissions, {}",
                full_path.display(),
                &why)),
            Ok(metadata) => metadata,
        };
        if !metadata.is_file() {
            return Err(format!(
                "{} could not be loaded because it is not a file",
                full_path.display()));
        }
        let collada_data = match Collada::load(&full_path) {
            Err(why) => return Err(format!(
                "couldn't open {}: {:?}",
                full_path.display(),
                &why)),
            Ok(data) => data,
        };

        // Store each of the visual scenes from the collada file.
        for visual_scene in collada_data.library_visual_scenes.as_ref().unwrap().visual_scene.iter() {
            let id = match visual_scene.id {
                None => return Err(format!(
                    "COLLADA file {} contained a <visual_scene> with no \"id\" attribute, this is unsupported.",
                    full_path.display())),
                Some(ref id) => id.clone(),
            };
            visual_scenes.insert(id, visual_scene.clone());
        }

        // Store each of the geometries so they can be referenced later.
        for geometry in collada_data.library_geometries.as_ref().unwrap().geometry.iter() {
            let id = match geometry.id {
                None => return Err(format!(
                    "COLLADA file {} contained a <geometry> with no \"id\" attribute, this is unsupported",
                    full_path.display())),
                Some(ref id) => id.clone(),
            };
            geometries.insert(id, geometry.clone());
        }

        Ok(())
    }

    /// Sets the path to the resources directory.
    ///
    /// # Details
    ///
    /// The resource manager is configured to look in the specified directory when loading
    /// resources such as meshes and shaders.
    pub fn set_resource_path<P: AsRef<Path>>(&self, path: P) {
        let mut resource_path = self.resource_path.borrow_mut();
        *resource_path = PathBuf::new();
        resource_path.push(path);
    }

    pub fn get_mesh(&self, uri: &str) -> Result<GLMeshData, String> {
        // Use cached mesh data if possible.
        if let Some(mesh) = self.get_cached_mesh(uri) {
            return Ok(mesh);
        }

        // Generate mesh data since none has ben created previously.
        let visual_scenes = self.visual_scenes.borrow();

        // TODO: Handle invalid URIs (empty, invalid characters?).
        let mut uri_segments = uri.split(".");
        let root = uri_segments.next().unwrap();
        let visual_scene = match visual_scenes.get(root) {
            None => return Err(format!(
                "No source file {} found from which to load {}",
                root,
                uri)),
            Some(visual_scene) => visual_scene,
        };

        // Get the first node in the URI.
        let mut node = {
            let name = uri_segments.next().unwrap();
            let mut result: Option<&Node> = None;
            for node in &visual_scene.node {
                if node.id.as_ref().unwrap() == name {
                    result = Some(node);
                    break;
                }
            }

            match result {
                None => return Err(format!(
                    "No node named {} found in scene {}",
                    name,
                    root)),
                Some(node) => node,
            }
        };

        for name in uri_segments {
            let mut result: Option<&Node> = None;
            for next_node in &node.nodes {
                if next_node.id.as_ref().unwrap() == name {
                    result = Some(next_node);
                    break;
                }
            }

            match result {
                None => return Err(format!(
                    "No node named {} found when parsing {}",
                    name,
                    uri)),
                Some(next_node) =>
                    node = next_node,
            }
        }

        let mesh_data = self.gen_mesh_from_node(node, uri).unwrap();
        Ok(mesh_data)
    }

    pub fn get_audio_clip(&self, path_text: &str) -> Rc<Wave> {
        let mut audio_clips = self.audio_clips.borrow_mut();

        if !audio_clips.contains_key(path_text) {
            let wave = Wave::from_file(path_text).unwrap();
            audio_clips.insert(path_text.into(), Rc::new(wave));
        }

        audio_clips.get(path_text).unwrap().clone()
    }

    pub fn instantiate_model(&self, resource: &str, scene: &Scene) -> Result<Entity, String> {
        if resource.contains(".") {
            println!("WARNING: ResourceManager::instantiate_model() doesn't yet support fully qualified URIs, only root assets may be instantiated.");
        }

        let mut uri_segments = resource.split(".");
        let root = uri_segments.next().unwrap();
        let visual_scenes = self.visual_scenes.borrow();
        let visual_scene = {
            match visual_scenes.get(root) {
                None => return Err(format!(
                    "No source file {} found from which to load {}",
                    root,
                    resource)),
                Some(visual_scene) => visual_scene,
            }
        };

        let node = {
            if visual_scene.node.len() == 0 {
                return Err(format!(
                    "No nodes associated with model {}",
                    resource));
            }

            if visual_scene.node.len() > 1 {
                println!(
                    "WARNING: Model {} has more than one node at the root level. This is not currenlty supported, only the first node will be used.",
                    resource);
            }

            &visual_scene.node[0]
        };

        let uri = String::from(resource);
        self.instantiate_node(scene, node, uri)
    }

    fn instantiate_node(&self, scene: &Scene, node: &Node, mut uri: String) -> Result<Entity, String> {
        uri.push_str(".");
        uri.push_str(node.id.as_ref().unwrap());

        let mesh_data = if let Some(mesh_data) = self.get_cached_mesh(&uri) {
            mesh_data
        } else {
            match self.gen_mesh_from_node(node, &uri) {
                Err(message) => return Err(message),
                Ok(mesh_data) => mesh_data,
            }
        };

        let entity = scene.create_entity();
        {
            // TODO: Apply the node's transform to the entity transform.
            let mut transform_manager = scene.get_manager_mut::<TransformManager>();
            transform_manager.assign(entity);
            scene.get_manager_mut::<MeshManager>()
                .give_mesh(entity, mesh_data);
        }

        // Instantiate each of the children and set the current node as their parent.
        for node in &node.nodes {
            let child = try!(self.instantiate_node(scene, node, uri.clone()));

            let mut transform_manager = scene.get_manager_mut::<TransformManager>();
            transform_manager.set_child(entity, child);
        }

        Ok(entity)
    }

    pub fn get_shader<P: AsRef<Path> + ::std::fmt::Debug>(
        &self,
        shader_path: P
    ) -> Result<ShaderProgram, ParseShaderError> {
        {
            let path_str = shader_path.as_ref().to_str().expect(&*format!(
                "shader path {:?} contains invalid unicode characters",
                shader_path));
            if let Some(shader) = self.shaders.borrow().get(path_str) {
                return Ok(shader.clone());
            }
        }

        // This should be an else block on the above if block, but that doesn't work until MIR has
        // dropped, so for now we have to settle for manual case analysis.
        {
            let path_string: String = shader_path.as_ref()
                .to_str()
                .expect(&*format!(
                    "shader path {:?} contains invalid unicode characters",
                    shader_path))
                .into();

            let mut full_path = self.resource_path.borrow().clone();
            full_path.push(shader_path);
            let program_src = load_file_text(full_path);

            let programs = try!(ShaderParser::parse(&*program_src));
            let vert_src = match programs.iter().find(|program| program.name == "vert") {
                None => return Err(ParseShaderError::NoVertProgram),
                Some(program) => program.src,
            };

            let frag_src = match programs.iter().find(|program| program.name == "frag") {
                None => return Err(ParseShaderError::NoFragProgram),
                Some(program) => program.src,
            };

            let shader = self.renderer.compile_shader_program(vert_src, frag_src);
            self.shaders.borrow_mut().insert(path_string, shader.clone());

            Ok(shader)
        }
    }

    fn gen_mesh_from_node(&self, node: &collada::Node, uri: &str) -> Result<GLMeshData, String> {
        let geometry_name = {
            if node.geometry_instances.len() == 0 {
                return Err(format!("No geometry is identified by {}", uri));
            }
            if node.geometry_instances.len() > 1 {
                return Err(format!("More than one geometry is identified by {}", uri));
            }

            let url = &node.geometry_instances[0].url;
            &url[1..] // Skip the leading "#" character that starts all URLs.
        };

        let geometries = self.geometries.borrow();
        let geometry = geometries.get(geometry_name).unwrap();
        self.gen_mesh(geometry, uri)
    }

    fn has_cached_mesh(&self, uri: &str) -> bool {
        self.meshes.borrow().contains_key(uri)
    }

    fn get_cached_mesh(&self, uri: &str) -> Option<GLMeshData> {
        match self.meshes.borrow().get(uri) {
            None => None,
            Some(mesh_ref) => Some(*mesh_ref),
        }
    }

    fn gen_mesh(&self, geometry: &Geometry, uri: &str) -> Result<GLMeshData, String> {
        assert!(!self.has_cached_mesh(uri), "Attempting to create a new mesh for {} when the uri is already in the meshes map", uri);

        println!("generating mesh: {}", uri);

        let mesh = collada::geometry_to_mesh(geometry).unwrap(); // TODO: Don't panic!

        let mesh_data = self.renderer.gen_mesh(&mesh);
        self.meshes.borrow_mut().insert(uri.into(), mesh_data);

        Ok(mesh_data)
    }
}

pub fn load_file_text<P: AsRef<Path>>(file_path: P) -> String {
    let mut file = match File::open(&file_path) {
        // The `desc` field of `IoError` is a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", file_path.as_ref().display(), Error::description(&why)),
        Ok(file) => file,
    };
    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Err(why) => panic!("couldn't read {}: {}", file_path.as_ref().display(), Error::description(&why)),
        Ok(_) => ()
    }
    contents
}
<|endoftext|>