<commit_before>extern crate chrono;
extern crate fuse;
extern crate libc;
extern crate regex;
extern crate rustc_serialize;
extern crate time;
extern crate users;

use libc::ENOSYS;
use chrono::*;
use fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyEmpty};
use rustc_serialize::json;
use std::path::Path;

use std::ffi::OsStr;

use fs;
use fs::inode;
use gd;
use object;

use fs::helpers::{create_inode_directory_attributes, create_inode_file_attributes};
use helpers;

pub struct GoodDataFS {
    pub client: gd::GoodDataClient,
    pub users_cache: users::UsersCache,
}

impl Drop for GoodDataFS {
    fn drop(&mut self) {
        println!("Unmounting GoodData Filesystem");
    }
}

#[allow(dead_code)]
impl GoodDataFS {
    pub fn client(&self) -> &gd::GoodDataClient {
        &self.client
    }

    pub fn get_projects_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_PROJECTS)
    }

    pub fn get_root_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_ROOT)
    }

    pub fn get_user_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.user()).to_string());

        let user = json::decode::<object::AccountSetting>(&json);

        let ts = UTC.datetime_from_str(&user.unwrap().accountSetting.updated.unwrap()[..],
                               "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();

        let updated = time::Timespec::new(ts, 0);

        create_inode_file_attributes(fs::constants::INODE_USER, json.len() as u64, updated)
    }

    pub fn get_projects_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.projects()).to_string());

        create_inode_file_attributes(fs::constants::INODE_PROJECTS_JSON,
                                     json.len() as u64,
                                     fs::constants::DEFAULT_CREATE_TIME)
    }
}

impl Filesystem for GoodDataFS {
    fn getattr(&mut self, req: &Request, ino: u64, reply: ReplyAttr) {
        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::getattr() - Getting attributes {} - {:?}",
                 ino,
                 inode);

        match ino {
            fs::constants::INODE_ROOT => fs::root::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS => fs::projects::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS_JSON => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_projects_json_attributes())
            }
            fs::constants::INODE_USER => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_user_json_attributes())
            }
            _ => {
                if inode.project > 0 && inode.category == fs::constants::Category::Internal as u8 &&
                   inode.reserved == 0 {
                    fs::projects::getattr(self, req, ino, reply)
                } else if inode.project > 0 {
                    fs::project::getattr(self, req, ino, reply)
                } else {
                    println!("getattr() - HAPR")
                }
            }
        }
    }

    fn lookup(&mut self, req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::lookup() - Looking up parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());

        match parent {
            fs::constants::INODE_ROOT => fs::root::lookup(self, req, parent, name, reply),
            fs::constants::INODE_PROJECTS => fs::projects::lookup(self, req, parent, name, reply),
            _ => {
                if parent_inode.project > 0 {
                    fs::project::lookup(self, req, parent, name, reply)
                }
            }
        }
    }

    fn read(&mut self,
            req: &Request,
            ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::read() - Reading inode {} - {:?}, fh: {}, offset: {}, size: {}",
                 ino,
                 inode,
                 fh,
                 offset,
                 size);

        match ino {
            fs::constants::INODE_PROJECTS_JSON => {
                // println!("off: {}, size {}", offset, size);
                let json = format!("{}\n",
                                   json::as_pretty_json(&self.client.projects_fetch_if_none())
                                       .to_string());
                // let json: String = fs.client.projects().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            fs::constants::INODE_USER => {
                let json: String = self.client.user().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            _ => {
                let inode = inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::read(self, req, ino, fh, offset, size, reply);
                } else {
                    println!("read() - HAPR")
                }
            }
        }
    }

    fn readdir(&mut self, req: &Request, ino: u64, fh: u64, offset: u64, reply: ReplyDirectory) {
        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::readdir() - Reading inode {} - {:?}, fh: {}, offset: {}",
                 ino,
                 inode,
                 fh,
                 offset);

        match ino {
            fs::constants::INODE_ROOT => {
                if offset == 0 {
                    fs::root::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            fs::constants::INODE_PROJECTS => {
                if offset == 0 {
                    fs::projects::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            _ => {
                let inode: fs::inode::Inode = fs::inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::readdir(self, req, ino, fh, offset, reply)
                }
            }
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &Path, _mode: u32, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::mkdir() - Making dir in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::create(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }

    fn rmdir(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::rmdir() - Removing dir in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::rmdir(self, name, reply),
            _ => {
                println!("WARN: rmdir() not implemented!");
                reply.ok()
                // reply.error(ENOSYS)
            }
        }
    }

    fn unlink(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::unlinl() - Removing file in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        println!("WARN: unlink() not implemented!");
        reply.ok()
        // reply.error(ENOSYS);
    }
}

impl GoodDataFS {
    pub fn mount(self, mountpoint: String) {
        const VERSION: &'static str = env!("CARGO_PKG_VERSION");
        println!("Mounting GoodData as Filesystem ({}), mountpoint: {}",
                 VERSION,
                 mountpoint);

        fuse::mount(self, &mountpoint, &[&OsStr::new("debug")]);
    }
}
<commit_msg>Use logger instead of println!<commit_after>extern crate chrono;
extern crate fuse;
extern crate libc;
extern crate regex;
extern crate rustc_serialize;
extern crate time;
extern crate users;

use libc::ENOSYS;
use chrono::*;
use fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyEmpty};
use rustc_serialize::json;
use std::path::Path;

use std::ffi::OsStr;

use fs;
use fs::inode;
use gd;
use object;

use fs::helpers::{create_inode_directory_attributes, create_inode_file_attributes};
use helpers;

pub struct GoodDataFS {
    pub client: gd::GoodDataClient,
    pub users_cache: users::UsersCache,
}

impl Drop for GoodDataFS {
    fn drop(&mut self) {
        println!("Unmounting GoodData Filesystem");
    }
}

#[allow(dead_code)]
impl GoodDataFS {
    pub fn client(&self) -> &gd::GoodDataClient {
        &self.client
    }

    pub fn get_projects_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_PROJECTS)
    }

    pub fn get_root_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_ROOT)
    }

    pub fn get_user_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.user()).to_string());

        let user = json::decode::<object::AccountSetting>(&json);

        let ts = UTC.datetime_from_str(&user.unwrap().accountSetting.updated.unwrap()[..],
                               "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();

        let updated = time::Timespec::new(ts, 0);

        create_inode_file_attributes(fs::constants::INODE_USER, json.len() as u64, updated)
    }

    pub fn get_projects_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.projects()).to_string());

        create_inode_file_attributes(fs::constants::INODE_PROJECTS_JSON,
                                     json.len() as u64,
                                     fs::constants::DEFAULT_CREATE_TIME)
    }
}

