<commit_before>use base64;
use hex::FromHex;
use serde_json as json;
use std::collections::HashMap;
use std::fmt::Debug;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, BufReader};
use std::path::Path;
use std::process::{Command, Output};
use std::str;
use tar::Archive;

use datatype::{EcuCustom, EcuVersion, Error, InstallCode, InstallOutcome, TufImage,
               TufMeta, Url, Util};
use http::{Client, Response};
use pacman::Credentials;

const NEW_PACKAGE: &'static str = "/tmp/sota-package";
const BOOT_BRANCH: &'static str = "/usr/share/sota/branchname";
const REMOTE_PATH: &'static str = "/etc/ostree/remotes.d/sota-remote.conf";

/// Struct for OSTree related functions.
pub struct Ostree;

impl Ostree {
    fn run<S: AsRef<OsStr> + Debug>(args: &[S]) -> Result<Output, Error> {
        debug!("running `ostree` command with args: {:?}", args);
        Command::new("ostree")
            .args(args)
            .env("OSTREE_REPO", "/sysroot/ostree/repo")
            .env("OSTREE_SYSROOT", "/sysroot")
            .env("OSTREE_BOOT_PARTITION", "/boot")
            .output()
            .map_err(|err| Error::OSTree(err.to_string()))
            .and_then(|output| {
                if output.status.success() {
                    Ok(output)
                } else {
                    let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
                    let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
                    Err(Error::OSTree(format!("stdout: {}\nstderr: {}", stdout, stderr)))
                }
            })
    }

    fn hash(commit: &str) -> Result<String, Error> {
        let data = Vec::from_hex(commit)?;
        Ok(base64::encode(&data).replace('/', "_").trim_right_matches('=').into())
    }
}

/// Details of a remote `OSTree` package.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)]
#[allow(non_snake_case)]
pub struct OstreePackage {
    #[serde(default)]
    pub ecu_serial:  String,
    pub refName:     String,
    pub commit:      String,
    pub description: String,
    pub pullUri:     String,
}

impl OstreePackage {
    pub fn new(ecu_serial: String, refname: String, commit: String, desc: String, treehub: &Url) -> Self {
        OstreePackage {
            ecu_serial:  ecu_serial,
            refName:     refname,
            commit:      commit,
            description: desc,
            pullUri:     format!("{}", treehub),
        }
    }

    /// Convert the current `OstreePackage` into an `EcuVersion`.
    pub fn into_version(self, custom: Option<EcuCustom>) -> EcuVersion {
        let mut hashes = HashMap::new();
        hashes.insert("sha256".to_string(), self.commit);

        EcuVersion {
            attacks_detected: "".to_string(),
            custom: custom,
            ecu_serial: self.ecu_serial,
            installed_image: TufImage {
                filepath: self.refName,
                fileinfo: TufMeta {
                    length: 0,
                    hashes: hashes,
                    custom: None
                }
            },
            previous_timeserver_time: "1970-01-01T00:00:00Z".to_string(),
            timeserver_time: "1970-01-01T00:00:00Z".to_string(),
        }
    }

    /// Install this package using the `ostree` command.
    pub fn install(&self, creds: &Credentials) -> Result<InstallOutcome, Error> {
        debug!("installing ostree commit {}", self.commit);
        let from = Self::get_latest(&self.ecu_serial)?;
        if from.commit == self.commit {
            return Ok(InstallOutcome::new(InstallCode::ALREADY_PROCESSED, "".into(), "".into()));
        }
        self.get_delta(creds.client, &self.pullUri, &from.commit)
            .and_then(|dir| Ostree::run(&["static-delta", "apply-offline", &dir]))
            .or_else(|_| self.pull_commit("sota-remote", creds))
            .map(|_| ())?;

        let output = Ostree::run(&["admin", "deploy", "--karg-proc-cmdline", &self.commit])?;
        let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
        let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
        if output.status.success() {
            Util::write_file(NEW_PACKAGE, &json::to_vec(self)?).unwrap_or_else(|err| error!("couldn't save package info: {}", err));
            Ok(InstallOutcome::new(InstallCode::OK, stdout, stderr))
        } else {
            Ok(InstallOutcome::new(InstallCode::INSTALL_FAILED, stdout, stderr))
        }
    }

    /// Get the latest OSTree package (including any new updates pending a reboot).
    pub fn get_latest(serial: &str) -> Result<OstreePackage, Error> {
        if Path::new(NEW_PACKAGE).exists() {
            trace!("getting ostree package from `{}`", NEW_PACKAGE);
            Ok(json::from_reader(BufReader::new(File::open(NEW_PACKAGE)?))?)
        } else if Path::new(BOOT_BRANCH).exists() {
            trace!("getting ostree branch from `{}`", BOOT_BRANCH);
            Ok(Self::get_current(serial, str::from_utf8(&Util::read_file(BOOT_BRANCH)?)?)?)
        } else {
            trace!("unknown ostree branch");
            Ok(Self::get_current(serial, "<unknown>")?)
        }
    }

    /// Get the current OSTree package with `ostree admin status`.
    pub fn get_current(serial: &str, branch: &str) -> Result<OstreePackage, Error> {
        Ostree::run(&["admin", "status"])
            .and_then(|output| OstreeBranch::parse(serial, branch, str::from_utf8(&output.stdout)?))
            .and_then(|branches| {
                branches.into_iter()
                    .filter(|branch| branch.current)
                    .map(|branch| branch.package)
                    .nth(0)
                    .ok_or_else(|| Error::OSTree("current branch unknown".to_string()))
            })
    }

    /// Extract a static delta between two commits (if it exists) and return the path.
    pub fn get_delta(&self, client: &Client, server: &str, current_commit: &str) -> Result<String, Error> {
        debug!("getting a static delta from {}", current_commit);
        let (current, next)  = (Ostree::hash(current_commit)?, Ostree::hash(&self.commit)?);
        let (prefix, suffix) = current.split_at(2);
        let url  = format!("{}/deltas/{}/{}-{}/apply-offline.tar", server, prefix, suffix, next);
        let data = match client.get(url.parse()?, None).recv().expect("get_delta") {
            Response::Success(data) => Ok(data),
            Response::Failed(data)  => Err(data.into()),
            Response::Error(err)    => Err(err)
        }?;

        let tar = format!("/tmp/sota-delta-{}-{}.tar", current_commit, self.commit);
        let mut file = File::create(&tar)?;
        let _ = io::copy(&mut &*data.body, &mut file)?;
        Archive::new(File::open(&tar)?).unpack("/tmp/sota-delta")?;
        Ok(format!("/tmp/sota-delta/{}/{}-{}", prefix, suffix, next))
    }

    /// Pull a commit from a remote repository with `ostree pull`.
    pub fn pull_commit(&self, remote: &str, creds: &Credentials) -> Result<Output, Error> {
        debug!("pulling from ostree remote: {}", remote);
        if ! Path::new(REMOTE_PATH).exists() {
            let _ = self.add_remote(remote, creds)?;
        }

        let mut args = vec!["pull".into(), remote.into()];
        if let Some(token) = creds.token {
            args.push(format!("--http-header='Authorization=Bearer {}'", token));
        }
        args.push(self.commit.clone());
        Ostree::run(&args)
    }

    /// Add a remote repository with `ostree remote add`.
    pub fn add_remote(&self, remote: &str, creds: &Credentials) -> Result<Output, Error> {
        debug!("adding ostree remote: {}", remote);
        if Path::new(REMOTE_PATH).exists() {
            fs::remove_file(REMOTE_PATH)?;
        }

        let mut args = vec!["remote".into(), "add".into(), "--no-gpg-verify".into()];
        if let Some(ca) = creds.ca_file {
            args.push(format!("--set=tls-ca-path={}", ca));
        }
        if let Some(pkey) = creds.pkey_file {
            args.push(format!("--set=tls-client-cert-path={}", pkey));
            args.push(format!("--set=tls-client-key-path={}", pkey));
        }
        args.push(remote.into());
        args.push(self.pullUri.clone());
        Ostree::run(&args)
    }
}

#[derive(Debug)]
struct OstreeBranch {
    current: bool,
    os_name: String,
    package: OstreePackage,
}

impl OstreeBranch {
    /// Parse the output from `ostree admin status`
    fn parse(ecu_serial: &str, branch_name: &str, stdout: &str) -> Result<Vec<OstreeBranch>, Error> {
        stdout.lines()
            .map(str::trim)
            .filter(|line| !line.is_empty())
            .collect::<Vec<_>>()
            .chunks(2)
            .map(|branch| {
                let first  = branch[0].split(' ').collect::<Vec<_>>();
                let second = branch[1].split(' ').collect::<Vec<_>>();

                let (current, os_name, commit_name) = match first.len() {
                    2 => (false, first[0], first[1]),
                    3 if first[0].trim() == "*" => (true, first[1], first[2]),
                    _ => return Err(Error::Parse(format!("couldn't parse branch: {:?}", first)))
                };
                let commit = commit_name.split('.').collect::<Vec<_>>()[0];
                let desc = match second.len() {
                    3 if second[0].trim() == "origin" && second[1].trim() == "refspec:" => second[2],
                    _ => return Err(Error::Parse(format!("couldn't parse branch: {:?}", second)))
                };

                Ok(OstreeBranch {
                    current: current,
                    os_name: os_name.into(),
                    package: OstreePackage {
                        ecu_serial:  ecu_serial.into(),
                        refName:     format!("{}-{}", branch_name, commit),
                        commit:      commit.into(),
                        description: desc.into(),
                        pullUri:     "".into(),
                    },
                })
            })
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const OSTREE_ADMIN_STATUS: &'static str = r#"
          gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0
            origin refspec: gnome-ostree/buildmaster/x86_64-runtime
        * gnome-ostree ce19c41036cc45e49b0cecf6b157523c2105c4de1c.0
            origin refspec: osname:gnome-ostree/buildmaster/x86_64-runtime
        "#;

    #[test]
    fn test_parse_branches() {
        let branches = OstreeBranch::parse("test-serial".into(), "<branch>", OSTREE_ADMIN_STATUS).expect("couldn't parse branches");
        assert_eq!(branches.len(), 2);
        assert_eq!(branches[0].current, false);
        assert_eq!(branches[0].os_name, "gnome-ostree");
        assert_eq!(branches[0].package.commit, "67e382b11d213a402a5313e61cbc69dfd5ab93cb07");
        assert_eq!(branches[0].package.refName, "<branch>-67e382b11d213a402a5313e61cbc69dfd5ab93cb07");
        assert_eq!(branches[0].package.description, "gnome-ostree/buildmaster/x86_64-runtime");
        assert_eq!(branches[1].current, true);
        assert_eq!(branches[1].package.refName, "<branch>-ce19c41036cc45e49b0cecf6b157523c2105c4de1c");
    }
}
<commit_msg>Remove OSTREE_SYSROOT=/sysroot env var.<commit_after>use base64;
use hex::FromHex;
use serde_json as json;
use std::collections::HashMap;
use std::fmt::Debug;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, BufReader};
use std::path::Path;
use std::process::{Command, Output};
use std::str;
use tar::Archive;