impl Filesystem for GoodDataFS {
    fn getattr(&mut self, req: &Request, ino: u64, reply: ReplyAttr) {
        let inode = inode::Inode::deserialize(ino);
        info!("GoodDataFS::getattr() - Getting attributes {} - {:?}",
              ino,
              inode);

        match ino {
            fs::constants::INODE_ROOT => fs::root::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS => fs::projects::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS_JSON => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_projects_json_attributes())
            }
            fs::constants::INODE_USER => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_user_json_attributes())
            }
            _ => {
                if inode.project > 0 && inode.category == fs::constants::Category::Internal as u8 &&
                   inode.reserved == 0 {
                    fs::projects::getattr(self, req, ino, reply)
                } else if inode.project > 0 {
                    fs::project::getattr(self, req, ino, reply)
                } else {
                    println!("getattr() - HAPR")
                }
            }
        }
    }

    fn lookup(&mut self, req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::lookup() - Looking up parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());

        match parent {
            fs::constants::INODE_ROOT => fs::root::lookup(self, req, parent, name, reply),
            fs::constants::INODE_PROJECTS => fs::projects::lookup(self, req, parent, name, reply),
            _ => {
                if parent_inode.project > 0 {
                    fs::project::lookup(self, req, parent, name, reply)
                }
            }
        }
    }

    fn read(&mut self,
            req: &Request,
            ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        let inode = inode::Inode::deserialize(ino);
        info!("GoodDataFS::read() - Reading inode {} - {:?}, fh: {}, offset: {}, size: {}",
              ino,
              inode,
              fh,
              offset,
              size);

        match ino {
            fs::constants::INODE_PROJECTS_JSON => {
                // println!("off: {}, size {}", offset, size);
                let json = format!("{}\n",
                                   json::as_pretty_json(&self.client.projects_fetch_if_none())
                                       .to_string());
                // let json: String = fs.client.projects().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            fs::constants::INODE_USER => {
                let json: String = self.client.user().clone().unwrap().into();
                reply.data(helpers::read_bytes(&json, offset, size));
            }
            _ => {
                let inode = inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::read(self, req, ino, fh, offset, size, reply);
                } else {
                    println!("read() - HAPR")
                }
            }
        }
    }

    fn readdir(&mut self, req: &Request, ino: u64, fh: u64, offset: u64, reply: ReplyDirectory) {
        let inode = inode::Inode::deserialize(ino);
        info!("GoodDataFS::readdir() - Reading inode {} - {:?}, fh: {}, offset: {}",
              ino,
              inode,
              fh,
              offset);

        match ino {
            fs::constants::INODE_ROOT => {
                if offset == 0 {
                    fs::root::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            fs::constants::INODE_PROJECTS => {
                if offset == 0 {
                    fs::projects::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            _ => {
                let inode: fs::inode::Inode = fs::inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::readdir(self, req, ino, fh, offset, reply)
                }
            }
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &Path, _mode: u32, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::mkdir() - Making dir in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::create(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }

    fn rmdir(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::rmdir() - Removing dir in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::rmdir(self, name, reply),
            _ => {
                println!("WARN: rmdir() not implemented!");
                reply.ok()
                // reply.error(ENOSYS)
            }
        }
    }

    fn unlink(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        info!("GoodDataFS::unlinl() - Removing file in parent {} - {:?}, path: {}",
              parent,
              parent_inode,
              name.to_str().unwrap());
        println!("WARN: unlink() not implemented!");
        reply.ok()
        // reply.error(ENOSYS);
    }
}

impl GoodDataFS {
    pub fn mount(self, mountpoint: String) {
        const VERSION: &'static str = env!("CARGO_PKG_VERSION");
        info!("Mounting GoodData as Filesystem ({}), mountpoint: {}",
              VERSION,
              mountpoint);

        // See https://github.com/osxfuse/osxfuse/wiki/Mount-options
        fuse::mount(self,
                    &mountpoint,
                    &[// &OsStr::new("debug"),
                      &OsStr::new("nolocalcaches"),
                      &OsStr::new("allow_other")]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).

use std::collections::BTreeMap;
use std::i32;

use chrono::{DateTime, UTC};

use DB_POOL;
use domain::github::{IssueComment, IssuePartial, Milestone, PullRequest, GitHubUser};
use error::DashResult;

#[derive(Clone, Debug, Deserialize)]
pub struct MilestoneFromJson {
    pub id: i32,
    pub number: i32,
    pub state: String,
    pub title: String,
    pub description: Option<String>,
    pub creator: GitHubUser,
    pub open_issues: i32,
    pub closed_issues: i32,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub closed_at: Option<DateTime<UTC>>,
    pub due_on: Option<DateTime<UTC>>,
}

impl MilestoneFromJson {
    pub fn with_repo(self, repo: &str) -> Milestone {
        Milestone {
            id: self.id,
            number: self.number,
            open: match &self.state as &str {
                "open" => true,
                _ => false,
            },
            title: self.title.replace(0x00 as char, ""),
            description: self.description.map(|s| s.replace(0x00 as char, "")),
            fk_creator: self.creator.id,
            open_issues: self.open_issues,
            closed_issues: self.closed_issues,
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            closed_at: self.closed_at.map(|t| t.naive_utc()),
            due_on: self.due_on.map(|t| t.naive_utc()),
            repository: repo.to_string(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct LabelFromJson {
    name: String,
    color: String,
}

pub type PullRequestUrls = BTreeMap<String, String>;

#[derive(Debug, Deserialize)]
pub struct IssueFromJson {
    pub number: i32,
    pub user: GitHubUser,
    pub assignee: Option<GitHubUser>,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub labels: Option<Vec<LabelFromJson>>,
    pub milestone: Option<MilestoneFromJson>,
    pub locked: bool,
    pub comments: i32,
    pub pull_request: Option<PullRequestUrls>,
    pub closed_at: Option<DateTime<UTC>>,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub comments_url: String,
}

impl IssueFromJson {
    pub fn with_repo(self, repo: &str) -> (IssuePartial, Option<Milestone>) {
        let milestone_id = match self.milestone {
            Some(ref m) => Some(m.id),
            None => None,
        };

        let issue = IssuePartial {
            number: self.number,
            fk_milestone: milestone_id,
            fk_user: self.user.id,
            fk_assignee: self.assignee.map(|a| a.id),
            open: match &*self.state {
                "open" => true,
                _ => false,
            },
            is_pull_request: self.pull_request.is_some(),
            title: self.title.replace(0x00 as char, ""),
            body: self.body.unwrap_or_else(String::new).replace(0x00 as char, ""),
            locked: self.locked,
            closed_at: self.closed_at.map(|t| t.naive_utc()),
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            labels: match self.labels {
                Some(json_labels) => json_labels.into_iter().map(|l| l.name).collect(),
                None => vec![],
            },
            repository: repo.to_string(),
        };

        (issue, self.milestone.map(|m| m.with_repo(repo)))
    }
}

#[derive(Debug, Deserialize)]
pub struct CommentFromJson {
    pub id: i32,
    pub html_url: String,
    pub body: String,
    pub user: GitHubUser,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
}

impl CommentFromJson {
    pub fn with_repo(self, repo: &str) -> DashResult<IssueComment> {
        use diesel::prelude::*;
        use domain::schema::issue::dsl::*;

        let issue_number = self.html_url
            .split('#')
            .next()
            .map(|r| r.split('/').last().map(|n| n.parse::<i32>()));

        let issue_number = match issue_number {
            Some(Some(Ok(n))) => n,
            _ => {
                // this should never happen
                // hi absurd GitHub search!
                i32::MAX
            }
        };

        let conn = try!(DB_POOL.get());

        let issue_id = try!(issue.select(id)
            .filter(number.eq(issue_number))
            .filter(repository.eq(repo))
            .first::<i32>(&*conn));

        Ok(IssueComment {
            id: self.id,
            fk_issue: issue_id,
            fk_user: self.user.id,
            body: self.body.replace(0x00 as char, ""),
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            repository: repo.to_string(),
        })
    }
}

#[derive(Debug, Deserialize)]
pub struct PullRequestFromJson {
    pub number: i32,
    pub review_comments_url: String,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub assignee: Option<GitHubUser>,
    pub milestone: Option<MilestoneFromJson>,
    pub locked: bool,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub closed_at: Option<DateTime<UTC>>,
    pub merged_at: Option<DateTime<UTC>>,
    pub commits: i32,
    pub additions: i32,
    pub deletions: i32,
    pub changed_files: i32,
}

impl PullRequestFromJson {
    pub fn with_repo(self, repo: &str) -> PullRequest {
        PullRequest {
            number: self.number,
            state: self.state.replace(0x00 as char, ""),
            title: self.title.replace(0x00 as char, ""),
            body: self.body.map(|s| s.replace(0x00 as char, "")),
            fk_assignee: self.assignee.map(|a| a.id),
            fk_milestone: self.milestone.map(|m| m.id),
            locked: self.locked,
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            closed_at: self.closed_at.map(|t| t.naive_utc()),
            merged_at: self.merged_at.map(|t| t.naive_utc()),
            commits: self.commits,
            additions: self.additions,
            deletions: self.deletions,
            changed_files: self.changed_files,
            repository: repo.to_string(),
        }
    }
}
<commit_msg>Simplify github models<commit_after>// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).

use std::collections::BTreeMap;
use std::i32;

use chrono::{DateTime, UTC};

use DB_POOL;
use domain::github::{IssueComment, IssuePartial, Milestone, PullRequest, GitHubUser};
use error::DashResult;

#[derive(Clone, Debug, Deserialize)]
pub struct MilestoneFromJson {
    pub id: i32,
    pub number: i32,
    pub state: String,
    pub title: String,
    pub description: Option<String>,
    pub creator: GitHubUser,
    pub open_issues: i32,
    pub closed_issues: i32,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub closed_at: Option<DateTime<UTC>>,
    pub due_on: Option<DateTime<UTC>>,
}

impl MilestoneFromJson {
    pub fn with_repo(self, repo: &str) -> Milestone {
        Milestone {
            id: self.id,
            number: self.number,
            open: self.state == "open",
            title: self.title.replace(0x00 as char, ""),
            description: self.description.map(|s| s.replace(0x00 as char, "")),
            fk_creator: self.creator.id,
            open_issues: self.open_issues,
            closed_issues: self.closed_issues,
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            closed_at: self.closed_at.map(|t| t.naive_utc()),
            due_on: self.due_on.map(|t| t.naive_utc()),
            repository: repo.to_string(),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct LabelFromJson {
    name: String,
    color: String,
}

pub type PullRequestUrls = BTreeMap<String, String>;

#[derive(Debug, Deserialize)]
pub struct IssueFromJson {
    pub number: i32,
    pub user: GitHubUser,
    pub assignee: Option<GitHubUser>,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub labels: Option<Vec<LabelFromJson>>,
    pub milestone: Option<MilestoneFromJson>,
    pub locked: bool,
    pub comments: i32,
    pub pull_request: Option<PullRequestUrls>,
    pub closed_at: Option<DateTime<UTC>>,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub comments_url: String,
}

impl IssueFromJson {
    pub fn with_repo(self, repo: &str) -> (IssuePartial, Option<Milestone>) {
        let issue = IssuePartial {
            number: self.number,
            fk_milestone: self.milestone.as_ref().map(|m| m.id),
            fk_user: self.user.id,
            fk_assignee: self.assignee.map(|a| a.id),
            open: self.state == "open",
            is_pull_request: self.pull_request.is_some(),
            title: self.title.replace(0x00 as char, ""),
            body: self.body.unwrap_or_else(String::new).replace(0x00 as char, ""),
            locked: self.locked,
            closed_at: self.closed_at.map(|t| t.naive_utc()),
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            labels: match self.labels {
                Some(json_labels) => json_labels.into_iter().map(|l| l.name).collect(),
                None => vec![],
            },
            repository: repo.to_string(),
        };

        (issue, self.milestone.map(|m| m.with_repo(repo)))
    }
}

#[derive(Debug, Deserialize)]
pub struct CommentFromJson {
    pub id: i32,
    pub html_url: String,
    pub body: String,
    pub user: GitHubUser,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
}

impl CommentFromJson {
    pub fn with_repo(self, repo: &str) -> DashResult<IssueComment> {
        use diesel::prelude::*;
        use domain::schema::issue::dsl::*;

        let issue_number = self.html_url
            .split('#')
            .next()
            .map(|r| r.split('/').last().map(|n| n.parse::<i32>()));

        let issue_number = match issue_number {
            Some(Some(Ok(n))) => n,
            _ => {
                // this should never happen
                // hi absurd GitHub search!
                i32::MAX
            }
        };

        let conn = try!(DB_POOL.get());

        let issue_id = try!(issue.select(id)
            .filter(number.eq(issue_number))
            .filter(repository.eq(repo))
            .first::<i32>(&*conn));

        Ok(IssueComment {
            id: self.id,
            fk_issue: issue_id,
            fk_user: self.user.id,
            body: self.body.replace(0x00 as char, ""),
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            repository: repo.to_string(),
        })
    }
}

#[derive(Debug, Deserialize)]
pub struct PullRequestFromJson {
    pub number: i32,
    pub review_comments_url: String,
    pub state: String,
    pub title: String,
    pub body: Option<String>,
    pub assignee: Option<GitHubUser>,
    pub milestone: Option<MilestoneFromJson>,
    pub locked: bool,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub closed_at: Option<DateTime<UTC>>,
    pub merged_at: Option<DateTime<UTC>>,
    pub commits: i32,
    pub additions: i32,
    pub deletions: i32,
    pub changed_files: i32,
}

impl PullRequestFromJson {
    pub fn with_repo(self, repo: &str) -> PullRequest {
        PullRequest {
            number: self.number,
            state: self.state.replace(0x00 as char, ""),
            title: self.title.replace(0x00 as char, ""),
            body: self.body.map(|s| s.replace(0x00 as char, "")),
            fk_assignee: self.assignee.map(|a| a.id),
            fk_milestone: self.milestone.map(|m| m.id),
            locked: self.locked,
            created_at: self.created_at.naive_utc(),
            updated_at: self.updated_at.naive_utc(),
            closed_at: self.closed_at.map(|t| t.naive_utc()),
            merged_at: self.merged_at.map(|t| t.naive_utc()),
            commits: self.commits,
            additions: self.additions,
            deletions: self.deletions,
            changed_files: self.changed_files,
            repository: repo.to_string(),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Format code and insert assertion<commit_after><|endoftext|>


<commit_before><commit_msg>Added xdg-positioner, fixes #236<commit_after><|endoftext|>


<commit_before>//! WebSocket handshake control.

pub mod headers;
pub mod client;
pub mod server;

mod machine;

use std::io::{Read, Write};

use base64;
use sha1::Sha1;

use error::Error;
use protocol::WebSocket;

use self::machine::{HandshakeMachine, RoundResult, StageResult, TryParse};

/// A WebSocket handshake.
pub struct MidHandshake<Stream, Role> {
    role: Role,
    machine: HandshakeMachine<Stream>,
}

impl<Stream, Role> MidHandshake<Stream, Role> {
    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &Stream {
        self.machine.get_ref()
    }
    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut Stream {
        self.machine.get_mut()
    }
}

impl<Stream: Read + Write, Role: HandshakeRole> MidHandshake<Stream, Role> {
    /// Restarts the handshake process.
    pub fn handshake(self) -> Result<WebSocket<Stream>, HandshakeError<Stream, Role>> {
        let mut mach = self.machine;
        loop {
            mach = match mach.single_round()? {
                RoundResult::WouldBlock(m) => {
                    return Err(HandshakeError::Interrupted(MidHandshake { machine: m, ..self }))
                }
                RoundResult::Incomplete(m) => m,
                RoundResult::StageFinished(s) => {
                    match self.role.stage_finished(s)? {
                        ProcessingResult::Continue(m) => m,
                        ProcessingResult::Done(ws) => return Ok(ws),
                    }
                }
            }
        }
    }
}

/// A handshake result.
pub enum HandshakeError<Stream, Role> {
    /// Handshake was interrupted (would block).
    Interrupted(MidHandshake<Stream, Role>),
    /// Handshake failed.
    Failure(Error),
}

impl<Stream, Role> From<Error> for HandshakeError<Stream, Role> {
    fn from(err: Error) -> Self {
        HandshakeError::Failure(err)
    }
}

/// Handshake role.
pub trait HandshakeRole {
    #[doc(hidden)]
    type IncomingData: TryParse;
    #[doc(hidden)]
    fn stage_finished<Stream>(&self, finish: StageResult<Self::IncomingData, Stream>)
        -> Result<ProcessingResult<Stream>, Error>;
}

/// Stage processing result.
#[doc(hidden)]
pub enum ProcessingResult<Stream> {
    Continue(HandshakeMachine<Stream>),
    Done(WebSocket<Stream>),
}

/// Turns a Sec-WebSocket-Key into a Sec-WebSocket-Accept.
fn convert_key(input: &[u8]) -> Result<String, Error> {
    // ... field is constructed by concatenating /key/ ...
    // ... with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455)
    const WS_GUID: &'static [u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    let mut sha1 = Sha1::new();
    sha1.update(input);
    sha1.update(WS_GUID);
    Ok(base64::encode(&sha1.digest().bytes()))
}

#[cfg(test)]
mod tests {

    use super::convert_key;

    #[test]
    fn key_conversion() {
        // example from RFC 6455
        assert_eq!(convert_key(b"dGhlIHNhbXBsZSBub25jZQ==").unwrap(),
                               "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
    }

}
<commit_msg>Add Debug, Display and Error to HandshakeError<commit_after>//! WebSocket handshake control.

pub mod headers;
pub mod client;
pub mod server;

mod machine;

use std::error::Error as ErrorTrait;
use std::fmt;
use std::io::{Read, Write};

use base64;
use sha1::Sha1;

use error::Error;
use protocol::WebSocket;

use self::machine::{HandshakeMachine, RoundResult, StageResult, TryParse};

/// A WebSocket handshake.
pub struct MidHandshake<Stream, Role> {
    role: Role,
    machine: HandshakeMachine<Stream>,
}

impl<Stream, Role> MidHandshake<Stream, Role> {
    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &Stream {
        self.machine.get_ref()
    }
    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut Stream {
        self.machine.get_mut()
    }
}

impl<Stream: Read + Write, Role: HandshakeRole> MidHandshake<Stream, Role> {
    /// Restarts the handshake process.
    pub fn handshake(self) -> Result<WebSocket<Stream>, HandshakeError<Stream, Role>> {
        let mut mach = self.machine;
        loop {
            mach = match mach.single_round()? {
                RoundResult::WouldBlock(m) => {
                    return Err(HandshakeError::Interrupted(MidHandshake { machine: m, ..self }))
                }
                RoundResult::Incomplete(m) => m,
                RoundResult::StageFinished(s) => {
                    match self.role.stage_finished(s)? {
                        ProcessingResult::Continue(m) => m,
                        ProcessingResult::Done(ws) => return Ok(ws),
                    }
                }
            }
        }
    }
}

/// A handshake result.
pub enum HandshakeError<Stream, Role> {
    /// Handshake was interrupted (would block).
    Interrupted(MidHandshake<Stream, Role>),
    /// Handshake failed.
    Failure(Error),
}

impl<Stream, Role> fmt::Debug for HandshakeError<Stream, Role> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HandshakeError::Interrupted(_) => write!(f, "HandshakeError::Interrupted(...)"),
            HandshakeError::Failure(ref e) => write!(f, "HandshakeError::Failure({:?})", e),
        }
    }
}

impl<Stream, Role> fmt::Display for HandshakeError<Stream, Role> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HandshakeError::Interrupted(_) => write!(f, "Interrupted handshake (WouldBlock)"),
            HandshakeError::Failure(ref e) => write!(f, "{}", e),
        }
    }
}

impl<Stream, Role> ErrorTrait for HandshakeError<Stream, Role> {
    fn description(&self) -> &str {
        match *self {
            HandshakeError::Interrupted(_) => "Interrupted handshake",
            HandshakeError::Failure(ref e) => e.description(),
        }
    }
}

impl<Stream, Role> From<Error> for HandshakeError<Stream, Role> {
    fn from(err: Error) -> Self {
        HandshakeError::Failure(err)
    }
}

/// Handshake role.
pub trait HandshakeRole {
    #[doc(hidden)]
    type IncomingData: TryParse;
    #[doc(hidden)]
    fn stage_finished<Stream>(&self, finish: StageResult<Self::IncomingData, Stream>)
        -> Result<ProcessingResult<Stream>, Error>;
}

/// Stage processing result.
#[doc(hidden)]
pub enum ProcessingResult<Stream> {
    Continue(HandshakeMachine<Stream>),
    Done(WebSocket<Stream>),
}

/// Turns a Sec-WebSocket-Key into a Sec-WebSocket-Accept.
fn convert_key(input: &[u8]) -> Result<String, Error> {
    // ... field is constructed by concatenating /key/ ...
    // ... with the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (RFC 6455)
    const WS_GUID: &'static [u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    let mut sha1 = Sha1::new();
    sha1.update(input);
    sha1.update(WS_GUID);
    Ok(base64::encode(&sha1.digest().bytes()))
}

#[cfg(test)]
mod tests {

    use super::convert_key;

    #[test]
    fn key_conversion() {
        // example from RFC 6455
        assert_eq!(convert_key(b"dGhlIHNhbXBsZSBub25jZQ==").unwrap(),
                               "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
    }

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Borders, padding, and margins.

use std::num::Zero;
use geom::side_offsets::SideOffsets2D;
use gfx::geometry::Au;
use newcss::complete::CompleteStyle;
use newcss::units::{Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin, CSSFontSize, CSSFontSizeLength};
use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto};
use newcss::values::{CSSHeight, CSSHeightLength, CSSHeightPercentage, CSSHeightAuto};
use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto};
use newcss::values::{CSSPadding, CSSPaddingLength, CSSPaddingPercentage};
/// Encapsulates the borders, padding, and margins, which we collectively call the "box model".
pub struct BoxModel {
    border: SideOffsets2D<Au>,
    padding: SideOffsets2D<Au>,
    margin: SideOffsets2D<Au>,
    /// The width of the content box.
    content_box_width: Au,
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
    Auto,
    Specified(Au),
}

impl MaybeAuto {
    pub fn from_margin(margin: CSSMargin, cb_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match margin {
            CSSMarginAuto => Auto,
            CSSMarginPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)),
            CSSMarginLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSMarginLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSMarginLength(Em(em)) => match font_size {
                CSSFontSizeLength(Px(v)) =>
                    Specified(Au::from_frac_px(em * v)),
                CSSFontSizeLength(Pt(v)) =>
                    Specified(Au::from_pt(em * v)),
                _ => fail!(~"expected non-relative font size"),
            }
        }
    }

    pub fn from_width(width: CSSWidth, cb_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match width {
            CSSWidthAuto => Auto,
            CSSWidthPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)),
            CSSWidthLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSWidthLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSWidthLength(Em(em)) => match font_size {
                CSSFontSizeLength(Px(v)) =>
                    Specified(Au::from_frac_px(em * v)),
                CSSFontSizeLength(Pt(v)) =>
                    Specified(Au::from_pt(em * v)),
                _ => fail!(~"expected non-relative font size"),
            }
        }
    }

    pub fn from_height(height: CSSHeight, cb_height: Au, font_size: CSSFontSize) -> MaybeAuto {
        match height {
            CSSHeightAuto => Auto,
            CSSHeightPercentage(percent) => Specified(cb_height.scale_by(percent/100.0)),
            CSSHeightLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSHeightLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSHeightLength(Em(em)) => match font_size {
                CSSFontSizeLength(Px(v)) =>
                    Specified(Au::from_frac_px(em * v)),
                CSSFontSizeLength(Pt(v)) =>
                    Specified(Au::from_pt(em * v)),
                _ => fail!(~"expected non-relative font size"),
            }

        }
    }

    pub fn specified_or_default(&self, default: Au) -> Au {
        match *self {
            Auto => default,
            Specified(value) => value,
        }
    }

    pub fn specified_or_zero(&self) -> Au {
        self.specified_or_default(Au(0))
    }
}

impl Zero for BoxModel {
    fn zero() -> BoxModel {
        BoxModel {
            border: Zero::zero(),
            padding: Zero::zero(),
            margin: Zero::zero(),
            content_box_width: Zero::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero()
    }
}

impl BoxModel {
    /// Populates the box model parameters from the given computed style.
    pub fn compute_borders(&mut self, style: CompleteStyle) {
        // Compute the borders.
        self.border.top = self.compute_border_width(style.border_top_width(), style.font_size());
        self.border.right = self.compute_border_width(style.border_right_width(), style.font_size());
        self.border.bottom = self.compute_border_width(style.border_bottom_width(), style.font_size());
        self.border.left = self.compute_border_width(style.border_left_width(), style.font_size());
    }

    pub fn compute_padding(&mut self, style: CompleteStyle, cb_width: Au) {
        self.padding.top = self.compute_padding_length(style.padding_top(), cb_width, style.font_size());
        self.padding.right = self.compute_padding_length(style.padding_right(), cb_width, style.font_size());
        self.padding.bottom = self.compute_padding_length(style.padding_bottom(), cb_width, style.font_size());
        self.padding.left = self.compute_padding_length(style.padding_left(), cb_width, style.font_size());
    }

    pub fn noncontent_width(&self) -> Au {
        let left = self.margin.left + self.border.left + self.padding.left;
        let right = self.margin.right + self.border.right + self.padding.right;
        left + right
    }

    pub fn offset(&self) -> Au {
        self.margin.left + self.border.left + self.padding.left
    }

    /// Helper function to compute the border width in app units from the CSS border width.
    pub fn compute_border_width(&self, width: CSSBorderWidth, font_size: CSSFontSize) -> Au {
        match width {
            CSSBorderWidthLength(Px(v)) => Au::from_frac_px(v),
            CSSBorderWidthLength(Pt(v)) => Au::from_pt(v),
            CSSBorderWidthLength(Em(em)) => match font_size {
                CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                _ => fail!(~"expected non-relative font size"),
            },
            CSSBorderWidthThin => Au::from_px(1),
            CSSBorderWidthMedium => Au::from_px(5),
            CSSBorderWidthThick => Au::from_px(10),
        }
    }

    pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au, font_size: CSSFontSize) -> Au {
        match padding {
            CSSPaddingLength(Px(v)) => Au::from_frac_px(v),
            CSSPaddingLength(Pt(v)) => Au::from_pt(v),
            CSSPaddingLength(Em(em)) => match font_size {
                CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                _ => fail!(~"expected non-relative font size"),
            },
            CSSPaddingPercentage(p) => content_box_width.scale_by(p/100.0)
        }
    }
}
<commit_msg>Brace multi-line match patterns per coding style.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Borders, padding, and margins.

use std::num::Zero;
use geom::side_offsets::SideOffsets2D;
use gfx::geometry::Au;
use newcss::complete::CompleteStyle;
use newcss::units::{Em, Pt, Px};
use newcss::values::{CSSBorderWidth, CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSBorderWidthThick, CSSBorderWidthThin, CSSFontSize, CSSFontSizeLength};
use newcss::values::{CSSWidth, CSSWidthLength, CSSWidthPercentage, CSSWidthAuto};
use newcss::values::{CSSHeight, CSSHeightLength, CSSHeightPercentage, CSSHeightAuto};
use newcss::values::{CSSMargin, CSSMarginLength, CSSMarginPercentage, CSSMarginAuto};
use newcss::values::{CSSPadding, CSSPaddingLength, CSSPaddingPercentage};
/// Encapsulates the borders, padding, and margins, which we collectively call the "box model".
pub struct BoxModel {
    border: SideOffsets2D<Au>,
    padding: SideOffsets2D<Au>,
    margin: SideOffsets2D<Au>,
    /// The width of the content box.
    content_box_width: Au,
}

/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
    Auto,
    Specified(Au),
}

impl MaybeAuto {
    pub fn from_margin(margin: CSSMargin, cb_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match margin {
            CSSMarginAuto => Auto,
            CSSMarginPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)),
            CSSMarginLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSMarginLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSMarginLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Specified(Au::from_frac_px(em * v)),
                    CSSFontSizeLength(Pt(v)) => Specified(Au::from_pt(em * v)),
                    _ => fail!(~"expected non-relative font size"),
                }
            }
        }
    }

    pub fn from_width(width: CSSWidth, cb_width: Au, font_size: CSSFontSize) -> MaybeAuto {
        match width {
            CSSWidthAuto => Auto,
            CSSWidthPercentage(percent) => Specified(cb_width.scale_by(percent/100.0)),
            CSSWidthLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSWidthLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSWidthLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Specified(Au::from_frac_px(em * v)),
                    CSSFontSizeLength(Pt(v)) => Specified(Au::from_pt(em * v)),
                    _ => fail!(~"expected non-relative font size"),
                }
            }
        }
    }

    pub fn from_height(height: CSSHeight, cb_height: Au, font_size: CSSFontSize) -> MaybeAuto {
        match height {
            CSSHeightAuto => Auto,
            CSSHeightPercentage(percent) => Specified(cb_height.scale_by(percent/100.0)),
            CSSHeightLength(Px(v)) => Specified(Au::from_frac_px(v)),
            CSSHeightLength(Pt(v)) => Specified(Au::from_pt(v)),
            CSSHeightLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Specified(Au::from_frac_px(em * v)),
                    CSSFontSizeLength(Pt(v)) => Specified(Au::from_pt(em * v)),
                    _ => fail!(~"expected non-relative font size"),
                }
            }

        }
    }

    pub fn specified_or_default(&self, default: Au) -> Au {
        match *self {
            Auto => default,
            Specified(value) => value,
        }
    }

    pub fn specified_or_zero(&self) -> Au {
        self.specified_or_default(Au(0))
    }
}