use datatype::{EcuCustom, EcuVersion, Error, InstallCode, InstallOutcome, TufImage,
               TufMeta, Url, Util};
use http::{Client, Response};
use pacman::Credentials;

const NEW_PACKAGE: &'static str = "/tmp/sota-package";
const BOOT_BRANCH: &'static str = "/usr/share/sota/branchname";
const REMOTE_PATH: &'static str = "/etc/ostree/remotes.d/sota-remote.conf";

/// Struct for OSTree related functions.
pub struct Ostree;

impl Ostree {
    fn run<S: AsRef<OsStr> + Debug>(args: &[S]) -> Result<Output, Error> {
        debug!("running `ostree` command with args: {:?}", args);
        Command::new("ostree")
            .args(args)
            .env("OSTREE_REPO", "/sysroot/ostree/repo")
            .env("OSTREE_BOOT_PARTITION", "/boot")
            .output()
            .map_err(|err| Error::OSTree(err.to_string()))
            .and_then(|output| {
                if output.status.success() {
                    Ok(output)
                } else {
                    let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
                    let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
                    Err(Error::OSTree(format!("stdout: {}\nstderr: {}", stdout, stderr)))
                }
            })
    }

    fn hash(commit: &str) -> Result<String, Error> {
        let data = Vec::from_hex(commit)?;
        Ok(base64::encode(&data).replace('/', "_").trim_right_matches('=').into())
    }
}

/// Details of a remote `OSTree` package.
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Default)]
#[allow(non_snake_case)]
pub struct OstreePackage {
    #[serde(default)]
    pub ecu_serial:  String,
    pub refName:     String,
    pub commit:      String,
    pub description: String,
    pub pullUri:     String,
}

impl OstreePackage {
    pub fn new(ecu_serial: String, refname: String, commit: String, desc: String, treehub: &Url) -> Self {
        OstreePackage {
            ecu_serial:  ecu_serial,
            refName:     refname,
            commit:      commit,
            description: desc,
            pullUri:     format!("{}", treehub),
        }
    }

    /// Convert the current `OstreePackage` into an `EcuVersion`.
    pub fn into_version(self, custom: Option<EcuCustom>) -> EcuVersion {
        let mut hashes = HashMap::new();
        hashes.insert("sha256".to_string(), self.commit);

        EcuVersion {
            attacks_detected: "".to_string(),
            custom: custom,
            ecu_serial: self.ecu_serial,
            installed_image: TufImage {
                filepath: self.refName,
                fileinfo: TufMeta {
                    length: 0,
                    hashes: hashes,
                    custom: None
                }
            },
            previous_timeserver_time: "1970-01-01T00:00:00Z".to_string(),
            timeserver_time: "1970-01-01T00:00:00Z".to_string(),
        }
    }

    /// Install this package using the `ostree` command.
    pub fn install(&self, creds: &Credentials) -> Result<InstallOutcome, Error> {
        debug!("installing ostree commit {}", self.commit);
        let from = Self::get_latest(&self.ecu_serial)?;
        if from.commit == self.commit {
            return Ok(InstallOutcome::new(InstallCode::ALREADY_PROCESSED, "".into(), "".into()));
        }
        self.get_delta(creds.client, &self.pullUri, &from.commit)
            .and_then(|dir| Ostree::run(&["static-delta", "apply-offline", &dir]))
            .or_else(|_| self.pull_commit("sota-remote", creds))
            .map(|_| ())?;

        let output = Ostree::run(&["admin", "deploy", "--karg-proc-cmdline", &self.commit])?;
        let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
        let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
        if output.status.success() {
            Util::write_file(NEW_PACKAGE, &json::to_vec(self)?).unwrap_or_else(|err| error!("couldn't save package info: {}", err));
            Ok(InstallOutcome::new(InstallCode::OK, stdout, stderr))
        } else {
            Ok(InstallOutcome::new(InstallCode::INSTALL_FAILED, stdout, stderr))
        }
    }

    /// Get the latest OSTree package (including any new updates pending a reboot).
    pub fn get_latest(serial: &str) -> Result<OstreePackage, Error> {
        if Path::new(NEW_PACKAGE).exists() {
            trace!("getting ostree package from `{}`", NEW_PACKAGE);
            Ok(json::from_reader(BufReader::new(File::open(NEW_PACKAGE)?))?)
        } else if Path::new(BOOT_BRANCH).exists() {
            trace!("getting ostree branch from `{}`", BOOT_BRANCH);
            Ok(Self::get_current(serial, str::from_utf8(&Util::read_file(BOOT_BRANCH)?)?)?)
        } else {
            trace!("unknown ostree branch");
            Ok(Self::get_current(serial, "<unknown>")?)
        }
    }

    /// Get the current OSTree package with `ostree admin status`.
    pub fn get_current(serial: &str, branch: &str) -> Result<OstreePackage, Error> {
        Ostree::run(&["admin", "status"])
            .and_then(|output| OstreeBranch::parse(serial, branch, str::from_utf8(&output.stdout)?))
            .and_then(|branches| {
                branches.into_iter()
                    .filter(|branch| branch.current)
                    .map(|branch| branch.package)
                    .nth(0)
                    .ok_or_else(|| Error::OSTree("current branch unknown".to_string()))
            })
    }

    /// Extract a static delta between two commits (if it exists) and return the path.
    pub fn get_delta(&self, client: &Client, server: &str, current_commit: &str) -> Result<String, Error> {
        debug!("getting a static delta from {}", current_commit);
        let (current, next)  = (Ostree::hash(current_commit)?, Ostree::hash(&self.commit)?);
        let (prefix, suffix) = current.split_at(2);
        let url  = format!("{}/deltas/{}/{}-{}/apply-offline.tar", server, prefix, suffix, next);
        let data = match client.get(url.parse()?, None).recv().expect("get_delta") {
            Response::Success(data) => Ok(data),
            Response::Failed(data)  => Err(data.into()),
            Response::Error(err)    => Err(err)
        }?;

        let tar = format!("/tmp/sota-delta-{}-{}.tar", current_commit, self.commit);
        let mut file = File::create(&tar)?;
        let _ = io::copy(&mut &*data.body, &mut file)?;
        Archive::new(File::open(&tar)?).unpack("/tmp/sota-delta")?;
        Ok(format!("/tmp/sota-delta/{}/{}-{}", prefix, suffix, next))
    }

    /// Pull a commit from a remote repository with `ostree pull`.
    pub fn pull_commit(&self, remote: &str, creds: &Credentials) -> Result<Output, Error> {
        debug!("pulling from ostree remote: {}", remote);
        if ! Path::new(REMOTE_PATH).exists() {
            let _ = self.add_remote(remote, creds)?;
        }

        let mut args = vec!["pull".into(), remote.into()];
        if let Some(token) = creds.token {
            args.push(format!("--http-header='Authorization=Bearer {}'", token));
        }
        args.push(self.commit.clone());
        Ostree::run(&args)
    }

    /// Add a remote repository with `ostree remote add`.
    pub fn add_remote(&self, remote: &str, creds: &Credentials) -> Result<Output, Error> {
        debug!("adding ostree remote: {}", remote);
        if Path::new(REMOTE_PATH).exists() {
            fs::remove_file(REMOTE_PATH)?;
        }

        let mut args = vec!["remote".into(), "add".into(), "--no-gpg-verify".into()];
        if let Some(ca) = creds.ca_file {
            args.push(format!("--set=tls-ca-path={}", ca));
        }
        if let Some(pkey) = creds.pkey_file {
            args.push(format!("--set=tls-client-cert-path={}", pkey));
            args.push(format!("--set=tls-client-key-path={}", pkey));
        }
        args.push(remote.into());
        args.push(self.pullUri.clone());
        Ostree::run(&args)
    }
}

#[derive(Debug)]
struct OstreeBranch {
    current: bool,
    os_name: String,
    package: OstreePackage,
}

impl OstreeBranch {
    /// Parse the output from `ostree admin status`
    fn parse(ecu_serial: &str, branch_name: &str, stdout: &str) -> Result<Vec<OstreeBranch>, Error> {
        stdout.lines()
            .map(str::trim)
            .filter(|line| !line.is_empty())
            .collect::<Vec<_>>()
            .chunks(2)
            .map(|branch| {
                let first  = branch[0].split(' ').collect::<Vec<_>>();
                let second = branch[1].split(' ').collect::<Vec<_>>();

                let (current, os_name, commit_name) = match first.len() {
                    2 => (false, first[0], first[1]),
                    3 if first[0].trim() == "*" => (true, first[1], first[2]),
                    _ => return Err(Error::Parse(format!("couldn't parse branch: {:?}", first)))
                };
                let commit = commit_name.split('.').collect::<Vec<_>>()[0];
                let desc = match second.len() {
                    3 if second[0].trim() == "origin" && second[1].trim() == "refspec:" => second[2],
                    _ => return Err(Error::Parse(format!("couldn't parse branch: {:?}", second)))
                };

                Ok(OstreeBranch {
                    current: current,
                    os_name: os_name.into(),
                    package: OstreePackage {
                        ecu_serial:  ecu_serial.into(),
                        refName:     format!("{}-{}", branch_name, commit),
                        commit:      commit.into(),
                        description: desc.into(),
                        pullUri:     "".into(),
                    },
                })
            })
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    const OSTREE_ADMIN_STATUS: &'static str = r#"
          gnome-ostree 67e382b11d213a402a5313e61cbc69dfd5ab93cb07.0
            origin refspec: gnome-ostree/buildmaster/x86_64-runtime
        * gnome-ostree ce19c41036cc45e49b0cecf6b157523c2105c4de1c.0
            origin refspec: osname:gnome-ostree/buildmaster/x86_64-runtime
        "#;

    #[test]
    fn test_parse_branches() {
        let branches = OstreeBranch::parse("test-serial".into(), "<branch>", OSTREE_ADMIN_STATUS).expect("couldn't parse branches");
        assert_eq!(branches.len(), 2);
        assert_eq!(branches[0].current, false);
        assert_eq!(branches[0].os_name, "gnome-ostree");
        assert_eq!(branches[0].package.commit, "67e382b11d213a402a5313e61cbc69dfd5ab93cb07");
        assert_eq!(branches[0].package.refName, "<branch>-67e382b11d213a402a5313e61cbc69dfd5ab93cb07");
        assert_eq!(branches[0].package.description, "gnome-ostree/buildmaster/x86_64-runtime");
        assert_eq!(branches[1].current, true);
        assert_eq!(branches[1].package.refName, "<branch>-ce19c41036cc45e49b0cecf6b157523c2105c4de1c");
    }
}
<|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/.

use crate::dbus_api::types::InterfacesRemoved;

pub const STRATIS_BASE_PATH: &str = "/org/storage/stratis3";
pub const STRATIS_BASE_SERVICE: &str = "org.storage.stratis3";

pub const MANAGER_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.Manager.r0";
pub const MANAGER_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.Manager.r1";
pub const MANAGER_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.Manager.r2";
pub const REPORT_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.Report.r0";
pub const REPORT_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.Report.r1";
pub const REPORT_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.Report.r2";

pub const LOCKED_POOLS_PROP: &str = "LockedPools";

pub const POOL_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.pool.r0";
pub const POOL_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.pool.r1";
pub const POOL_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.pool.r2";
pub const POOL_NAME_PROP: &str = "Name";
pub const POOL_UUID_PROP: &str = "Uuid";
pub const POOL_HAS_CACHE_PROP: &str = "HasCache";
pub const POOL_ENCRYPTED_PROP: &str = "Encrypted";
pub const POOL_AVAIL_ACTIONS_PROP: &str = "AvailableActions";
pub const POOL_KEY_DESC_PROP: &str = "KeyDescription";
pub const POOL_TOTAL_SIZE_PROP: &str = "TotalPhysicalSize";
pub const POOL_TOTAL_USED_PROP: &str = "TotalPhysicalUsed";
pub const POOL_CLEVIS_INFO_PROP: &str = "ClevisInfo";
pub const POOL_ALLOC_SIZE_PROP: &str = "AllocatedSize";
pub const POOL_FS_LIMIT_PROP: &str = "FsLimit";
pub const POOL_OVERPROV_PROP: &str = "Overprovisioning";
pub const POOL_NO_ALLOCABLE_SPACE_PROP: &str = "NoAllocSpace";

pub const FILESYSTEM_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.filesystem.r0";
pub const FILESYSTEM_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.filesystem.r1";
pub const FILESYSTEM_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.filesystem.r2";
pub const FILESYSTEM_NAME_PROP: &str = "Name";
pub const FILESYSTEM_UUID_PROP: &str = "Uuid";
pub const FILESYSTEM_USED_PROP: &str = "Used";
pub const FILESYSTEM_DEVNODE_PROP: &str = "Devnode";
pub const FILESYSTEM_POOL_PROP: &str = "Pool";
pub const FILESYSTEM_CREATED_PROP: &str = "Created";
pub const FILESYSTEM_SIZE_PROP: &str = "Size";

pub const BLOCKDEV_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.blockdev.r0";
pub const BLOCKDEV_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.blockdev.r1";
pub const BLOCKDEV_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.blockdev.r2";
pub const BLOCKDEV_DEVNODE_PROP: &str = "Devnode";
pub const BLOCKDEV_HARDWARE_INFO_PROP: &str = "HardwareInfo";
pub const BLOCKDEV_USER_INFO_PROP: &str = "UserInfo";
pub const BLOCKDEV_INIT_TIME_PROP: &str = "InitializationTime";
pub const BLOCKDEV_POOL_PROP: &str = "Pool";
pub const BLOCKDEV_UUID_PROP: &str = "Uuid";
pub const BLOCKDEV_TIER_PROP: &str = "Tier";
pub const BLOCKDEV_PHYSICAL_PATH_PROP: &str = "PhysicalPath";

pub const BLOCKDEV_TOTAL_SIZE_PROP: &str = "TotalPhysicalSize";

/// Get a list of all the standard pool interfaces
pub fn standard_pool_interfaces() -> Vec<String> {
    [POOL_INTERFACE_NAME_3_0, POOL_INTERFACE_NAME_3_1]
        .iter()
        .map(|s| (*s).to_string())
        .collect()
}

/// Get a list of all the standard filesystem interfaces
pub fn standard_filesystem_interfaces() -> Vec<String> {
    [FILESYSTEM_INTERFACE_NAME_3_0, FILESYSTEM_INTERFACE_NAME_3_1]
        .iter()
        .map(|s| (*s).to_string())
        .collect()
}

/// Get a list of all the standard blockdev interfaces
pub fn standard_blockdev_interfaces() -> Vec<String> {
    [BLOCKDEV_INTERFACE_NAME_3_0, BLOCKDEV_INTERFACE_NAME_3_1]
        .iter()
        .map(|s| (*s).to_string())
        .collect()
}

/// Get a list of all interfaces supported by a pool object.
pub fn pool_interface_list() -> InterfacesRemoved {
    standard_pool_interfaces()
}

/// Get a list of all interfaces supported by a filesystem object.
pub fn filesystem_interface_list() -> InterfacesRemoved {
    standard_filesystem_interfaces()
}

/// Get a list of all interfaces supported by a blockdev object.
pub fn blockdev_interface_list() -> InterfacesRemoved {
    standard_blockdev_interfaces()
}
<commit_msg>Add revision 2 interfaces to lists of standard ones<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/.

use crate::dbus_api::types::InterfacesRemoved;

pub const STRATIS_BASE_PATH: &str = "/org/storage/stratis3";
pub const STRATIS_BASE_SERVICE: &str = "org.storage.stratis3";

pub const MANAGER_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.Manager.r0";
pub const MANAGER_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.Manager.r1";
pub const MANAGER_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.Manager.r2";
pub const REPORT_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.Report.r0";
pub const REPORT_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.Report.r1";
pub const REPORT_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.Report.r2";

pub const LOCKED_POOLS_PROP: &str = "LockedPools";

pub const POOL_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.pool.r0";
pub const POOL_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.pool.r1";
pub const POOL_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.pool.r2";
pub const POOL_NAME_PROP: &str = "Name";
pub const POOL_UUID_PROP: &str = "Uuid";
pub const POOL_HAS_CACHE_PROP: &str = "HasCache";
pub const POOL_ENCRYPTED_PROP: &str = "Encrypted";
pub const POOL_AVAIL_ACTIONS_PROP: &str = "AvailableActions";
pub const POOL_KEY_DESC_PROP: &str = "KeyDescription";
pub const POOL_TOTAL_SIZE_PROP: &str = "TotalPhysicalSize";
pub const POOL_TOTAL_USED_PROP: &str = "TotalPhysicalUsed";
pub const POOL_CLEVIS_INFO_PROP: &str = "ClevisInfo";
pub const POOL_ALLOC_SIZE_PROP: &str = "AllocatedSize";
pub const POOL_FS_LIMIT_PROP: &str = "FsLimit";
pub const POOL_OVERPROV_PROP: &str = "Overprovisioning";
pub const POOL_NO_ALLOCABLE_SPACE_PROP: &str = "NoAllocSpace";

pub const FILESYSTEM_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.filesystem.r0";
pub const FILESYSTEM_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.filesystem.r1";
pub const FILESYSTEM_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.filesystem.r2";
pub const FILESYSTEM_NAME_PROP: &str = "Name";
pub const FILESYSTEM_UUID_PROP: &str = "Uuid";
pub const FILESYSTEM_USED_PROP: &str = "Used";
pub const FILESYSTEM_DEVNODE_PROP: &str = "Devnode";
pub const FILESYSTEM_POOL_PROP: &str = "Pool";
pub const FILESYSTEM_CREATED_PROP: &str = "Created";
pub const FILESYSTEM_SIZE_PROP: &str = "Size";

pub const BLOCKDEV_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.blockdev.r0";
pub const BLOCKDEV_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.blockdev.r1";
pub const BLOCKDEV_INTERFACE_NAME_3_2: &str = "org.storage.stratis3.blockdev.r2";
pub const BLOCKDEV_DEVNODE_PROP: &str = "Devnode";
pub const BLOCKDEV_HARDWARE_INFO_PROP: &str = "HardwareInfo";
pub const BLOCKDEV_USER_INFO_PROP: &str = "UserInfo";
pub const BLOCKDEV_INIT_TIME_PROP: &str = "InitializationTime";
pub const BLOCKDEV_POOL_PROP: &str = "Pool";
pub const BLOCKDEV_UUID_PROP: &str = "Uuid";
pub const BLOCKDEV_TIER_PROP: &str = "Tier";
pub const BLOCKDEV_PHYSICAL_PATH_PROP: &str = "PhysicalPath";

pub const BLOCKDEV_TOTAL_SIZE_PROP: &str = "TotalPhysicalSize";

/// Get a list of all the standard pool interfaces
pub fn standard_pool_interfaces() -> Vec<String> {
    [
        POOL_INTERFACE_NAME_3_0,
        POOL_INTERFACE_NAME_3_1,
        POOL_INTERFACE_NAME_3_2,
    ]
    .iter()
    .map(|s| (*s).to_string())
    .collect()
}

/// Get a list of all the standard filesystem interfaces
pub fn standard_filesystem_interfaces() -> Vec<String> {
    [
        FILESYSTEM_INTERFACE_NAME_3_0,
        FILESYSTEM_INTERFACE_NAME_3_1,
        FILESYSTEM_INTERFACE_NAME_3_2,
    ]
    .iter()
    .map(|s| (*s).to_string())
    .collect()
}

/// Get a list of all the standard blockdev interfaces
pub fn standard_blockdev_interfaces() -> Vec<String> {
    [
        BLOCKDEV_INTERFACE_NAME_3_0,
        BLOCKDEV_INTERFACE_NAME_3_1,
        BLOCKDEV_INTERFACE_NAME_3_2,
    ]
    .iter()
    .map(|s| (*s).to_string())
    .collect()
}

/// Get a list of all interfaces supported by a pool object.
pub fn pool_interface_list() -> InterfacesRemoved {
    standard_pool_interfaces()
}

/// Get a list of all interfaces supported by a filesystem object.
pub fn filesystem_interface_list() -> InterfacesRemoved {
    standard_filesystem_interfaces()
}

/// Get a list of all interfaces supported by a blockdev object.
pub fn blockdev_interface_list() -> InterfacesRemoved {
    standard_blockdev_interfaces()
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;
use std::mem;

extern {
  static _ZTVN10__cxxabiv117__class_type_infoE: u64;
}

pub struct IntHolder {
  pub vt: &'static FooVTable,
  pub value: i64,
}

pub struct FooVTable {
  pub type_info: &'static TypeInfo,
  pub value: fn(&IntHolder) -> i64,
  pub pad: u64,
  pub destructor: fn(&IntHolder)->(),
}

pub struct TypeInfo {
  pub vt: &'static u64,
  pub mangled_name: &'static str,
}

static name: &'static str = "9LOLHolder\x00";

pub static FooTV: TypeInfo = TypeInfo {
  vt: &_ZTVN10__cxxabiv117__class_type_infoE,
  mangled_name: &name
};

#[no_mangle]
pub static _ZTV9IntHolder: FooVTable = FooVTable {
  type_info: &FooTV,
  value: IntHolder::_ZN9IntHolder5valueEv,
  pad: 0,
  destructor: IntHolder::_ZN9IntHolderD0Ev
};

fn puts(s: &str) {
  unsafe {
    libc::puts(mem::transmute(s.as_ptr()));
  }
}

impl IntHolder {

  #[no_mangle]
  pub fn _ZN9IntHolderC1El(&mut self, value: i64) {
    puts("rust >> IntHolder::IntHolder(long)");
    unsafe {
      let mut x : u64 = mem::transmute(&_ZTV9IntHolder);
      x += 0x8;
      self.vt = mem::transmute(x);
    }
    self.value = value;
  }

  #[no_mangle]
  pub fn _ZN9IntHolderD0Ev(&self) {
    puts("rust >> IntHolder::~IntHolder()");
    unsafe {
      libc::free( mem::transmute(self) );
    }
  }

  #[no_mangle]
  pub fn _ZN9IntHolder5valueEv(&self) -> i64 {
    puts("rust >> IntHolder::value()");
    self.value
  }

  #[no_mangle]
  pub fn _ZN9IntHolder3addEl(&mut self, other: i64) {
    puts("rust >> IntHolder::add(long)");
    self.value += other;
  }

  #[no_mangle]
  pub fn _ZN9IntHolder3subEl(&mut self, other: i64) {
    puts("rust >> IntHolder::sub(long)");
    self.value -= other;
  }

}

<commit_msg>fix vtable stuff; now much more proper<commit_after>#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

extern crate libc;
use std::mem;

extern {
  static _ZTVN10__cxxabiv117__class_type_infoE: u64;
  fn _ZN9IntHolderdlEPv(ptr: u64) -> ();
  fn _ZdlPv(ptr: u64) -> ();
  fn _ZdlPvm(ptr: u64, size: libc::size_t) -> ();
}

pub struct IntHolder {
  pub vt: &'static FooVTable,
  pub value: i64,
}

pub struct FooVTable {
  pub type_info: &'static TypeInfo,
  pub value: fn(&IntHolder) -> i64,
  pub complete_object_destructor: fn(&IntHolder)->(),
  pub deleting_destructor: fn(&IntHolder)->()

}

pub struct TypeInfo {
  pub vt: &'static u64,
  pub mangled_name: &'static str,
}

#[no_mangle]
pub static _ZTS9IntHolder: &'static str = "9LOLHolder\x00";

#[no_mangle]
pub static _ZTI9IntHolder: TypeInfo = TypeInfo {
  vt: &_ZTVN10__cxxabiv117__class_type_infoE,
  mangled_name: &_ZTS9IntHolder
};

#[no_mangle]
pub static _ZTV9IntHolder: FooVTable = FooVTable {
  type_info: &_ZTI9IntHolder,
  value: IntHolder::_ZN9IntHolder5valueEv,
  complete_object_destructor: IntHolder::_ZN9IntHolderD1Ev,
  deleting_destructor: IntHolder::_ZN9IntHolderD0Ev
};

impl IntHolder {

  #[no_mangle]
  pub fn _ZN9IntHolderC1El(&mut self, value: i64) {
    println!("rust >> IntHolder::IntHolder(long) C1");
    println!("self: {:p}", self as *const IntHolder);
    unsafe {
      let mut x : u64 = mem::transmute(&_ZTV9IntHolder);
      x += 0x8;
      self.vt = mem::transmute(x);
    }
    self.value = value;
  }

  #[no_mangle]
  pub fn _ZN9IntHolderC2ERKS_(&mut self, other: &IntHolder) {
    println!("rust >> IntHolder::IntHolder(IntHolder const&)");
    println!("self: {:p}", self as *const IntHolder);
    println!("other: {:p}", other as *const IntHolder);

    unsafe {
      let mut x : u64 = mem::transmute(&_ZTV9IntHolder);
      x += 0x8;
      self.vt = mem::transmute(x);
    }
    self.value = other.value;
    println!("self.value: {:?}", self.value);
    println!("other.value: {:?}", other.value);
  }

  #[no_mangle]
  pub fn _ZN9IntHolderC2El(&mut self, value: i64) {
    println!("rust >> IntHolder::IntHolder(long) C2");
    println!("self: {:p}", self as *const IntHolder);
    unsafe {
      let mut x : u64 = mem::transmute(&_ZTV9IntHolder);
      x += 0x8;
      self.vt = mem::transmute(x);
    }
    self.value = value;
  }

/* C3 constructor is never generally emitted by GCC/Clang
  #[no_mangle]
  pub fn _ZN9IntHolderC3El(&mut self, value: i64) {
    println!("rust >> IntHolder::IntHolder(long) C3");
  }
*/

  #[no_mangle]
  pub fn _ZN9IntHolderD0Ev(&self) {
    println!("rust >> IntHolder::~IntHolder() D0");
    println!("self: {:p}", self as *const IntHolder);

    IntHolder::_ZN9IntHolderD1Ev(self);
    unsafe {
      //static void operator delete(void*):
      //_ZN9IntHolderdlEPv(mem::transmute(self));

      //non-overridden delete:
      _ZdlPvm(mem::transmute(self),
        mem::size_of::<IntHolder>() as libc::size_t
      );
    }
  }

  #[no_mangle]
  pub fn _ZN9IntHolderD1Ev(&self) {
    println!("rust >> IntHolder::~IntHolder() D1");
    println!("self: {:p}", self as *const IntHolder);
  }

  #[no_mangle]
  pub fn _ZN9IntHolderD2Ev(&self) {
    println!("rust >> IntHolder::~IntHolder() D2");
  }

  #[no_mangle]
  pub fn _ZN9IntHolder5valueEv(&self) -> i64 {
    println!("rust >> IntHolder::value()");
    self.value
  }

  #[no_mangle]
  pub fn _ZN9IntHolder3addEl(&mut self, other: i64) {
    println!("rust >> IntHolder::add(long)");
    self.value += other;
  }

  #[no_mangle]
  pub fn _ZN9IntHolder3subEl(&mut self, other: i64) {
    println!("rust >> IntHolder::sub(long)");
    self.value -= other;
  }

}

<|endoftext|>


<commit_before>use std::env;
use std::io::{Error as IOError, ErrorKind as IOErrorKind, Read};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::result::Result;
use std::sync::Mutex;
use std::error::Error;

#[cfg(feature = "session_time")]
use time::Duration;
use futures::{self, Future};
use hyper::header::ContentType;
use hyper::mime;
use hyper::Error as HyperError;
use hyper_staticfile::Static;
use regex::RegexSet;

use tokio_core::reactor::Handle;

use isymtope_build::input::*;
use isymtope_build::processing::*;
use server::*;

pub type IsymtopeServiceRouter = Router;
pub type ResponseMsgChannel = futures::sync::oneshot::Sender<IsymtopeServerResult<ResponseMsg>>;
pub type RequestMsgChannel = futures::sync::mpsc::UnboundedSender<(Msg, ResponseMsgChannel)>;

#[derive(Debug)]
pub struct TemplateRenderServiceFactory {
    sender: RequestMsgChannel,
    handle: Handle,
    prefix: String,
}

impl TemplateRenderServiceFactory {
    pub fn new(sender: RequestMsgChannel, handle: Handle, prefix: String) -> Self {
        TemplateRenderServiceFactory {
            sender: sender,
            handle: handle,
            prefix: prefix,
        }
    }
}

impl IsymtopeAppServiceFactory for TemplateRenderServiceFactory {
    type Request = Request;
    type Response = Response;
    type Error = HyperError;
    type Instance = TemplateRenderService;

    fn create(&self) -> Self::Instance {
        TemplateRenderService {
            sender: self.sender.clone(),
            handle: self.handle.clone(),
            prefix: self.prefix.clone(),
        }
    }
}

#[derive(Debug)]
pub struct TemplateRenderService {
    sender: RequestMsgChannel,
    handle: Handle,
    prefix: String,
}

impl IsymtopeAppService for TemplateRenderService {
    type Request = Request;
    type Response = Response;
    type Error = HyperError;
    type Future = Box<Future<Item = Response, Error = Self::Error>>;

    fn call(&self, app_name: &str, req: Request) -> Self::Future {
        // let (tx1, rx1) = futures::sync::oneshot::channel::<IsymtopeServerResult<ResponseMsg>>();
        // #[cfg(feature = "session_time")]
        // let new_session =
        //     Msg::NewSession(SESSION_COOKIES_RANDOM_STRING_BYTES, Some(Duration::days(1)));

        // #[cfg(not(feature = "session_time"))]
        // let new_session = Msg::NewSession(SESSION_COOKIES_RANDOM_STRING_BYTES);

        // let (tx2, rx2) = futures::sync::oneshot::channel::<IsymtopeServerResult<ResponseMsg>>();
        // let render = Msg::RenderAppRoute(app_name.to_owned(), req.path().to_owned());

        // self.sender.unbounded_send((new_session, tx1)).unwrap();
        // self.sender.unbounded_send((render, tx2)).unwrap();

        let (tx, rx) = futures::sync::oneshot::channel::<IsymtopeServerResult<ResponseMsg>>();
        let template_path = "/app.ism".to_owned();
        let base_url = format!("http://localhost:3000/app/{}/", app_name);
        let render = Msg::RenderAppRoute(base_url.to_owned(), app_name.to_owned(), template_path, req.path().to_owned());
        self.sender.unbounded_send((render, tx)).unwrap();

        let work = rx
            .map_err(|_| {
                HyperError::Io(IOError::new(
                    IOErrorKind::Other,
                    "Failed making request on ServerContext.",
                ))
            })
            .and_then(move |rendered| {
                eprintln!("Got render complete.");
                eprintln!("Got render result: {:?}", rendered);

                match rendered {
                    Ok(ResponseMsg::RenderComplete(response)) => {
                        let body = response.take();
                        let response = Response::new().with_body(body);
                        future::ok(response)
                    }

                    _ => {
                        let body =
                            format!("Unknown response message from render task: {:?}", rendered);
                        let response = Response::new().with_body(body);
                        future::ok(response)
                    }
                }
            });

        Box::new(work)
    }
}

// impl Service for IsymtopeService {
//     type Request = Request;
//     type Response = Response;
//     type Error = HyperError;
//     type Future = Box<Future<Item = Response, Error = Self::Error>>;

//     fn call(&self, req: Self::Request) -> Self::Future {
//     }
// }
<commit_msg>Support host and port in base_url<commit_after>use std::env;
use std::io::{Error as IOError, ErrorKind as IOErrorKind, Read};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::result::Result;
use std::sync::Mutex;
use std::error::Error;

#[cfg(feature = "session_time")]
use time::Duration;
use futures::{self, Future};
use hyper::header::ContentType;
use hyper::mime;
use hyper::Error as HyperError;
use hyper_staticfile::Static;
use regex::RegexSet;

use tokio_core::reactor::Handle;

use isymtope_build::input::*;
use isymtope_build::processing::*;
use server::*;

pub type IsymtopeServiceRouter = Router;
pub type ResponseMsgChannel = futures::sync::oneshot::Sender<IsymtopeServerResult<ResponseMsg>>;
pub type RequestMsgChannel = futures::sync::mpsc::UnboundedSender<(Msg, ResponseMsgChannel)>;

#[derive(Debug)]
pub struct TemplateRenderServiceFactory {
    sender: RequestMsgChannel,
    handle: Handle,
    prefix: String,
}

impl TemplateRenderServiceFactory {
    pub fn new(sender: RequestMsgChannel, handle: Handle, prefix: String) -> Self {
        TemplateRenderServiceFactory {
            sender: sender,
            handle: handle,
            prefix: prefix,
        }
    }
}

impl IsymtopeAppServiceFactory for TemplateRenderServiceFactory {
    type Request = Request;
    type Response = Response;
    type Error = HyperError;
    type Instance = TemplateRenderService;

    fn create(&self) -> Self::Instance {
        TemplateRenderService {
            sender: self.sender.clone(),
            handle: self.handle.clone(),
            prefix: self.prefix.clone(),
        }
    }
}

#[derive(Debug)]
pub struct TemplateRenderService {
    sender: RequestMsgChannel,
    handle: Handle,
    prefix: String,
}

impl IsymtopeAppService for TemplateRenderService {
    type Request = Request;
    type Response = Response;
    type Error = HyperError;
    type Future = Box<Future<Item = Response, Error = Self::Error>>;

    fn call(&self, app_name: &str, req: Request) -> Self::Future {
        // let (tx1, rx1) = futures::sync::oneshot::channel::<IsymtopeServerResult<ResponseMsg>>();
        // #[cfg(feature = "session_time")]
        // let new_session =
        //     Msg::NewSession(SESSION_COOKIES_RANDOM_STRING_BYTES, Some(Duration::days(1)));

        // #[cfg(not(feature = "session_time"))]
        // let new_session = Msg::NewSession(SESSION_COOKIES_RANDOM_STRING_BYTES);

        // let (tx2, rx2) = futures::sync::oneshot::channel::<IsymtopeServerResult<ResponseMsg>>();
        // let render = Msg::RenderAppRoute(app_name.to_owned(), req.path().to_owned());

        // self.sender.unbounded_send((new_session, tx1)).unwrap();
        // self.sender.unbounded_send((render, tx2)).unwrap();

        let (tx, rx) = futures::sync::oneshot::channel::<IsymtopeServerResult<ResponseMsg>>();
        let template_path = "/app.ism".to_owned();
        let (scheme, authority) = (req.uri().scheme().unwrap(), req.uri().authority().unwrap());
        let base_url = format!("{}://{}/app/{}/", scheme, authority, app_name);
        let render = Msg::RenderAppRoute(base_url.to_owned(), app_name.to_owned(), template_path, req.path().to_owned());
        self.sender.unbounded_send((render, tx)).unwrap();

        let work = rx
            .map_err(|_| {
                HyperError::Io(IOError::new(
                    IOErrorKind::Other,
                    "Failed making request on ServerContext.",
                ))
            })
            .and_then(move |rendered| {
                eprintln!("Got render complete.");
                eprintln!("Got render result: {:?}", rendered);

                match rendered {
                    Ok(ResponseMsg::RenderComplete(response)) => {
                        let body = response.take();
                        let response = Response::new().with_body(body);
                        future::ok(response)
                    }

                    _ => {
                        let body =
                            format!("Unknown response message from render task: {:?}", rendered);
                        let response = Response::new().with_body(body);
                        future::ok(response)
                    }
                }
            });

        Box::new(work)
    }
}

// impl Service for IsymtopeService {
//     type Request = Request;
//     type Response = Response;
//     type Error = HyperError;
//     type Future = Box<Future<Item = Response, Error = Self::Error>>;

//     fn call(&self, req: Self::Request) -> Self::Future {
//     }
// }
<|endoftext|>


<commit_before>
use std::collections::BTreeMap;

use assembler::parser::{Literal, Node, InstructionField};

// MARK: - Constants

const BYTES_PER_INSTRUCTION: usize = 2;
const DIRECTIVE_ORG: &'static str = "org";
const DIRECTIVE_DB : &'static str = "db";

// MARK: - Semantic Analysis

/**
 @return () in the event the arguments are valid for the directive, or a failure reason.
 */
fn validate_directive_semantics<'a>(identifier: &'a str, arguments: &Vec<Literal<'a>>) -> Result<(), String> {
    /*
     The 'org' directive is used to set the current output origin address. The directive requires
     a single numeric literal in the range $000-$FFF.
     */
    if identifier == DIRECTIVE_ORG {
        if arguments.len() != 1 {
            return Err(format!("Incorrect number of parameters ({}) for directive .org, expecting 1", arguments.len()));
        }

        match arguments[0] {
            Literal::Numeric(a) if a <= 4095 => {}
            _ => {
                return Err(format!("Directive .org requires 1 numeric literal in the range $000-$FFF."));
            }
        }

        return Ok(());
    }

    /*
     The 'db' directive is used to emit a series of bytes at the current location.
     A list of 1 or more literals is required, either numeric or string.
     A string literal is emitted without a null-terminator.
     */
    if identifier == DIRECTIVE_DB {
        if arguments.len() == 0 {
            return Err(format!("Incorrect number of parameters ({}) for directive .db, expecting 1 or more.", arguments.len()));
        }

        for argument in arguments {
            if let &Literal::Numeric(value) = argument {
                if value > 0xFF {
                    return Err(format!("All numeric parameters to .db must be 1-byte literals (${:X} > $FF)", value));
                }
            }
        }

        return Ok(());
    }

    Err(format!("Unrecognized directive .{}", identifier))
}

/**
 @return The number of bytes the directive represents within the output stream.
 */
fn size_of_directive<'a>(identifier: &'a str, arguments: &Vec<Literal<'a>>) -> usize {
    // The origin directive is not emitted.
    if identifier == DIRECTIVE_ORG {
        return 0;
    }