impl Zero for BoxModel {
    fn zero() -> BoxModel {
        BoxModel {
            border: Zero::zero(),
            padding: Zero::zero(),
            margin: Zero::zero(),
            content_box_width: Zero::zero(),
        }
    }

    fn is_zero(&self) -> bool {
        self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero()
    }
}

impl BoxModel {
    /// Populates the box model parameters from the given computed style.
    pub fn compute_borders(&mut self, style: CompleteStyle) {
        // Compute the borders.
        self.border.top = self.compute_border_width(style.border_top_width(), style.font_size());
        self.border.right = self.compute_border_width(style.border_right_width(), style.font_size());
        self.border.bottom = self.compute_border_width(style.border_bottom_width(), style.font_size());
        self.border.left = self.compute_border_width(style.border_left_width(), style.font_size());
    }

    pub fn compute_padding(&mut self, style: CompleteStyle, cb_width: Au) {
        self.padding.top = self.compute_padding_length(style.padding_top(), cb_width, style.font_size());
        self.padding.right = self.compute_padding_length(style.padding_right(), cb_width, style.font_size());
        self.padding.bottom = self.compute_padding_length(style.padding_bottom(), cb_width, style.font_size());
        self.padding.left = self.compute_padding_length(style.padding_left(), cb_width, style.font_size());
    }