    // The number of bytes emitted by .db is the sum of argument lengths.
    if identifier == DIRECTIVE_DB {
        return arguments.iter().fold(0, |acc, argument| {
            match *argument {
                Literal::Numeric(number) if number <= 0xFF => { acc + 1 }
                Literal::String(string) => { acc + string.len() }
                _ => {
                    panic!("Semantic analysis for directive .{} failed.", identifier);
                }
            }
        });
    }

    // The first pass at semantic analysis should have caught an invalid directive.
    panic!("Semantic analysis for directive .{} failed.", identifier);
}

// MARK: - Pass 1: Define Labels

/**
 In a 2-pass assembler, the first pass is used to resolve the address of all labels
 declared in the assembly. This involves walking the ASL, computing the size of instructions
 and directives in the output stream and using that information to establish the label-address map.
 @param syntax_list The un-filtered syntax list.
 @return A tuple of (the filtered syntax list with all labels removed,
     the map of labels to their corresponding addresses) on success or a string describing
     the reason the first pass failed.
 */
fn define_and_filter_labels<'a>(syntax_list: Vec<Node<'a>>) -> Result<(Vec<Node<'a>>, BTreeMap<&'a str, usize>), String> {
    let mut label_address_map = BTreeMap::new();
    let mut current_address = 0x000;

    // Define all labels and process '.org' directives.
    for node in syntax_list.iter() {
        match *node {
            Node::Directive { identifier, ref arguments } => {
                // Validate the directive and that the arguments match the identifier.
                try!(validate_directive_semantics(identifier, arguments));

                // Adjust address by directive size.
                current_address = current_address + size_of_directive(identifier, arguments);

                // The origin directive changes the current address.
                if let (DIRECTIVE_ORG, &Literal::Numeric(address)) = (identifier, &arguments[0]) {
                    current_address = address;
                }
            }

            Node::Label { identifier } => {
                // Map the label to the current address and remove from the ASL.
                if label_address_map.contains_key(&identifier) {
                    return Err(format!("Attempted re-definition of label {}.", identifier));
                }

                label_address_map.insert(identifier, current_address);
            }

            Node::Instruction { mnemonic: _, fields: _ } => {
                // All Chip8 instructions are the same length.
                current_address = current_address + BYTES_PER_INSTRUCTION;
            }
        }
    }

    // Remove any label nodes from the ASL as they have now been resolved.
    let filtered_asl = syntax_list.into_iter().filter(|node| {
        match *node {
            Node::Label { identifier: _ } => false,
            Node::Directive { identifier: _, arguments: _ } => true,
            Node::Instruction { mnemonic: _, fields: _ } => true
        }
    }).collect();

    // Semantic analysis for directives and labels is complete.
    Ok((filtered_asl, label_address_map))
}