    pub fn noncontent_width(&self) -> Au {
        let left = self.margin.left + self.border.left + self.padding.left;
        let right = self.margin.right + self.border.right + self.padding.right;
        left + right
    }

    pub fn offset(&self) -> Au {
        self.margin.left + self.border.left + self.padding.left
    }

    /// Helper function to compute the border width in app units from the CSS border width.
    pub fn compute_border_width(&self, width: CSSBorderWidth, font_size: CSSFontSize) -> Au {
        match width {
            CSSBorderWidthLength(Px(v)) => Au::from_frac_px(v),
            CSSBorderWidthLength(Pt(v)) => Au::from_pt(v),
            CSSBorderWidthLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                    CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                    _ => fail!(~"expected non-relative font size"),
                }
            },
            CSSBorderWidthThin => Au::from_px(1),
            CSSBorderWidthMedium => Au::from_px(5),
            CSSBorderWidthThick => Au::from_px(10),
        }
    }

    pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au, font_size: CSSFontSize) -> Au {
        match padding {
            CSSPaddingLength(Px(v)) => Au::from_frac_px(v),
            CSSPaddingLength(Pt(v)) => Au::from_pt(v),
            CSSPaddingLength(Em(em)) => {
                match font_size {
                    CSSFontSizeLength(Px(v)) => Au::from_frac_px(em * v),
                    CSSFontSizeLength(Pt(v)) => Au::from_pt(em * v),
                    _ => fail!(~"expected non-relative font size"),
                }
            },
            CSSPaddingPercentage(p) => content_box_width.scale_by(p/100.0)
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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.
//

/// This module is responsible for handling the .delivery/config.json file

use std::collections::HashMap;
use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;

use rustc_serialize::json;
use rustc_serialize::json::DecoderError;

use errors::DeliveryError;
use git;
use utils::mkdir_recursive;
use utils::path_join_many::PathJoinMany;
use utils::say::{say, sayln};
use utils::path_ext::{is_dir, is_file};

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct DeliveryConfig {
    pub version: String,
    pub build_cookbook: HashMap<String, String>,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>,
    pub dependencies: Option<Vec<String>>
}

// v1 config, deprecated, but still supported
#[derive(RustcDecodable)]
pub struct DeliveryConfigV1 {
    pub version: String,
    pub build_cookbook: String,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>
}

impl Default for DeliveryConfig {
    fn default() -> DeliveryConfig {
        let mut build_cookbook = HashMap::new();
        build_cookbook.insert("name".to_string(),
                              "build-cookbook".to_string());
        build_cookbook.insert("path".to_string(),
                              ".delivery/build-cookbook".to_string());
        DeliveryConfig {
            version: "2".to_string(),
            build_cookbook: build_cookbook,
            skip_phases: Some(Vec::new()),
            build_nodes: Some(HashMap::new()),
            dependencies: Some(Vec::new())
        }
    }
}

impl DeliveryConfig {
    pub fn init(proj_path: &PathBuf) -> Result<(), DeliveryError> {
        if DeliveryConfig::config_file_exists(proj_path) {
            debug!("Delivery config file already exists, skipping");
            return Ok(())
        }

        debug!("proj_path: {:?}\n", proj_path);
        debug!("Creating a new config file");

        let config = DeliveryConfig::default();
        try!(config.write_file(proj_path));
        let config_path = DeliveryConfig::config_file_path(proj_path);
        let config_path_str = &config_path.to_str().unwrap();
        try!(git::git_command(&["checkout", "-b", "add-delivery-config"], proj_path));
        try!(git::git_command(&["add", &config_path_str], proj_path));
        try!(git::git_command(&["commit", "-m", "Add Delivery config"], proj_path));
        Ok(())
    }

    fn config_file_path(proj_path: &PathBuf) -> PathBuf {
        proj_path.join_many(&[".delivery", "config.json"])
    }

    fn config_file_exists(proj_path: &PathBuf) -> bool {
        is_file(&DeliveryConfig::config_file_path(proj_path))
    }

    pub fn validate_config_file(proj_path: &PathBuf) -> Result<bool, DeliveryError> {
        let config_file_path = DeliveryConfig::config_file_path(proj_path);
        let mut config_file = try!(File::open(&config_file_path));
        let mut config_file_content = String::new();
        try!(config_file.read_to_string(&mut config_file_content));
        let config_file_content_str = config_file_content.trim();
        // try to parse it as v2
        let parse_v2_result: Result<DeliveryConfig, DecoderError> = json::decode(config_file_content_str);
        let result = match parse_v2_result {
            Ok(_) => Ok(true),
            Err(_) => {
                // then try as v1
                let parse_v1_result: Result<DeliveryConfigV1, DecoderError> = json::decode(config_file_content_str);
                match parse_v1_result {
                    Ok(_) => Ok(true),
                    Err(e) => Err(e)
                }
            }
        };
        // convert any error in a delivery error
        let boolean_result = try!(result);
        Ok(boolean_result)
    }

    fn write_file(&self, proj_path: &PathBuf) -> Result<(), DeliveryError> {
        let write_dir = proj_path.join_many(&[".delivery"]);
        if !is_dir(&write_dir) {
            try!(mkdir_recursive(&write_dir));
        }
        let write_path = DeliveryConfig::config_file_path(proj_path);
        say("white", "Writing configuration to ");
        sayln("yellow", &format!("{}", write_path.display()));
        let mut f = try!(File::create(&write_path));
        let json_obj = json::as_pretty_json(&self);
        let json_string = format!("{}", json_obj);
        sayln("magenta", "New delivery configuration");
        sayln("magenta", "--------------------------");
        say("white", &json_string);
        try!(f.write_all(json_string.as_bytes()));
        Ok(())
    }
}
<commit_msg>Add newline to JSON config output<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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.
//

/// This module is responsible for handling the .delivery/config.json file

use std::collections::HashMap;
use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;

use rustc_serialize::json;
use rustc_serialize::json::DecoderError;

use errors::DeliveryError;
use git;
use utils::mkdir_recursive;
use utils::path_join_many::PathJoinMany;
use utils::say::{say, sayln};
use utils::path_ext::{is_dir, is_file};

#[derive(RustcEncodable, RustcDecodable, Clone)]
pub struct DeliveryConfig {
    pub version: String,
    pub build_cookbook: HashMap<String, String>,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>,
    pub dependencies: Option<Vec<String>>
}

// v1 config, deprecated, but still supported
#[derive(RustcDecodable)]
pub struct DeliveryConfigV1 {
    pub version: String,
    pub build_cookbook: String,
    pub skip_phases: Option<Vec<String>>,
    pub build_nodes: Option<HashMap<String, Vec<String>>>
}

impl Default for DeliveryConfig {
    fn default() -> DeliveryConfig {
        let mut build_cookbook = HashMap::new();
        build_cookbook.insert("name".to_string(),
                              "build-cookbook".to_string());
        build_cookbook.insert("path".to_string(),
                              ".delivery/build-cookbook".to_string());
        DeliveryConfig {
            version: "2".to_string(),
            build_cookbook: build_cookbook,
            skip_phases: Some(Vec::new()),
            build_nodes: Some(HashMap::new()),
            dependencies: Some(Vec::new())
        }
    }
}

impl DeliveryConfig {
    pub fn init(proj_path: &PathBuf) -> Result<(), DeliveryError> {
        if DeliveryConfig::config_file_exists(proj_path) {
            debug!("Delivery config file already exists, skipping");
            return Ok(())
        }

        debug!("proj_path: {:?}\n", proj_path);
        debug!("Creating a new config file");

        let config = DeliveryConfig::default();
        try!(config.write_file(proj_path));
        let config_path = DeliveryConfig::config_file_path(proj_path);
        let config_path_str = &config_path.to_str().unwrap();
        try!(git::git_command(&["checkout", "-b", "add-delivery-config"], proj_path));
        try!(git::git_command(&["add", &config_path_str], proj_path));
        try!(git::git_command(&["commit", "-m", "Add Delivery config"], proj_path));
        Ok(())
    }

    fn config_file_path(proj_path: &PathBuf) -> PathBuf {
        proj_path.join_many(&[".delivery", "config.json"])
    }

    fn config_file_exists(proj_path: &PathBuf) -> bool {
        is_file(&DeliveryConfig::config_file_path(proj_path))
    }

    pub fn validate_config_file(proj_path: &PathBuf) -> Result<bool, DeliveryError> {
        let config_file_path = DeliveryConfig::config_file_path(proj_path);
        let mut config_file = try!(File::open(&config_file_path));
        let mut config_file_content = String::new();
        try!(config_file.read_to_string(&mut config_file_content));
        let config_file_content_str = config_file_content.trim();
        // try to parse it as v2
        let parse_v2_result: Result<DeliveryConfig, DecoderError> = json::decode(config_file_content_str);
        let result = match parse_v2_result {
            Ok(_) => Ok(true),
            Err(_) => {
                // then try as v1
                let parse_v1_result: Result<DeliveryConfigV1, DecoderError> = json::decode(config_file_content_str);
                match parse_v1_result {
                    Ok(_) => Ok(true),
                    Err(e) => Err(e)
                }
            }
        };
        // convert any error in a delivery error
        let boolean_result = try!(result);
        Ok(boolean_result)
    }

    fn write_file(&self, proj_path: &PathBuf) -> Result<(), DeliveryError> {
        let write_dir = proj_path.join_many(&[".delivery"]);
        if !is_dir(&write_dir) {
            try!(mkdir_recursive(&write_dir));
        }
        let write_path = DeliveryConfig::config_file_path(proj_path);
        say("white", "Writing configuration to ");
        sayln("yellow", &format!("{}", write_path.display()));
        let mut f = try!(File::create(&write_path));
        let json_obj = json::as_pretty_json(&self);
        let json_string = format!("{}", json_obj);
        sayln("magenta", "New delivery configuration");
        sayln("magenta", "--------------------------");
        sayln("white", &json_string);
        try!(f.write_all(json_string.as_bytes()));
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Main module to handle the layout.
//! This is where the i3-specific code is.

pub mod layout {
    use super::super::container::{Container, Handle, ContainerType};
    use super::super::tree::Node;
    use super::super::super::rustwlc::handle::{WlcView, WlcOutput};

    use std::sync::Mutex;

    use std::ptr;

    struct RootNode {
        root: Node,
        active_container: *const Node,
    }

    impl RootNode {
        fn get_active_container(&self) -> Option<&Node> {
            if self.active_container.is_null() {
                None
            } else {
                unsafe {
                    Some(&*self.active_container)
                }
            }
        }
    }

    unsafe impl Send for RootNode {}

    lazy_static! {
        static ref ROOT: Mutex<RootNode> = {
            Mutex::new(RootNode{
                root: Node::new(Container::new_root()),
                active_container: ptr::null(),
            })
        };
    }

    pub fn add_output(wlc_output: WlcOutput) {
        let mut root = ROOT.lock().unwrap();
        let output = Container::new_output(wlc_output);
        root.root.new_child(output);
        drop(root);
        add_workspace(&"1");
        switch_workspace(&"1");
    }

    pub fn add_workspace(name: &str) {
        trace!("Adding new workspace to root");
        let mut root = ROOT.lock().unwrap();
        let workspace = Container::new_workspace(name.to_string());
        // NOTE handle multiple outputs
        root.root.get_children_mut()[0].new_child(workspace);
    }

    pub fn add_view(wlc_view: WlcView) {
        let mut root = ROOT.lock().unwrap();
        if let Some(current_workspace) = get_current_workspace(&root) {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            current_workspace.new_child(Container::new_view(wlc_view));
        }
    }

    pub fn remove_view(wlc_view: &WlcView) {
        let mut root = ROOT.lock().unwrap();
        if let Some(view) = root.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().unwrap();
            parent.remove_child(view);
        }
    }

    pub fn switch_workspace(name: &str) {
        trace!("Switching to workspace {}", name);
        let mut root = ROOT.lock().unwrap();
        if let Some(old_workspace) = get_current_workspace(&root) {
            // Make all the views in the original workspace to be invisible
            for view in old_workspace.get_children_mut() {
                trace!("Setting {:?} invisible", view);
                match view.get_val().get_handle().unwrap() {
                    Handle::View(view) => view.set_mask(0),
                    _ => {},
                }
            }
        }
        let current_workspace: *const Node;
        {
            let new_current_workspace: &mut Node;
            if let Some(_) = get_workspace_by_name(&root, name) {
                trace!("Found workspace {}", name);
                new_current_workspace = get_workspace_by_name_mut(&mut root, name).unwrap();
            } else {
                drop(root);
                add_workspace(name);
                root = ROOT.lock().unwrap();
                new_current_workspace = get_workspace_by_name_mut(&mut root, name).unwrap();
            }
            for view in new_current_workspace.get_children_mut() {
                trace!("Setting {:?} visible", view);
                match view.get_val().get_handle().unwrap() {
                    Handle::View(view) => view.set_mask(1),
                    _ => {},
                }
            }
            // Set the first view to be focused, so that the view is updated to this new workspace
            if new_current_workspace.get_children().len() > 0 {
                trace!("Focusing view");
                match new_current_workspace.get_children_mut()[0].get_val().get_handle().unwrap() {
                    Handle::View(view) => view.focus(),
                    _ => {},
                }
            } else {
                WlcView::root().focus();
            }
            current_workspace = new_current_workspace as *const Node;
        }
        root.active_container = current_workspace;
    }

    fn get_focused_workspace<'a>(root: &'a RootNode) -> Option<&'a Node> {
        for output in root.root.get_children() {
            if output.get_val().is_focused() {
                for workspace in output.get_children() {
                    if workspace.get_val().is_focused() {
                        return Some(workspace);
                    }
                }
            }
        }
        None

    }

    fn get_current_workspace<'a>(root: &'a RootNode) -> Option<&'a mut Node> {
        if let Some(container) = root.get_active_container() {
            //if let Some(child) = container.get_ancestor_of_type(ContainerType::Workspace) {
                //return child.get_children()[0].get_parent()

            //}
            // NOTE hack here, remove commented code above to make this work properly
            let parent = container.get_parent().unwrap();
            for child in parent.get_children_mut() {
                if child == container {
                    return Some(child);
                }
            }
        }
        return None
    }

    fn get_workspace_by_name<'a, 'b>(root: &'a RootNode, name: &'b str) -> Option<&'a Node> {
        for child in root.root.get_children()[0].get_children() {
            if child.get_val().get_name().unwrap() != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn get_workspace_by_name_mut<'a, 'b>(root: &'a mut RootNode, name: &'b str) -> Option<&'a mut Node> {
        for child in root.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().unwrap() != name {
                continue
            }
            return Some(child);
        }
        return None
    }
 }

<commit_msg>RootNode -> Tree<commit_after>//! Main module to handle the layout.
//! This is where the i3-specific code is.

pub mod layout {
    use super::super::container::{Container, Handle, ContainerType};
    use super::super::tree::Node;
    use super::super::super::rustwlc::handle::{WlcView, WlcOutput};

    use std::sync::Mutex;

    use std::ptr;

    struct Tree {
        root: Node,
        active_container: *const Node,
    }

    impl Tree {
        fn get_active_container(&self) -> Option<&Node> {
            if self.active_container.is_null() {
                None
            } else {
                unsafe {
                    Some(&*self.active_container)
                }
            }
        }
    }

    unsafe impl Send for Tree {}

    lazy_static! {
        static ref TREE: Mutex<Tree> = {
            Mutex::new(Tree{
                root: Node::new(Container::new_root()),
                active_container: ptr::null(),
            })
        };
    }

    pub fn add_output(wlc_output: WlcOutput) {
        let mut root = TREE.lock().unwrap();
        let output = Container::new_output(wlc_output);
        root.root.new_child(output);
        drop(root);
        add_workspace(&"1");
        switch_workspace(&"1");
    }

    pub fn add_workspace(name: &str) {
        trace!("Adding new workspace to root");
        let mut root = TREE.lock().unwrap();
        let workspace = Container::new_workspace(name.to_string());
        // NOTE handle multiple outputs
        root.root.get_children_mut()[0].new_child(workspace);
    }