/**
 Analyze the ASL for the assembly and convert it into an output byte stream.
 */
pub fn assemble<'a>(syntax_list: Vec<Node<'a>>) -> Result<(), String> {
    let _ = try!(define_and_filter_labels(syntax_list));
    Ok(())
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use super::*;
  use super::{validate_directive_semantics, size_of_directive};

  use assembler::scanner::Scanner;
  use assembler::parser::*;

  #[test]
  fn test_validate_directive_semantics_for_org() {
    let mut params = vec![];
    assert_eq!(validate_directive_semantics("org", &params), Err("Incorrect number of parameters (0) for directive .org, expecting 1".to_string()));
    params = vec![Literal::Numeric(1), Literal::Numeric(3)];
    assert_eq!(validate_directive_semantics("org", &params), Err("Incorrect number of parameters (2) for directive .org, expecting 1".to_string()));
    params = vec![Literal::Numeric(0x1000)];
    assert_eq!(validate_directive_semantics("org", &params), Err("Directive .org requires 1 numeric literal in the range $000-$FFF.".to_string()));
    params = vec![Literal::String("TEST_STRING")];
    assert_eq!(validate_directive_semantics("org", &params), Err("Directive .org requires 1 numeric literal in the range $000-$FFF.".to_string()));
    params = vec![Literal::Numeric(0xFFF)];
    assert_eq!(validate_directive_semantics("org", &params), Ok(()));
    params = vec![Literal::Numeric(0x000)];
    assert_eq!(validate_directive_semantics("org", &params), Ok(()));
  }

  #[test]
  fn test_validate_directive_semantics_for_db() {
    let mut params = vec![];
    assert_eq!(validate_directive_semantics("db", &params), Err("Incorrect number of parameters (0) for directive .db, expecting 1 or more.".to_string()));
    params = vec![Literal::Numeric(0x100)];
    assert_eq!(validate_directive_semantics("db", &params), Err("All numeric parameters to .db must be 1-byte literals ($100 > $FF)".to_string()));
    params = vec![Literal::String("TEST_STRING")];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
    params = vec![Literal::Numeric(0xFF)];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
    params = vec![Literal::Numeric(0x00)];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
    params = vec![Literal::String("TEST_STRING"), Literal::Numeric(0x00)];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
  }

  #[test]
  fn test_validate_directive_semantics_for_invalid_directive() {
    let mut params = vec![];
    assert_eq!(validate_directive_semantics("dw", &params), Err("Unrecognized directive .dw".to_string()));
    params = vec![Literal::Numeric(0x100)];
    assert_eq!(validate_directive_semantics("dw", &params), Err("Unrecognized directive .dw".to_string()));
  }

  #[test]
  fn test_size_of_directive_for_org() {
    assert_eq!(size_of_directive("org", &vec![]), 0);
    assert_eq!(size_of_directive("org", &vec![Literal::Numeric(0x100)]), 0);
    assert_eq!(size_of_directive("org", &vec![Literal::Numeric(0x100), Literal::String("TEST_STRING")]), 0);
  }

  #[test]
  fn test_size_of_directive_for_db() {
    assert_eq!(size_of_directive("db", &vec![]), 0);
    assert_eq!(size_of_directive("db", &vec![Literal::Numeric(0xFF)]), 1);
    assert_eq!(size_of_directive("db", &vec![Literal::String("TEST_STRING")]), 11);
    assert_eq!(size_of_directive("db", &vec![Literal::String("TEST_STRING"), Literal::Numeric(0x00)]), 12);
  }

  #[test]
  #[should_panic]
  fn test_size_of_directive_panics_for_invalid_directive() {
    size_of_directive("dw", &vec![]);
  }

}
<commit_msg>Some tests for base define_and_filter_labels case.<commit_after>
use std::collections::BTreeMap;