    pub fn add_view(wlc_view: WlcView) {
        let mut root = TREE.lock().unwrap();
        if let Some(current_workspace) = get_current_workspace(&root) {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            current_workspace.new_child(Container::new_view(wlc_view));
        }
    }

    pub fn remove_view(wlc_view: &WlcView) {
        let mut root = TREE.lock().unwrap();
        if let Some(view) = root.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().unwrap();
            parent.remove_child(view);
        }
    }

    pub fn switch_workspace(name: &str) {
        trace!("Switching to workspace {}", name);
        let mut root = TREE.lock().unwrap();
        if let Some(old_workspace) = get_current_workspace(&root) {
            // Make all the views in the original workspace to be invisible
            for view in old_workspace.get_children_mut() {
                trace!("Setting {:?} invisible", view);
                match view.get_val().get_handle().unwrap() {
                    Handle::View(view) => view.set_mask(0),
                    _ => {},
                }
            }
        }
        let current_workspace: *const Node;
        {
            let new_current_workspace: &mut Node;
            if let Some(_) = get_workspace_by_name(&root, name) {
                trace!("Found workspace {}", name);
                new_current_workspace = get_workspace_by_name_mut(&mut root, name).unwrap();
            } else {
                drop(root);
                add_workspace(name);
                root = TREE.lock().unwrap();
                new_current_workspace = get_workspace_by_name_mut(&mut root, name).unwrap();
            }
            for view in new_current_workspace.get_children_mut() {
                trace!("Setting {:?} visible", view);
                match view.get_val().get_handle().unwrap() {
                    Handle::View(view) => view.set_mask(1),
                    _ => {},
                }
            }
            // Set the first view to be focused, so that the view is updated to this new workspace
            if new_current_workspace.get_children().len() > 0 {
                trace!("Focusing view");
                match new_current_workspace.get_children_mut()[0].get_val().get_handle().unwrap() {
                    Handle::View(view) => view.focus(),
                    _ => {},
                }
            } else {
                WlcView::root().focus();
            }
            current_workspace = new_current_workspace as *const Node;
        }
        root.active_container = current_workspace;
    }

    fn get_focused_workspace<'a>(root: &'a Tree) -> Option<&'a Node> {
        for output in root.root.get_children() {
            if output.get_val().is_focused() {
                for workspace in output.get_children() {
                    if workspace.get_val().is_focused() {
                        return Some(workspace);
                    }
                }
            }
        }
        None

    }

    fn get_current_workspace<'a>(root: &'a Tree) -> Option<&'a mut Node> {
        if let Some(container) = root.get_active_container() {
            //if let Some(child) = container.get_ancestor_of_type(ContainerType::Workspace) {
                //return child.get_children()[0].get_parent()

            //}
            // NOTE hack here, remove commented code above to make this work properly
            let parent = container.get_parent().unwrap();
            for child in parent.get_children_mut() {
                if child == container {
                    return Some(child);
                }
            }
        }
        return None
    }

    fn get_workspace_by_name<'a, 'b>(root: &'a Tree, name: &'b str) -> Option<&'a Node> {
        for child in root.root.get_children()[0].get_children() {
            if child.get_val().get_name().unwrap() != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn get_workspace_by_name_mut<'a, 'b>(root: &'a mut Tree, name: &'b str) -> Option<&'a mut Node> {
        for child in root.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().unwrap() != name {
                continue
            }
            return Some(child);
        }
        return None
    }
 }

<|endoftext|>


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

use core::prelude::*;
use core::to_bytes;
use core::to_str::ToStr;

#[deriving(Eq)]
pub enum Abi {
    // NB: This ordering MUST match the AbiDatas array below.
    // (This is ensured by the test indices_are_correct().)

    // Single platform ABIs come first (`for_arch()` relies on this)
    Cdecl,
    Stdcall,
    Fastcall,
    Aapcs,

    // Multiplatform ABIs second
    Rust,
    C,
    RustIntrinsic,
}

#[deriving(Eq)]
pub enum Architecture {
    // NB. You cannot change the ordering of these
    // constants without adjusting IntelBits below.
    // (This is ensured by the test indices_are_correct().)
    X86,
    X86_64,
    Arm,
    Mips
}