use assembler::parser::{Literal, Node, InstructionField};

// MARK: - Constants

const BYTES_PER_INSTRUCTION: usize = 2;
const DIRECTIVE_ORG: &'static str = "org";
const DIRECTIVE_DB : &'static str = "db";

// MARK: - Semantic Analysis

/**
 @return () in the event the arguments are valid for the directive, or a failure reason.
 */
fn validate_directive_semantics<'a>(identifier: &'a str, arguments: &Vec<Literal<'a>>) -> Result<(), String> {
    /*
     The 'org' directive is used to set the current output origin address. The directive requires
     a single numeric literal in the range $000-$FFF.
     */
    if identifier == DIRECTIVE_ORG {
        if arguments.len() != 1 {
            return Err(format!("Incorrect number of parameters ({}) for directive .org, expecting 1", arguments.len()));
        }

        match arguments[0] {
            Literal::Numeric(a) if a <= 4095 => {}
            _ => {
                return Err(format!("Directive .org requires 1 numeric literal in the range $000-$FFF."));
            }
        }

        return Ok(());
    }

    /*
     The 'db' directive is used to emit a series of bytes at the current location.
     A list of 1 or more literals is required, either numeric or string.
     A string literal is emitted without a null-terminator.
     */
    if identifier == DIRECTIVE_DB {
        if arguments.len() == 0 {
            return Err(format!("Incorrect number of parameters ({}) for directive .db, expecting 1 or more.", arguments.len()));
        }

        for argument in arguments {
            if let &Literal::Numeric(value) = argument {
                if value > 0xFF {
                    return Err(format!("All numeric parameters to .db must be 1-byte literals (${:X} > $FF)", value));
                }
            }
        }

        return Ok(());
    }

    Err(format!("Unrecognized directive .{}", identifier))
}

/**
 @return The number of bytes the directive represents within the output stream.
 */
fn size_of_directive<'a>(identifier: &'a str, arguments: &Vec<Literal<'a>>) -> usize {
    // The origin directive is not emitted.
    if identifier == DIRECTIVE_ORG {
        return 0;
    }

    // The number of bytes emitted by .db is the sum of argument lengths.
    if identifier == DIRECTIVE_DB {
        return arguments.iter().fold(0, |acc, argument| {
            match *argument {
                Literal::Numeric(number) if number <= 0xFF => { acc + 1 }
                Literal::String(string) => { acc + string.len() }
                _ => {
                    panic!("Semantic analysis for directive .{} failed.", identifier);
                }
            }
        });
    }

    // The first pass at semantic analysis should have caught an invalid directive.
    panic!("Semantic analysis for directive .{} failed.", identifier);
}

// MARK: - Pass 1: Define Labels

/**
 In a 2-pass assembler, the first pass is used to resolve the address of all labels
 declared in the assembly. This involves walking the ASL, computing the size of instructions
 and directives in the output stream and using that information to establish the label-address map.
 @param syntax_list The un-filtered syntax list.
 @return A tuple of (the filtered syntax list with all labels removed,
     the map of labels to their corresponding addresses) on success or a string describing
     the reason the first pass failed.
 */
fn define_and_filter_labels<'a>(syntax_list: Vec<Node<'a>>) -> Result<(Vec<Node<'a>>, BTreeMap<&'a str, usize>), String> {
    let mut label_address_map = BTreeMap::new();
    let mut current_address = 0x000;

    // Define all labels and process '.org' directives.
    for node in syntax_list.iter() {
        match *node {
            Node::Directive { identifier, ref arguments } => {
                // Validate the directive and that the arguments match the identifier.
                try!(validate_directive_semantics(identifier, arguments));

                // Adjust address by directive size.
                current_address = current_address + size_of_directive(identifier, arguments);

                // The origin directive changes the current address.
                if let (DIRECTIVE_ORG, &Literal::Numeric(address)) = (identifier, &arguments[0]) {
                    current_address = address;
                }
            }

            Node::Label { identifier } => {
                // Map the label to the current address and remove from the ASL.
                if label_address_map.contains_key(&identifier) {
                    return Err(format!("Attempted re-definition of label {}.", identifier));
                }

                label_address_map.insert(identifier, current_address);
            }

            Node::Instruction { mnemonic: _, fields: _ } => {
                // All Chip8 instructions are the same length.
                current_address = current_address + BYTES_PER_INSTRUCTION;
            }
        }
    }

    // Remove any label nodes from the ASL as they have now been resolved.
    let filtered_asl = syntax_list.into_iter().filter(|node| {
        match *node {
            Node::Label { identifier: _ } => false,
            Node::Directive { identifier: _, arguments: _ } => true,
            Node::Instruction { mnemonic: _, fields: _ } => true
        }
    }).collect();

    // Semantic analysis for directives and labels is complete.
    Ok((filtered_asl, label_address_map))
}

/**
 Analyze the ASL for the assembly and convert it into an output byte stream.
 */
pub fn assemble<'a>(syntax_list: Vec<Node<'a>>) -> Result<(), String> {
    let _ = try!(define_and_filter_labels(syntax_list));
    Ok(())
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use super::*;
  use super::{validate_directive_semantics, size_of_directive};
  use super::define_and_filter_labels;

  use assembler::parser::*;

  #[test]
  fn test_validate_directive_semantics_for_org() {
    let mut params = vec![];
    assert_eq!(validate_directive_semantics("org", &params), Err("Incorrect number of parameters (0) for directive .org, expecting 1".to_string()));
    params = vec![Literal::Numeric(1), Literal::Numeric(3)];
    assert_eq!(validate_directive_semantics("org", &params), Err("Incorrect number of parameters (2) for directive .org, expecting 1".to_string()));
    params = vec![Literal::Numeric(0x1000)];
    assert_eq!(validate_directive_semantics("org", &params), Err("Directive .org requires 1 numeric literal in the range $000-$FFF.".to_string()));
    params = vec![Literal::String("TEST_STRING")];
    assert_eq!(validate_directive_semantics("org", &params), Err("Directive .org requires 1 numeric literal in the range $000-$FFF.".to_string()));
    params = vec![Literal::Numeric(0xFFF)];
    assert_eq!(validate_directive_semantics("org", &params), Ok(()));
    params = vec![Literal::Numeric(0x000)];
    assert_eq!(validate_directive_semantics("org", &params), Ok(()));
  }

  #[test]
  fn test_validate_directive_semantics_for_db() {
    let mut params = vec![];
    assert_eq!(validate_directive_semantics("db", &params), Err("Incorrect number of parameters (0) for directive .db, expecting 1 or more.".to_string()));
    params = vec![Literal::Numeric(0x100)];
    assert_eq!(validate_directive_semantics("db", &params), Err("All numeric parameters to .db must be 1-byte literals ($100 > $FF)".to_string()));
    params = vec![Literal::String("TEST_STRING")];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
    params = vec![Literal::Numeric(0xFF)];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
    params = vec![Literal::Numeric(0x00)];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
    params = vec![Literal::String("TEST_STRING"), Literal::Numeric(0x00)];
    assert_eq!(validate_directive_semantics("db", &params), Ok(()));
  }

  #[test]
  fn test_validate_directive_semantics_for_invalid_directive() {
    let mut params = vec![];
    assert_eq!(validate_directive_semantics("dw", &params), Err("Unrecognized directive .dw".to_string()));
    params = vec![Literal::Numeric(0x100)];
    assert_eq!(validate_directive_semantics("dw", &params), Err("Unrecognized directive .dw".to_string()));
  }

  #[test]
  fn test_size_of_directive_for_org() {
    assert_eq!(size_of_directive("org", &vec![]), 0);
    assert_eq!(size_of_directive("org", &vec![Literal::Numeric(0x100)]), 0);
    assert_eq!(size_of_directive("org", &vec![Literal::Numeric(0x100), Literal::String("TEST_STRING")]), 0);
  }

  #[test]
  fn test_size_of_directive_for_db() {
    assert_eq!(size_of_directive("db", &vec![]), 0);
    assert_eq!(size_of_directive("db", &vec![Literal::Numeric(0xFF)]), 1);
    assert_eq!(size_of_directive("db", &vec![Literal::String("TEST_STRING")]), 11);
    assert_eq!(size_of_directive("db", &vec![Literal::String("TEST_STRING"), Literal::Numeric(0x00)]), 12);
  }

  #[test]
  #[should_panic]
  fn test_size_of_directive_panics_for_invalid_directive() {
    size_of_directive("dw", &vec![]);
  }

  #[test]
  fn test_define_and_filter_labels() {
    let program = vec![
      Node::Directive   { identifier: "org", arguments: vec![Literal::Numeric(0x100)] },
      Node::Label       { identifier: "label1" },
      Node::Directive   { identifier: "db",  arguments: vec![Literal::Numeric(0xFF)]  },
      Node::Label       { identifier: "label2" },
      Node::Instruction {   mnemonic: "trap",   fields: vec![] },
      Node::Label       { identifier: "label3" }
    ];

    let result = define_and_filter_labels(program);

    // Assert that semantic analysis passed.
    if let Err(reason) = result {
      assert!(false, "Unexpected failure in assembler pass 1: {}", reason);
      return;
    }

    // Verify that the
    if let Ok((filtered_asl, label_map)) = result {
      assert_eq!(label_map.len(), 3);
      assert_eq!(label_map.get("label1").unwrap(), &0x100);
      assert_eq!(label_map.get("label2").unwrap(), &0x101);
      assert_eq!(label_map.get("label3").unwrap(), &0x103);
      assert_eq!(filtered_asl.len(), 3);
      assert_eq!(filtered_asl.get(0).unwrap(), &Node::Directive { identifier: "org", arguments: vec![Literal::Numeric(0x100)] });
      assert_eq!(filtered_asl.get(1).unwrap(), &Node::Directive { identifier: "db",  arguments: vec![Literal::Numeric(0xFF)] });
      assert_eq!(filtered_asl.get(2).unwrap(), &Node::Instruction { mnemonic: "trap", fields: vec![] });
    }
  }

}
<|endoftext|>


<commit_before>//! This is the Server module for Xt.

// This file is part of Xt.

// This is the Xt text editor; it edits text.
// Copyright (C) 2016-2018  The Xt Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

/// `Buffer` struct module for Xt.
///
/// Each struct instance holds a Buffer's state, and links with the
/// associated workspace of the buffer.
/// If no workspace is defined, it uses the wildcard workspace.
pub mod buffer;

/// Workspace module for Xt.
/// Holds a collection of `Buffer` structs together with
/// `Vec<Buffers>`.
pub mod workspace;

/// Major and Minor modes for Xt.
/// Defines the basic structure for each modes, with (planned)
/// extensible.
pub mod modes;
<commit_msg>server/mod.rs: add Gapbuffer as an external crate<commit_after>//! This is the Server module for Xt.

// This file is part of Xt.

// This is the Xt text editor; it edits text.
// Copyright (C) 2016-2018  The Xt Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

extern crate gapbuffer;

/// `Buffer` struct module for Xt.
///
/// Each struct instance holds a Buffer's state, and links with the
/// associated workspace of the buffer.
/// If no workspace is defined, it uses the wildcard workspace.
pub mod buffer;

/// Workspace module for Xt.
/// Holds a collection of `Buffer` structs together with
/// `Vec<Buffers>`.
pub mod workspace;

/// Major and Minor modes for Xt.
/// Defines the basic structure for each modes, with (planned)
/// extensible.
pub mod modes;
<|endoftext|>


<commit_before>use scoped_threadpool::Pool;
use std::cmp;

use ctxt::VM;
use gc::root::Slot;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::large::LargeSpace;
use gc::swiper::marking;
use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::swiper::{CardIdx, CARD_REFS};
use gc::{Address, GcReason, Region};
use object::Obj;

pub struct ParallelFullCollector<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    large_space: &'a LargeSpace,
    rootset: &'a [Slot],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    old_top: Address,
    old_limit: Address,
    init_old_top: Vec<Address>,

    reason: GcReason,
    number_workers: usize,

    min_heap_size: usize,
    max_heap_size: usize,

    units: Vec<Unit>,
    regions: Vec<OldRegion>,
}

impl<'a, 'ast> ParallelFullCollector<'a, 'ast> {
    pub fn new(
        vm: &'a VM<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        large_space: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [Slot],
        reason: GcReason,
        number_workers: usize,
        min_heap_size: usize,
        max_heap_size: usize,
    ) -> ParallelFullCollector<'a, 'ast> {
        let old_total = old.total();

        ParallelFullCollector {
            vm: vm,
            heap: heap,
            young: young,
            old: old,
            large_space: large_space,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            old_top: old_total.start,
            old_limit: old_total.end,
            init_old_top: Vec::new(),

            reason: reason,
            number_workers: number_workers,

            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,

            units: Vec::new(),
            regions: Vec::new(),
        }
    }

    pub fn collect(&mut self, pool: &mut Pool) {
        let dev_verbose = self.vm.args.flag_gc_dev_verbose;
        self.init_old_top = {
            let protected = self.old.protected();
            protected.regions.iter().map(|r| r.top()).collect()
        };

        if dev_verbose {
            println!("Full GC: Phase 1 (marking)");
        }

        self.mark_live(pool);

        if dev_verbose {
            println!("Full GC: Phase 2 (compute forward)");
        }

        self.compute_forward(pool);

        if dev_verbose {
            println!("Full GC: Phase 3 (update refs)");
        }

        self.update_references();

        if dev_verbose {
            println!("Full GC: Phase 4 (relocate)");
        }

        self.relocate();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects)");
        }

        self.update_large_objects();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects) finished.");
        }
    }

    fn mark_live(&mut self, pool: &mut Pool) {
        marking::start(
            self.rootset,
            self.heap.clone(),
            self.perm_space.total(),
            pool,
        );
    }

    fn compute_forward(&mut self, pool: &mut Pool) {
        self.compute_units();
        self.compute_live_bytes(pool);
        self.compute_regions();
    }

    fn compute_units(&mut self) {
        let active = self.old.active_size();
        let unit_size = active / (4 * self.number_workers);

        let protected = self.old.protected();

        for old_region in &protected.regions {
            self.units_for_old_region(old_region.active_region(), unit_size);
        }

        let eden = self.young.eden_active();
        self.units.push(Unit::new(eden));

        let from = self.young.from_active();
        self.units.push(Unit::new(from));

        let to = self.young.to_active();
        self.units.push(Unit::new(to));
    }

    fn units_for_old_region(&mut self, region: Region, unit_size: usize) {
        let mut last = region.start;

        while last < region.end {
            let end = self.find_object_start(last, unit_size, region.end);
            let region = Region::new(last, end);
            self.units.push(Unit::new(region));
            last = end;
        }

        assert_eq!(last, region.end);
    }

    fn find_object_start(&mut self, last: Address, unit_size: usize, end: Address) -> Address {
        let ptr = last.offset(unit_size);

        if ptr >= end {
            return end;
        }

        let (card_start, card_end) = self.card_table.card_indices(ptr, end.align_card());
        let card_start = cmp::max(card_start, self.card_table.card_idx(last).to_usize() + 1);

        for card in card_start..card_end {
            let card: CardIdx = card.into();

            let crossing_entry = self.crossing_map.get(card);
            let card_start = self.card_table.to_address(card);

            match crossing_entry {
                CrossingEntry::NoRefs => {}
                CrossingEntry::LeadingRefs(refs) => {
                    if (refs as usize) < CARD_REFS {
                        return card_start.add_ptr(refs as usize);
                    }
                }

                CrossingEntry::FirstObject(offset) => {
                    return card_start.add_ptr(offset as usize);
                }

                CrossingEntry::ArrayStart(offset) => {
                    return card_start.sub_ptr(offset as usize);
                }
            }
        }

        end
    }

    fn compute_live_bytes(&mut self, pool: &mut Pool) {
        pool.scoped(|scoped| {
            for unit in &mut self.units {
                scoped.execute(move || {
                    let mut live = 0;

                    walk_region(unit.region, |obj, _address, size| {
                        if obj.header().is_marked_non_atomic() {
                            live += size;
                        }
                    });

                    unit.live = 0;
                });
            }
        });
    }

    fn compute_regions(&mut self) {
        let live: usize = self.units.iter().map(|u| u.live).sum();
        let number_regions = self.number_workers;

        let region_size = ((live as f64 / number_regions as f64) * 0.90f64) as usize;
        let mut regions = Vec::with_capacity(number_regions);

        let mut start = 0;
        let mut size = 0;

        for (id, unit) in self.units.iter().enumerate() {
            size += unit.live;

            if size > region_size {
                let units = id - start + 1;
                regions.push(OldRegion::new(start, units));

                start = id + 1;
            }
        }

        if start != self.units.len() {
            let units = self.units.len() - start;
            regions.push(OldRegion::new(start, units));
        }

        std::mem::replace(&mut self.regions, regions);
    }

    fn update_references(&mut self) {
        unimplemented!();
    }

    fn relocate(&mut self) {
        unimplemented!();
    }

    fn update_large_objects(&mut self) {
        unimplemented!();
    }
}

fn walk_region<F>(region: Region, mut fct: F)
where
    F: FnMut(&mut Obj, Address, usize),
{
    let mut scan = region.start;

    while scan < region.end {
        let object = scan.to_mut_obj();

        if object.header().vtblptr().is_null() {
            scan = scan.add_ptr(1);
            continue;
        }

        let object_size = object.size();

        fct(object, scan, object_size);

        scan = scan.offset(object_size);
    }
}

struct Unit {
    region: Region,
    live: usize,
}

impl Unit {
    fn new(region: Region) -> Unit {
        Unit {
            region: region,
            live: 0,
        }
    }

    fn size(&self) -> usize {
        self.region.size()
    }
}

struct OldRegion {
    start: usize,
    regions: usize,
}

impl OldRegion {
    fn new(start: usize, regions: usize) -> OldRegion {
        OldRegion {
            start: start,
            regions: regions,
        }
    }
}
<commit_msg>pfull: added compute_actual_forward<commit_after>use scoped_threadpool::Pool;
use std::cmp;

use ctxt::VM;
use gc::root::Slot;
use gc::space::Space;
use gc::swiper::card::CardTable;
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::large::LargeSpace;
use gc::swiper::marking;
use gc::swiper::old::OldGen;
use gc::swiper::young::YoungGen;
use gc::swiper::{CardIdx, CARD_REFS};
use gc::{Address, GcReason, Region};
use object::Obj;

pub struct ParallelFullCollector<'a, 'ast: 'a> {
    vm: &'a VM<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    large_space: &'a LargeSpace,
    rootset: &'a [Slot],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    old_top: Address,
    old_limit: Address,
    init_old_top: Vec<Address>,

    reason: GcReason,
    number_workers: usize,

    min_heap_size: usize,
    max_heap_size: usize,

    units: Vec<Unit>,
    regions: Vec<OldRegion>,
}

impl<'a, 'ast> ParallelFullCollector<'a, 'ast> {
    pub fn new(
        vm: &'a VM<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        large_space: &'a LargeSpace,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [Slot],
        reason: GcReason,
        number_workers: usize,
        min_heap_size: usize,
        max_heap_size: usize,
    ) -> ParallelFullCollector<'a, 'ast> {
        let old_total = old.total();

        ParallelFullCollector {
            vm: vm,
            heap: heap,
            young: young,
            old: old,
            large_space: large_space,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            old_top: old_total.start,
            old_limit: old_total.end,
            init_old_top: Vec::new(),

            reason: reason,
            number_workers: number_workers,

            min_heap_size: min_heap_size,
            max_heap_size: max_heap_size,

            units: Vec::new(),
            regions: Vec::new(),
        }
    }

    pub fn collect(&mut self, pool: &mut Pool) {
        let dev_verbose = self.vm.args.flag_gc_dev_verbose;
        self.init_old_top = {
            let protected = self.old.protected();
            protected.regions.iter().map(|r| r.top()).collect()
        };

        if dev_verbose {
            println!("Full GC: Phase 1 (marking)");
        }

        self.mark_live(pool);

        if dev_verbose {
            println!("Full GC: Phase 2 (compute forward)");
        }

        self.compute_forward(pool);

        if dev_verbose {
            println!("Full GC: Phase 3 (update refs)");
        }

        self.update_references();

        if dev_verbose {
            println!("Full GC: Phase 4 (relocate)");
        }

        self.relocate();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects)");
        }

        self.update_large_objects();

        if dev_verbose {
            println!("Full GC: Phase 5 (large objects) finished.");
        }
    }

    fn mark_live(&mut self, pool: &mut Pool) {
        marking::start(
            self.rootset,
            self.heap.clone(),
            self.perm_space.total(),
            pool,
        );
    }

    fn compute_forward(&mut self, pool: &mut Pool) {
        self.compute_units();
        self.compute_live_bytes(pool);
        self.compute_regions();
        self.compute_actual_forward(pool);
    }

    fn compute_units(&mut self) {
        let active = self.old.active_size();
        let unit_size = active / (4 * self.number_workers);

        let protected = self.old.protected();

        for old_region in &protected.regions {
            self.units_for_old_region(old_region.active_region(), unit_size);
        }

        let eden = self.young.eden_active();
        self.units.push(Unit::new(eden));

        let from = self.young.from_active();
        self.units.push(Unit::new(from));

        let to = self.young.to_active();
        self.units.push(Unit::new(to));
    }

    fn units_for_old_region(&mut self, region: Region, unit_size: usize) {
        let mut last = region.start;

        while last < region.end {
            let end = self.find_object_start(last, unit_size, region.end);
            let region = Region::new(last, end);
            self.units.push(Unit::new(region));
            last = end;
        }

        assert_eq!(last, region.end);
    }

    fn find_object_start(&mut self, last: Address, unit_size: usize, end: Address) -> Address {
        let ptr = last.offset(unit_size);

        if ptr >= end {
            return end;
        }

        let (card_start, card_end) = self.card_table.card_indices(ptr, end.align_card());
        let card_start = cmp::max(card_start, self.card_table.card_idx(last).to_usize() + 1);

        for card in card_start..card_end {
            let card: CardIdx = card.into();

            let crossing_entry = self.crossing_map.get(card);
            let card_start = self.card_table.to_address(card);

            match crossing_entry {
                CrossingEntry::NoRefs => {}
                CrossingEntry::LeadingRefs(refs) => {
                    if (refs as usize) < CARD_REFS {
                        return card_start.add_ptr(refs as usize);
                    }
                }

                CrossingEntry::FirstObject(offset) => {
                    return card_start.add_ptr(offset as usize);
                }

                CrossingEntry::ArrayStart(offset) => {
                    return card_start.sub_ptr(offset as usize);
                }
            }
        }

        end
    }

    fn compute_live_bytes(&mut self, pool: &mut Pool) {
        pool.scoped(|scoped| {
            for unit in &mut self.units {
                scoped.execute(move || {
                    let mut live = 0;

                    walk_region(unit.region, |obj, _address, size| {
                        if obj.header().is_marked_non_atomic() {
                            live += size;
                        }
                    });

                    unit.live = 0;
                });
            }
        });
    }

    fn compute_regions(&mut self) {
        let live: usize = self.units.iter().map(|u| u.live).sum();
        let number_regions = self.number_workers;

        let region_size = ((live as f64 / number_regions as f64) * 0.90f64) as usize;
        let mut regions = Vec::with_capacity(number_regions);

        let mut start = 0;
        let mut size = 0;

        for (id, unit) in self.units.iter().enumerate() {
            size += unit.live;

            if size > region_size {
                let units = id - start + 1;
                regions.push(OldRegion::new(start, units));

                start = id + 1;
            }
        }

        if start != self.units.len() {
            let units = self.units.len() - start;
            regions.push(OldRegion::new(start, units));
        }

        std::mem::replace(&mut self.regions, regions);
    }

    fn compute_actual_forward(&mut self, _pool: &mut Pool) {
        unimplemented!();
    }

    fn update_references(&mut self) {
        unimplemented!();
    }

    fn relocate(&mut self) {
        unimplemented!();
    }

    fn update_large_objects(&mut self) {
        unimplemented!();
    }
}