// FIXME(#5423) After a snapshot, we can change these constants:
// const IntelBits: u32 = (1 << (X86 as uint)) | (1 << X86_64 as uint));
// const ArmBits: u32 = (1 << (Arm as uint));
static IntelBits: u32 = 1 | 2;
static ArmBits: u32 = 4;

struct AbiData {
    abi: Abi,

    // Name of this ABI as we like it called.
    name: &'static str,

    // Is it specific to a platform? If so, which one?  Also, what is
    // the name that LLVM gives it (in case we disagree)
    abi_arch: AbiArchitecture
}

enum AbiArchitecture {
    RustArch,   // Not a real ABI (e.g., intrinsic)
    AllArch,    // An ABI that specifies cross-platform defaults (e.g., "C")
    Archs(u32)  // Multiple architectures (bitset)
}

#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
pub struct AbiSet {
    priv bits: u32   // each bit represents one of the abis below
}

static AbiDatas: &'static [AbiData] = &[
    // Platform-specific ABIs
    AbiData {abi: Cdecl, name: "cdecl", abi_arch: Archs(IntelBits)},
    AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
    AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
    AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},

    // Cross-platform ABIs
    //
    // NB: Do not adjust this ordering without
    // adjusting the indices below.
    AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
    AbiData {abi: C, name: "C", abi_arch: AllArch},
    AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
];

fn each_abi(op: &fn(abi: Abi) -> bool) {
    /*!
     *
     * Iterates through each of the defined ABIs.
     */

    for AbiDatas.each |abi_data| {
        if !op(abi_data.abi) {
            return;
        }
    }
}

pub fn lookup(name: &str) -> Option<Abi> {
    /*!
     *
     * Returns the ABI with the given name (if any).
     */

    for each_abi |abi| {
        if name == abi.data().name {
            return Some(abi);
        }
    }
    return None;
}

pub fn all_names() -> ~[&'static str] {
    AbiDatas.map(|d| d.name)
}

pub impl Abi {
    #[inline]
    fn index(&self) -> uint {
        *self as uint
    }

    #[inline]
    fn data(&self) -> &'static AbiData {
        &AbiDatas[self.index()]
    }

    fn name(&self) -> &'static str {
        self.data().name
    }
}

impl Architecture {
    fn bit(&self) -> u32 {
        1 << (*self as u32)
    }
}

pub impl AbiSet {
    fn from(abi: Abi) -> AbiSet {
        AbiSet { bits: (1 << abi.index()) }
    }

    #[inline]
    fn Rust() -> AbiSet {
        AbiSet::from(Rust)
    }

    #[inline]
    fn C() -> AbiSet {
        AbiSet::from(C)
    }

    #[inline]
    fn Intrinsic() -> AbiSet {
        AbiSet::from(RustIntrinsic)
    }

    fn default() -> AbiSet {
        AbiSet::C()
    }

    fn empty() -> AbiSet {
        AbiSet { bits: 0 }
    }

    #[inline]
    fn is_rust(&self) -> bool {
        self.bits == 1 << Rust.index()
    }

    #[inline]
    fn is_c(&self) -> bool {
        self.bits == 1 << C.index()
    }

    #[inline]
    fn is_intrinsic(&self) -> bool {
        self.bits == 1 << RustIntrinsic.index()
    }

    fn contains(&self, abi: Abi) -> bool {
        (self.bits & (1 << abi.index())) != 0
    }

    fn subset_of(&self, other_abi_set: AbiSet) -> bool {
        (self.bits & other_abi_set.bits) == self.bits
    }

    fn add(&mut self, abi: Abi) {
        self.bits |= (1 << abi.index());
    }

    fn each(&self, op: &fn(abi: Abi) -> bool) {
        for each_abi |abi| {
            if self.contains(abi) {
                if !op(abi) {
                    return;
                }
            }
        }
    }

    fn is_empty(&self) -> bool {
        self.bits == 0
    }

    fn for_arch(&self, arch: Architecture) -> Option<Abi> {
        // NB---Single platform ABIs come first
        for self.each |abi| {
            let data = abi.data();
            match data.abi_arch {
                Archs(a) if (a & arch.bit()) != 0 => { return Some(abi); }
                Archs(_) => { }
                RustArch | AllArch => { return Some(abi); }
            }
        }

        None
    }

    fn check_valid(&self) -> Option<(Abi, Abi)> {
        let mut abis = ~[];
        for self.each |abi| { abis.push(abi); }

        for abis.eachi |i, abi| {
            let data = abi.data();
            for abis.slice(0, i).each |other_abi| {
                let other_data = other_abi.data();
                debug!("abis=(%?,%?) datas=(%?,%?)",
                       abi, data.abi_arch,
                       other_abi, other_data.abi_arch);
                match (&data.abi_arch, &other_data.abi_arch) {
                    (&AllArch, &AllArch) => {
                        // Two cross-architecture ABIs
                        return Some((*abi, *other_abi));
                    }
                    (_, &RustArch) |
                    (&RustArch, _) => {
                        // Cannot combine Rust or Rust-Intrinsic with
                        // anything else.
                        return Some((*abi, *other_abi));
                    }
                    (&Archs(is), &Archs(js)) if (is & js) != 0 => {
                        // Two ABIs for same architecture
                        return Some((*abi, *other_abi));
                    }
                    _ => {}
                }
            }
        }

        return None;
    }
}

impl to_bytes::IterBytes for Abi {
    fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        self.index().iter_bytes(lsb0, f)
    }
}

impl to_bytes::IterBytes for AbiSet {
    fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        self.bits.iter_bytes(lsb0, f)
    }
}

impl ToStr for Abi {
    fn to_str(&self) -> ~str {
        self.data().name.to_str()
    }
}

impl ToStr for AbiSet {
    fn to_str(&self) -> ~str {
        unsafe { // so we can push to strs.
            let mut strs = ~[];
            for self.each |abi| {
                strs.push(abi.data().name);
            }
            fmt!("\"%s\"", str::connect_slices(strs, " "))
        }
    }
}

#[test]
fn lookup_Rust() {
    let abi = lookup("Rust");
    assert!(abi.is_some() && abi.get().data().name == "Rust");
}

#[test]
fn lookup_cdecl() {
    let abi = lookup("cdecl");
    assert!(abi.is_some() && abi.get().data().name == "cdecl");
}

#[test]
fn lookup_baz() {
    let abi = lookup("baz");
    assert!(abi.is_none());
}

#[cfg(test)]
fn cannot_combine(n: Abi, m: Abi) {
    let mut set = AbiSet::empty();
    set.add(n);
    set.add(m);
    match set.check_valid() {
        Some((a, b)) => {
            assert!((n == a && m == b) ||
                         (m == a && n == b));
        }
        None => {
            fail!(~"Invalid match not detected");
        }
    }
}

#[cfg(test)]
fn can_combine(n: Abi, m: Abi) {
    let mut set = AbiSet::empty();
    set.add(n);
    set.add(m);
    match set.check_valid() {
        Some((_, _)) => {
            fail!(~"Valid match declared invalid");
        }
        None => {}
    }
}

#[test]
fn cannot_combine_cdecl_and_stdcall() {
    cannot_combine(Cdecl, Stdcall);
}

#[test]
fn cannot_combine_c_and_rust() {
    cannot_combine(C, Rust);
}

#[test]
fn cannot_combine_rust_and_cdecl() {
    cannot_combine(Rust, Cdecl);
}

#[test]
fn cannot_combine_rust_intrinsic_and_cdecl() {
    cannot_combine(RustIntrinsic, Cdecl);
}

#[test]
fn can_combine_c_and_stdcall() {
    can_combine(C, Stdcall);
}

#[test]
fn can_combine_aapcs_and_stdcall() {
    can_combine(Aapcs, Stdcall);
}

#[test]
fn abi_to_str_stdcall_aaps() {
    let mut set = AbiSet::empty();
    set.add(Aapcs);
    set.add(Stdcall);
    assert!(set.to_str() == ~"\"stdcall aapcs\"");
}

#[test]
fn abi_to_str_c_aaps() {
    let mut set = AbiSet::empty();
    set.add(Aapcs);
    set.add(C);
    debug!("set = %s", set.to_str());
    assert!(set.to_str() == ~"\"aapcs C\"");
}

#[test]
fn abi_to_str_rust() {
    let mut set = AbiSet::empty();
    set.add(Rust);
    debug!("set = %s", set.to_str());
    assert!(set.to_str() == ~"\"Rust\"");
}

#[test]
fn indices_are_correct() {
    for AbiDatas.eachi |i, abi_data| {
        assert!(i == abi_data.abi.index());
    }

    let bits = 1 << (X86 as u32);
    let bits = bits | 1 << (X86_64 as u32);
    assert!(IntelBits == bits);

    let bits = 1 << (Arm as u32);
    assert!(ArmBits == bits);
}

#[cfg(test)]
fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) {
    let mut set = AbiSet::empty();
    for abis.each |&abi| {
        set.add(abi);
    }
    let r = set.for_arch(arch);
    assert!(r == expect);
}

#[test]
fn pick_multiplatform() {
    check_arch([C, Cdecl], X86, Some(Cdecl));
    check_arch([C, Cdecl], X86_64, Some(Cdecl));
    check_arch([C, Cdecl], Arm, Some(C));
}

#[test]
fn pick_uniplatform() {
    check_arch([Stdcall], X86, Some(Stdcall));
    check_arch([Stdcall], Arm, None);
}
<commit_msg>auto merge of #5637 : luqmana/rust/5423, r=brson<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;
use core::to_bytes;
use core::to_str::ToStr;

#[deriving(Eq)]
pub enum Abi {
    // NB: This ordering MUST match the AbiDatas array below.
    // (This is ensured by the test indices_are_correct().)

    // Single platform ABIs come first (`for_arch()` relies on this)
    Cdecl,
    Stdcall,
    Fastcall,
    Aapcs,

    // Multiplatform ABIs second
    Rust,
    C,
    RustIntrinsic,
}

#[deriving(Eq)]
pub enum Architecture {
    // NB. You cannot change the ordering of these
    // constants without adjusting IntelBits below.
    // (This is ensured by the test indices_are_correct().)
    X86,
    X86_64,
    Arm,
    Mips
}

static IntelBits: u32 = (1 << (X86 as uint)) | (1 << (X86_64 as uint));
static ArmBits: u32 = (1 << (Arm as uint));

struct AbiData {
    abi: Abi,

    // Name of this ABI as we like it called.
    name: &'static str,

    // Is it specific to a platform? If so, which one?  Also, what is
    // the name that LLVM gives it (in case we disagree)
    abi_arch: AbiArchitecture
}

enum AbiArchitecture {
    RustArch,   // Not a real ABI (e.g., intrinsic)
    AllArch,    // An ABI that specifies cross-platform defaults (e.g., "C")
    Archs(u32)  // Multiple architectures (bitset)
}

#[auto_encode]
#[auto_decode]
#[deriving(Eq)]
pub struct AbiSet {
    priv bits: u32   // each bit represents one of the abis below
}

static AbiDatas: &'static [AbiData] = &[
    // Platform-specific ABIs
    AbiData {abi: Cdecl, name: "cdecl", abi_arch: Archs(IntelBits)},
    AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)},
    AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)},
    AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)},

    // Cross-platform ABIs
    //
    // NB: Do not adjust this ordering without
    // adjusting the indices below.
    AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
    AbiData {abi: C, name: "C", abi_arch: AllArch},
    AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
];

fn each_abi(op: &fn(abi: Abi) -> bool) {
    /*!
     *
     * Iterates through each of the defined ABIs.
     */

    for AbiDatas.each |abi_data| {
        if !op(abi_data.abi) {
            return;
        }
    }
}

pub fn lookup(name: &str) -> Option<Abi> {
    /*!
     *
     * Returns the ABI with the given name (if any).
     */

    for each_abi |abi| {
        if name == abi.data().name {
            return Some(abi);
        }
    }
    return None;
}

pub fn all_names() -> ~[&'static str] {
    AbiDatas.map(|d| d.name)
}

pub impl Abi {
    #[inline]
    fn index(&self) -> uint {
        *self as uint
    }

    #[inline]
    fn data(&self) -> &'static AbiData {
        &AbiDatas[self.index()]
    }

    fn name(&self) -> &'static str {
        self.data().name
    }
}

impl Architecture {
    fn bit(&self) -> u32 {
        1 << (*self as u32)
    }
}

pub impl AbiSet {
    fn from(abi: Abi) -> AbiSet {
        AbiSet { bits: (1 << abi.index()) }
    }

    #[inline]
    fn Rust() -> AbiSet {
        AbiSet::from(Rust)
    }

    #[inline]
    fn C() -> AbiSet {
        AbiSet::from(C)
    }

    #[inline]
    fn Intrinsic() -> AbiSet {
        AbiSet::from(RustIntrinsic)
    }

    fn default() -> AbiSet {
        AbiSet::C()
    }

    fn empty() -> AbiSet {
        AbiSet { bits: 0 }
    }

    #[inline]
    fn is_rust(&self) -> bool {
        self.bits == 1 << Rust.index()
    }

    #[inline]
    fn is_c(&self) -> bool {
        self.bits == 1 << C.index()
    }

    #[inline]
    fn is_intrinsic(&self) -> bool {
        self.bits == 1 << RustIntrinsic.index()
    }

    fn contains(&self, abi: Abi) -> bool {
        (self.bits & (1 << abi.index())) != 0
    }

    fn subset_of(&self, other_abi_set: AbiSet) -> bool {
        (self.bits & other_abi_set.bits) == self.bits
    }

    fn add(&mut self, abi: Abi) {
        self.bits |= (1 << abi.index());
    }

    fn each(&self, op: &fn(abi: Abi) -> bool) {
        for each_abi |abi| {
            if self.contains(abi) {
                if !op(abi) {
                    return;
                }
            }
        }
    }

    fn is_empty(&self) -> bool {
        self.bits == 0
    }

    fn for_arch(&self, arch: Architecture) -> Option<Abi> {
        // NB---Single platform ABIs come first
        for self.each |abi| {
            let data = abi.data();
            match data.abi_arch {
                Archs(a) if (a & arch.bit()) != 0 => { return Some(abi); }
                Archs(_) => { }
                RustArch | AllArch => { return Some(abi); }
            }
        }

        None
    }

    fn check_valid(&self) -> Option<(Abi, Abi)> {
        let mut abis = ~[];
        for self.each |abi| { abis.push(abi); }

        for abis.eachi |i, abi| {
            let data = abi.data();
            for abis.slice(0, i).each |other_abi| {
                let other_data = other_abi.data();
                debug!("abis=(%?,%?) datas=(%?,%?)",
                       abi, data.abi_arch,
                       other_abi, other_data.abi_arch);
                match (&data.abi_arch, &other_data.abi_arch) {
                    (&AllArch, &AllArch) => {
                        // Two cross-architecture ABIs
                        return Some((*abi, *other_abi));
                    }
                    (_, &RustArch) |
                    (&RustArch, _) => {
                        // Cannot combine Rust or Rust-Intrinsic with
                        // anything else.
                        return Some((*abi, *other_abi));
                    }
                    (&Archs(is), &Archs(js)) if (is & js) != 0 => {
                        // Two ABIs for same architecture
                        return Some((*abi, *other_abi));
                    }
                    _ => {}
                }
            }
        }

        return None;
    }
}

impl to_bytes::IterBytes for Abi {
    fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        self.index().iter_bytes(lsb0, f)
    }
}

impl to_bytes::IterBytes for AbiSet {
    fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
        self.bits.iter_bytes(lsb0, f)
    }
}

impl ToStr for Abi {
    fn to_str(&self) -> ~str {
        self.data().name.to_str()
    }
}

impl ToStr for AbiSet {
    fn to_str(&self) -> ~str {
        unsafe { // so we can push to strs.
            let mut strs = ~[];
            for self.each |abi| {
                strs.push(abi.data().name);
            }
            fmt!("\"%s\"", str::connect_slices(strs, " "))
        }
    }
}

#[test]
fn lookup_Rust() {
    let abi = lookup("Rust");
    assert!(abi.is_some() && abi.get().data().name == "Rust");
}

#[test]
fn lookup_cdecl() {
    let abi = lookup("cdecl");
    assert!(abi.is_some() && abi.get().data().name == "cdecl");
}

#[test]
fn lookup_baz() {
    let abi = lookup("baz");
    assert!(abi.is_none());
}

#[cfg(test)]
fn cannot_combine(n: Abi, m: Abi) {
    let mut set = AbiSet::empty();
    set.add(n);
    set.add(m);
    match set.check_valid() {
        Some((a, b)) => {
            assert!((n == a && m == b) ||
                         (m == a && n == b));
        }
        None => {
            fail!(~"Invalid match not detected");
        }
    }
}

#[cfg(test)]
fn can_combine(n: Abi, m: Abi) {
    let mut set = AbiSet::empty();
    set.add(n);
    set.add(m);
    match set.check_valid() {
        Some((_, _)) => {
            fail!(~"Valid match declared invalid");
        }
        None => {}
    }
}

#[test]
fn cannot_combine_cdecl_and_stdcall() {
    cannot_combine(Cdecl, Stdcall);
}

#[test]
fn cannot_combine_c_and_rust() {
    cannot_combine(C, Rust);
}

#[test]
fn cannot_combine_rust_and_cdecl() {
    cannot_combine(Rust, Cdecl);
}

#[test]
fn cannot_combine_rust_intrinsic_and_cdecl() {
    cannot_combine(RustIntrinsic, Cdecl);
}

#[test]
fn can_combine_c_and_stdcall() {
    can_combine(C, Stdcall);
}

#[test]
fn can_combine_aapcs_and_stdcall() {
    can_combine(Aapcs, Stdcall);
}

#[test]
fn abi_to_str_stdcall_aaps() {
    let mut set = AbiSet::empty();
    set.add(Aapcs);
    set.add(Stdcall);
    assert!(set.to_str() == ~"\"stdcall aapcs\"");
}

#[test]
fn abi_to_str_c_aaps() {
    let mut set = AbiSet::empty();
    set.add(Aapcs);
    set.add(C);
    debug!("set = %s", set.to_str());
    assert!(set.to_str() == ~"\"aapcs C\"");
}

#[test]
fn abi_to_str_rust() {
    let mut set = AbiSet::empty();
    set.add(Rust);
    debug!("set = %s", set.to_str());
    assert!(set.to_str() == ~"\"Rust\"");
}

#[test]
fn indices_are_correct() {
    for AbiDatas.eachi |i, abi_data| {
        assert!(i == abi_data.abi.index());
    }

    let bits = 1 << (X86 as u32);
    let bits = bits | 1 << (X86_64 as u32);
    assert!(IntelBits == bits);

    let bits = 1 << (Arm as u32);
    assert!(ArmBits == bits);
}

#[cfg(test)]
fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) {
    let mut set = AbiSet::empty();
    for abis.each |&abi| {
        set.add(abi);
    }
    let r = set.for_arch(arch);
    assert!(r == expect);
}

#[test]
fn pick_multiplatform() {
    check_arch([C, Cdecl], X86, Some(Cdecl));
    check_arch([C, Cdecl], X86_64, Some(Cdecl));
    check_arch([C, Cdecl], Arm, Some(C));
}

#[test]
fn pick_uniplatform() {
    check_arch([Stdcall], X86, Some(Stdcall));
    check_arch([Stdcall], Arm, None);
}
<|endoftext|>