fn walk_region<F>(region: Region, mut fct: F)
where
    F: FnMut(&mut Obj, Address, usize),
{
    let mut scan = region.start;

    while scan < region.end {
        let object = scan.to_mut_obj();

        if object.header().vtblptr().is_null() {
            scan = scan.add_ptr(1);
            continue;
        }

        let object_size = object.size();

        fct(object, scan, object_size);

        scan = scan.offset(object_size);
    }
}

struct Unit {
    region: Region,
    live: usize,
}

impl Unit {
    fn new(region: Region) -> Unit {
        Unit {
            region: region,
            live: 0,
        }
    }

    fn size(&self) -> usize {
        self.region.size()
    }
}

struct OldRegion {
    start: usize,
    regions: usize,
}

impl OldRegion {
    fn new(start: usize, regions: usize) -> OldRegion {
        OldRegion {
            start: start,
            regions: regions,
        }
    }
}
<|endoftext|>


<commit_before>use serde_json;
use sputnikvm;

use sputnikvm::{read_hex, Gas, M256, Address};
use sputnikvm::vm::{Machine, VectorMachine, Stack, PC};
use sputnikvm::blockchain::Block;
use sputnikvm::transaction::{Transaction, VectorTransaction};

use super::json_schema::{create_machine, test_machine};

use serde_json::{Value, Error};
use std::fs::File;
use std::path::Path;
use std::io::{BufReader, Write, stdout};
use std::str::FromStr;

use rustyline::error::ReadlineError;
use rustyline::Editor;

pub fn test_transaction(name: &str, v: &Value, debug: bool) {
    print!("Testing {} ... ", name);
    if debug {
        print!("\n");
    }
    stdout().flush();

    let mut machine = create_machine(v);
    let result = machine.fire();

    let out = v["out"].as_str();

    if out.is_some() {
        if result.is_ok() && test_machine(v, &machine, debug) {
            println!("OK");
        } else {
            println!("Failed {:?}", result.err());
        }
    } else {
        if result.is_err() {
            println!("OK");
        } else {
            println!("Failed");
        }
    }
}

pub fn debug_transaction(v: &Value) {
    let mut machine = create_machine(v);
    let mut rl = Editor::<()>::new();

    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                match line.as_ref() {
                    "step" => {
                        if machine.pc().stopped() {
                            println!("Stopped");
                        } else {
                            println!("Running {:?} ... {:?}.", machine.pc().peek_opcode(),
                                     machine.step());
                        }
                    },
                    "fire" => {
                        let result = machine.fire();
                        println!("{:?}", result);
                    },
                    "print stack" => {
                        for i in 0..machine.stack().size() {
                            println!("{}: {:x}", i, machine.stack().peek(i).unwrap());
                        }
                    },
                    _ => {
                        println!("Unknown command.");
                    }
                }
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
}
<commit_msg>Problem: no way for long programs to be debugged Solution: add a fire debug command<commit_after>use serde_json;
use sputnikvm;

use sputnikvm::{read_hex, Gas, M256, Address};
use sputnikvm::vm::{Machine, VectorMachine, Stack, PC};
use sputnikvm::blockchain::Block;
use sputnikvm::transaction::{Transaction, VectorTransaction};

use super::json_schema::{create_machine, test_machine};

use serde_json::{Value, Error};
use std::fs::File;
use std::path::Path;
use std::io::{BufReader, Write, stdout};
use std::str::FromStr;

use rustyline::error::ReadlineError;
use rustyline::Editor;

pub fn test_transaction(name: &str, v: &Value, debug: bool) {
    print!("Testing {} ... ", name);
    if debug {
        print!("\n");
    }
    stdout().flush();

    let mut machine = create_machine(v);
    let result = machine.fire();

    let out = v["out"].as_str();

    if out.is_some() {
        if result.is_ok() && test_machine(v, &machine, debug) {
            println!("OK");
        } else {
            println!("Failed {:?}", result.err());
        }
    } else {
        if result.is_err() {
            println!("OK");
        } else {
            println!("Failed");
        }
    }
}

pub fn debug_transaction(v: &Value) {
    let mut machine = create_machine(v);
    let mut rl = Editor::<()>::new();

    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                match line.as_ref() {
                    "step" => {
                        if machine.pc().stopped() {
                            println!("Stopped");
                        } else {
                            println!("Running {:?} ... {:?}.", machine.pc().peek_opcode(),
                                     machine.step());
                        }
                    },
                    "fire" => {
                        let result = machine.fire();
                        println!("{:?}", result);
                    },
                    "fire debug" => {
                        while !machine.pc().stopped() {
                            println!("Running {:?} ... {:?}.", machine.pc().peek_opcode(),
                                     machine.step());
                        }
                    },
                    "print stack" => {
                        for i in 0..machine.stack().size() {
                            println!("{}: {:x}", i, machine.stack().peek(i).unwrap());
                        }
                    },
                    _ => {
                        println!("Unknown command.");
                    }
                }
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Rouille developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use Request;
use RouteError;

use std::io::Cursor;
use std::mem;

use multipart::server::Multipart as InnerMultipart;

// TODO: provide wrappers around these
pub use multipart::server::MultipartField;
pub use multipart::server::MultipartData;
pub use multipart::server::MultipartFile;

/// Error that can happen when decoding multipart data.
#[derive(Clone, Debug)]
pub enum MultipartError {
    /// The `Content-Type` header of the request indicates that it doesn't contain multipart data
    /// or is invalid.
    WrongContentType,
}

impl From<MultipartError> for RouteError {
    #[inline]
    fn from(err: MultipartError) -> RouteError {
        RouteError::WrongInput
    }
}

pub fn get_multipart_input(request: &Request) -> Result<Multipart, MultipartError> {
    let boundary = match multipart_boundary(request) {
        Some(b) => b,
        None => return Err(MultipartError::WrongContentType)
    };

    Ok(Multipart {
        inner: InnerMultipart::with_body(Cursor::new(request.data()), boundary)
    })
}

///
/// # Warning
///
/// If the previously returned entry had contents of type MultipartField::File, calling this again
/// will discard any unread contents of that entry.
pub struct Multipart {
    inner: InnerMultipart<Cursor<Vec<u8>>>
}

impl Multipart {
    pub fn next(&mut self) -> Option<MultipartField<Cursor<Vec<u8>>>> {
        match self.inner.read_entry() {
            Ok(e) => e,
            _ => return None
        }
    }
}

fn multipart_boundary(request: &Request) -> Option<String> {
    const BOUNDARY: &'static str = "boundary=";

    let content_type = match request.header("Content-Type") {
        None => return None,
        Some(c) => c
    };

    let start = match content_type.find(BOUNDARY) {
        Some(pos) => pos + BOUNDARY.len(),
        None => return None
    };

    let end = content_type[start..].find(';').map_or(content_type.len(), |end| start + end);
    Some(content_type[start .. end].to_owned())
}

<commit_msg>Minor documentation<commit_after>// Copyright (c) 2016 The Rouille developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use Request;
use RouteError;

use std::io::Cursor;
use std::mem;

use multipart::server::Multipart as InnerMultipart;

// TODO: provide wrappers around these
pub use multipart::server::MultipartField;
pub use multipart::server::MultipartData;
pub use multipart::server::MultipartFile;

/// Error that can happen when decoding multipart data.
#[derive(Clone, Debug)]
pub enum MultipartError {
    /// The `Content-Type` header of the request indicates that it doesn't contain multipart data
    /// or is invalid.
    WrongContentType,
}

impl From<MultipartError> for RouteError {
    #[inline]
    fn from(err: MultipartError) -> RouteError {
        RouteError::WrongInput
    }
}

/// Attempts to decode the content of the request as `multipart/form-data` data.
pub fn get_multipart_input(request: &Request) -> Result<Multipart, MultipartError> {
    let boundary = match multipart_boundary(request) {
        Some(b) => b,
        None => return Err(MultipartError::WrongContentType)
    };

    Ok(Multipart {
        inner: InnerMultipart::with_body(Cursor::new(request.data()), boundary)
    })
}

/// Allows you to inspect the content of the multipart input of a request.
pub struct Multipart {
    inner: InnerMultipart<Cursor<Vec<u8>>>
}

impl Multipart {
    pub fn next(&mut self) -> Option<MultipartField<Cursor<Vec<u8>>>> {
        match self.inner.read_entry() {
            Ok(e) => e,
            _ => return None
        }
    }
}

fn multipart_boundary(request: &Request) -> Option<String> {
    const BOUNDARY: &'static str = "boundary=";

    let content_type = match request.header("Content-Type") {
        None => return None,
        Some(c) => c
    };

    let start = match content_type.find(BOUNDARY) {
        Some(pos) => pos + BOUNDARY.len(),
        None => return None
    };

    let end = content_type[start..].find(';').map_or(content_type.len(), |end| start + end);
    Some(content_type[start .. end].to_owned())
}

<|endoftext|>