<commit_before>use std::fs::{create_dir_all, File};
use std::io::Write;

use clap::ArgMatches;
use rusoto::ChainProvider;

use aws::credentials_provider;
use encryption::Encryptor;
use error::KawsResult;
use pki::CertificateAuthority;

pub struct Cluster<'a> {
    name: &'a str,
    region: &'a str,
}

pub struct ExistingCluster<'a> {
    aws_credentials_provider: ChainProvider,
    domain: &'a str,
    cluster: Cluster<'a>,
    kms_master_key_id: &'a str,
}

pub struct NewCluster<'a> {
    availability_zone: &'a str,
    aws_account_id: &'a str,
    cluster: Cluster<'a>,
    coreos_ami: &'a str,
    domain: &'a str,
    iam_users: Vec<&'a str>,
    instance_size: &'a str,
    kubernetes_version: &'a str,
    masters_max_size: &'a str,
    masters_min_size: &'a str,
    nodes_max_size: &'a str,
    nodes_min_size: &'a str,
    rbac_super_user: &'a str,
    ssh_keys: Vec<&'a str>,
    zone_id: &'a str,
}

impl<'a> Cluster<'a> {
    pub fn new(name: &'a str, region: &'a str) -> Self {
        Cluster {
            name: name,
            region: region,
        }
    }

    fn etcd_ca_cert_path(&self) -> String {
        format!("clusters/{}/etcd-ca.pem", self.name)
    }

    fn etcd_encrypted_ca_key_path(&self) -> String {
        format!("clusters/{}/etcd-ca-key-encrypted.base64", self.name)
    }

    fn etcd_server_cert_path(&self) -> String {
        format!("clusters/{}/etcd-server.pem", self.name)
    }

    fn etcd_encrypted_server_key_path(&self) -> String {
        format!("clusters/{}/etcd-server-key-encrypted.base64", self.name)
    }

    fn etcd_client_cert_path(&self) -> String {
        format!("clusters/{}/etcd-client.pem", self.name)
    }

    fn etcd_encrypted_client_key_path(&self) -> String {
        format!("clusters/{}/etcd-client-key-encrypted.base64", self.name)
    }

    fn etcd_peer_ca_cert_path(&self) -> String {
        format!("clusters/{}/etcd-peer-ca.pem", self.name)
    }

    fn etcd_peer_encrypted_ca_key_path(&self) -> String {
        format!("clusters/{}/etcd-peer-ca-key-encrypted.base64", self.name)
    }

    fn etcd_peer_cert_path(&self) -> String {
        format!("clusters/{}/etcd-peer.pem", self.name)
    }

    fn etcd_peer_encrypted_key_path(&self) -> String {
        format!("clusters/{}/etcd-peer-key-encrypted.base64", self.name)
    }

    fn k8s_ca_cert_path(&self) -> String {
        format!("clusters/{}/k8s-ca.pem", self.name)
    }

    fn k8s_encrypted_ca_key_path(&self) -> String {
        format!("clusters/{}/k8s-ca-key-encrypted.base64", self.name)
    }

    fn k8s_encrypted_master_key_path(&self) -> String {
        format!("clusters/{}/k8s-master-key-encrypted.base64", self.name)
    }

    fn k8s_encrypted_node_key_path(&self) -> String {
        format!("clusters/{}/k8s-node-key-encrypted.base64", self.name)
    }

    fn gitignore_path(&self) -> String {
        format!("clusters/{}/.gitignore", self.name)
    }

    fn k8s_master_cert_path(&self) -> String {
        format!("clusters/{}/k8s-master.pem", self.name)
    }

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

    fn k8s_node_cert_path(&self) -> String {
        format!("clusters/{}/k8s-node.pem", self.name)
    }

    fn region(&self) -> &str {
        self.region
    }

    fn tfvars_path(&self) -> String {
        format!("clusters/{}/terraform.tfvars", self.name)
    }
}

impl<'a> ExistingCluster<'a> {
    pub fn new(matches: &'a ArgMatches) -> Self {
        ExistingCluster {
            aws_credentials_provider: credentials_provider(
                matches.value_of("aws-credentials-path"),
                matches.value_of("aws-credentials-profile"),
            ),
            cluster: Cluster::new(
                matches.value_of("cluster").expect("missing cluster name"),
                matches.value_of("region").expect("missing region"),
            ),
            domain: matches.value_of("domain").expect("missing domain"),
            kms_master_key_id: matches.value_of("kms-key").expect("missing kms-key"),
        }
    }

    pub fn generate_pki(&mut self) -> KawsResult {
        self.generate_etcd_pki(self.kms_master_key_id)?;
        self.generate_etcd_peer_pki(self.kms_master_key_id)?;
        self.generate_k8s_pki(self.kms_master_key_id)?;

        Ok(None)
    }

    fn generate_etcd_pki(&self, kms_key_id: &str) -> KawsResult {
        let ca = CertificateAuthority::generate(&format!("kaws-etcd-ca-{}", self.cluster.name))?;

        let (server_cert, server_key) = ca.generate_cert(
            &format!("kaws-etcd-server-{}", self.cluster.name),
            Some(&[
                "10.0.1.4",
                "10.0.1.5",
                "10.0.1.6",
            ]),
        )?;

        let (client_cert, client_key) = ca.generate_cert(
            &format!("kaws-etcd-client-{}", self.cluster.name),
            None,
        )?;

        let mut encryptor = Encryptor::new(
            self.aws_credentials_provider.clone(),
            self.cluster.region().parse()?,
            Some(kms_key_id),
        );

        ca.write_to_files(
            &mut encryptor,
            &self.cluster.etcd_ca_cert_path(),
            &self.cluster.etcd_encrypted_ca_key_path(),
        )?;

        server_cert.write_to_file(&self.cluster.etcd_server_cert_path())?;
        server_key.write_to_file(
            &mut encryptor,
            &self.cluster.etcd_encrypted_server_key_path(),
        )?;

        client_cert.write_to_file(&self.cluster.etcd_client_cert_path())?;
        client_key.write_to_file(
            &mut encryptor,
            &self.cluster.etcd_encrypted_client_key_path(),
        )?;

        Ok(None)
    }

    fn generate_etcd_peer_pki(&self, kms_key_id: &str) -> KawsResult {
        let ca = CertificateAuthority::generate(
            &format!("kaws-etcd-peer-ca-{}", self.cluster.name)
        )?;

        let (peer_cert, peer_key) = ca.generate_cert(
            &format!("kaws-etcd-peer-{}", self.cluster.name),
            Some(&[
                "10.0.1.4",
                "10.0.1.5",
                "10.0.1.6",
            ]),
        )?;

        let mut encryptor = Encryptor::new(
            self.aws_credentials_provider.clone(),
            self.cluster.region().parse()?,
            Some(kms_key_id),
        );

        ca.write_to_files(
            &mut encryptor,
            &self.cluster.etcd_peer_ca_cert_path(),
            &self.cluster.etcd_peer_encrypted_ca_key_path(),
        )?;

        peer_cert.write_to_file(&self.cluster.etcd_peer_cert_path())?;
        peer_key.write_to_file(
            &mut encryptor,
            &self.cluster.etcd_peer_encrypted_key_path(),
        )?;

        Ok(None)
    }

    fn generate_k8s_pki(&self, kms_key_id: &str) -> KawsResult {
        let ca = CertificateAuthority::generate(&format!("kaws-k8s-ca-{}", self.cluster.name))?;

        let (master_cert, master_key) = ca.generate_cert(
            &format!("kaws-k8s-master-{}", self.cluster.name),
            Some(&[
                "kubernetes",
                "kubernetes.default",
                "kubernetes.default.svc",
                "kubernetes.default.svc.cluster.local",
                &format!("kubernetes.{}", self.domain),
                "10.3.0.1",
            ]),
        )?;

        let (node_cert, node_key) = ca.generate_cert(
            &format!("kaws-k8s-node-{}", self.cluster.name),
            None,
        )?;

        let mut encryptor = Encryptor::new(
            self.aws_credentials_provider.clone(),
            self.cluster.region().parse()?,
            Some(kms_key_id),
        );

        ca.write_to_files(
            &mut encryptor,
            &self.cluster.k8s_ca_cert_path(),
            &self.cluster.k8s_encrypted_ca_key_path(),
        )?;

        master_cert.write_to_file(&self.cluster.k8s_master_cert_path())?;
        master_key.write_to_file(
            &mut encryptor,
            &self.cluster.k8s_encrypted_master_key_path(),
        )?;

        node_cert.write_to_file(&self.cluster.k8s_node_cert_path())?;
        node_key.write_to_file(
            &mut encryptor,
            &self.cluster.k8s_encrypted_node_key_path(),
        )?;

        Ok(None)
    }
}

impl<'a> NewCluster<'a> {
    pub fn new(matches: &'a ArgMatches) -> Self {
        NewCluster {
            availability_zone: matches
                .value_of("availability-zone")
                .expect("missing availability-zone"),
            aws_account_id: matches.value_of("aws-account-id").expect("missing aws-account-id"),
            cluster: Cluster::new(
                matches.value_of("cluster").expect("missing cluster name"),
                matches.value_of("region").expect("missing region"),
            ),
            coreos_ami: matches.value_of("ami").expect("missing ami"),
            domain: matches.value_of("domain").expect("missing domain"),
            iam_users: matches
                .values_of("iam-user")
                .expect("missing iam-users")
                .collect(),
            instance_size: matches.value_of("size").expect("missing instance size"),
            kubernetes_version: matches.value_of("k8s-version").expect("missing k8s-version"),
            masters_max_size: matches
                .value_of("masters-max-size")
                .expect("missing masters-max-size"),
            masters_min_size: matches
                .value_of("masters-min-size")
                .expect("missing masters-min-size"),
            nodes_max_size: matches
                .value_of("nodes-max-size")
                .expect("missing nodes-max-size"),
            nodes_min_size: matches
                .value_of("nodes-min-size")
                .expect("missing nodes-min-size"),
            rbac_super_user: matches.value_of("rbac-super-user").expect("missing rbac-super-user"),
            ssh_keys: matches.values_of("ssh-key").expect("missing ssh-keys").collect(),
            zone_id: matches.value_of("zone-id").expect("missing zone-id"),
        }
    }

    pub fn init(&mut self) -> KawsResult {
        try!(self.create_directories());
        try!(self.create_gitignore());
        try!(self.create_tfvars());
        try!(self.create_pki_stubs());

        Ok(Some(format!(
            "Cluster \"{name}\" initialized! Commit clusters/{name} to Git.",
            name = self.cluster.name,
        )))
    }

    fn create_directories(&self) -> KawsResult {
        log_wrap!("Creating directories for the new cluster", {
            try!(create_dir_all(format!("clusters/{}", self.cluster.name)));
        });

        Ok(None)
    }

    fn create_gitignore(&self) -> KawsResult {
        log_wrap!("Creating .gitignore file", {
            let mut file = try!(File::create(&self.cluster.gitignore_path()));

            try!(write!(file, "*-key.pem"));
        });

        Ok(None)
    }

    fn create_tfvars(&self) -> KawsResult {
        log_wrap!("Creating tfvars file", {
            let mut file = try!(File::create(&self.cluster.tfvars_path()));

            try!(write!(
                file,
                "\
kaws_account_id = \"{}\"
kaws_availability_zone = \"{}\"
kaws_cluster = \"{}\"
kaws_coreos_ami = \"{}\"
kaws_domain = \"{}\"
kaws_etcd_01_initial_cluster_state = \"new\"
kaws_etcd_02_initial_cluster_state = \"new\"
kaws_etcd_03_initial_cluster_state = \"new\"
kaws_iam_users = [{}]
kaws_instance_size = \"{}\"
kaws_masters_max_size = \"{}\"
kaws_masters_min_size = \"{}\"
kaws_nodes_max_size = \"{}\"
kaws_nodes_min_size = \"{}\"
kaws_propagating_vgws = []
kaws_rbac_super_user = \"{}\"
kaws_region = \"{}\"
kaws_ssh_keys = [{}]
kaws_version = \"{}\"
kaws_zone_id = \"{}\"
",
                self.aws_account_id,
                self.availability_zone,
                self.cluster.name(),
                self.coreos_ami,
                self.domain,
                self.iam_users.iter().map(|iam_user| {
                    format!("\"{}\"", iam_user)
                }).collect::<Vec<String>>().join(", "),
                self.instance_size,
                self.masters_max_size,
                self.masters_min_size,
                self.nodes_max_size,
                self.nodes_min_size,
                self.rbac_super_user,
                self.cluster.region(),
                self.ssh_keys.iter().map(|ssh_key| {
                    format!("\"{}\"", ssh_key)
                }).collect::<Vec<String>>().join(", "),
                self.kubernetes_version,
                self.zone_id,
            ));
        });

        Ok(None)
    }

    fn create_pki_stubs(&self) -> KawsResult {
        let paths = [
            &self.cluster.etcd_ca_cert_path(),
            &self.cluster.etcd_server_cert_path(),
            &self.cluster.etcd_encrypted_server_key_path(),
            &self.cluster.etcd_client_cert_path(),
            &self.cluster.etcd_encrypted_client_key_path(),

            &self.cluster.etcd_peer_ca_cert_path(),
            &self.cluster.etcd_peer_cert_path(),
            &self.cluster.etcd_peer_encrypted_key_path(),

            &self.cluster.k8s_ca_cert_path(),
            &self.cluster.k8s_master_cert_path(),
            &self.cluster.k8s_encrypted_master_key_path(),
            &self.cluster.k8s_node_cert_path(),
            &self.cluster.k8s_encrypted_node_key_path(),
        ];

        for path in paths.iter() {
            try!(File::create(path));
        }

        Ok(None)
    }
}
<commit_msg>Ensure all PKI stub files are generated.<commit_after>use std::fs::{create_dir_all, File};
use std::io::Write;

use clap::ArgMatches;
use rusoto::ChainProvider;

use aws::credentials_provider;
use encryption::Encryptor;
use error::KawsResult;
use pki::CertificateAuthority;

pub struct Cluster<'a> {
    name: &'a str,
    region: &'a str,
}

pub struct ExistingCluster<'a> {
    aws_credentials_provider: ChainProvider,
    domain: &'a str,
    cluster: Cluster<'a>,
    kms_master_key_id: &'a str,
}

pub struct NewCluster<'a> {
    availability_zone: &'a str,
    aws_account_id: &'a str,
    cluster: Cluster<'a>,
    coreos_ami: &'a str,
    domain: &'a str,
    iam_users: Vec<&'a str>,
    instance_size: &'a str,
    kubernetes_version: &'a str,
    masters_max_size: &'a str,
    masters_min_size: &'a str,
    nodes_max_size: &'a str,
    nodes_min_size: &'a str,
    rbac_super_user: &'a str,
    ssh_keys: Vec<&'a str>,
    zone_id: &'a str,
}

impl<'a> Cluster<'a> {
    pub fn new(name: &'a str, region: &'a str) -> Self {
        Cluster {
            name: name,
            region: region,
        }
    }

    fn etcd_ca_cert_path(&self) -> String {
        format!("clusters/{}/etcd-ca.pem", self.name)
    }

    fn etcd_encrypted_ca_key_path(&self) -> String {
        format!("clusters/{}/etcd-ca-key-encrypted.base64", self.name)
    }

    fn etcd_server_cert_path(&self) -> String {
        format!("clusters/{}/etcd-server.pem", self.name)
    }

    fn etcd_encrypted_server_key_path(&self) -> String {
        format!("clusters/{}/etcd-server-key-encrypted.base64", self.name)
    }

    fn etcd_client_cert_path(&self) -> String {
        format!("clusters/{}/etcd-client.pem", self.name)
    }

    fn etcd_encrypted_client_key_path(&self) -> String {
        format!("clusters/{}/etcd-client-key-encrypted.base64", self.name)
    }

    fn etcd_peer_ca_cert_path(&self) -> String {
        format!("clusters/{}/etcd-peer-ca.pem", self.name)
    }

    fn etcd_peer_encrypted_ca_key_path(&self) -> String {
        format!("clusters/{}/etcd-peer-ca-key-encrypted.base64", self.name)
    }

    fn etcd_peer_cert_path(&self) -> String {
        format!("clusters/{}/etcd-peer.pem", self.name)
    }

    fn etcd_peer_encrypted_key_path(&self) -> String {
        format!("clusters/{}/etcd-peer-key-encrypted.base64", self.name)
    }

    fn k8s_ca_cert_path(&self) -> String {
        format!("clusters/{}/k8s-ca.pem", self.name)
    }

    fn k8s_encrypted_ca_key_path(&self) -> String {
        format!("clusters/{}/k8s-ca-key-encrypted.base64", self.name)
    }

    fn k8s_encrypted_master_key_path(&self) -> String {
        format!("clusters/{}/k8s-master-key-encrypted.base64", self.name)
    }

    fn k8s_encrypted_node_key_path(&self) -> String {
        format!("clusters/{}/k8s-node-key-encrypted.base64", self.name)
    }

    fn gitignore_path(&self) -> String {
        format!("clusters/{}/.gitignore", self.name)
    }

    fn k8s_master_cert_path(&self) -> String {
        format!("clusters/{}/k8s-master.pem", self.name)
    }

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

    fn k8s_node_cert_path(&self) -> String {
        format!("clusters/{}/k8s-node.pem", self.name)
    }

    fn region(&self) -> &str {
        self.region
    }

    fn tfvars_path(&self) -> String {
        format!("clusters/{}/terraform.tfvars", self.name)
    }
}

impl<'a> ExistingCluster<'a> {
    pub fn new(matches: &'a ArgMatches) -> Self {
        ExistingCluster {
            aws_credentials_provider: credentials_provider(
                matches.value_of("aws-credentials-path"),
                matches.value_of("aws-credentials-profile"),
            ),
            cluster: Cluster::new(
                matches.value_of("cluster").expect("missing cluster name"),
                matches.value_of("region").expect("missing region"),
            ),
            domain: matches.value_of("domain").expect("missing domain"),
            kms_master_key_id: matches.value_of("kms-key").expect("missing kms-key"),
        }
    }

    pub fn generate_pki(&mut self) -> KawsResult {
        self.generate_etcd_pki(self.kms_master_key_id)?;
        self.generate_etcd_peer_pki(self.kms_master_key_id)?;
        self.generate_k8s_pki(self.kms_master_key_id)?;

        Ok(None)
    }

    fn generate_etcd_pki(&self, kms_key_id: &str) -> KawsResult {
        let ca = CertificateAuthority::generate(&format!("kaws-etcd-ca-{}", self.cluster.name))?;

        let (server_cert, server_key) = ca.generate_cert(
            &format!("kaws-etcd-server-{}", self.cluster.name),
            Some(&[
                "10.0.1.4",
                "10.0.1.5",
                "10.0.1.6",
            ]),
        )?;

        let (client_cert, client_key) = ca.generate_cert(
            &format!("kaws-etcd-client-{}", self.cluster.name),
            None,
        )?;

        let mut encryptor = Encryptor::new(
            self.aws_credentials_provider.clone(),
            self.cluster.region().parse()?,
            Some(kms_key_id),
        );

        ca.write_to_files(
            &mut encryptor,
            &self.cluster.etcd_ca_cert_path(),
            &self.cluster.etcd_encrypted_ca_key_path(),
        )?;

        server_cert.write_to_file(&self.cluster.etcd_server_cert_path())?;
        server_key.write_to_file(
            &mut encryptor,
            &self.cluster.etcd_encrypted_server_key_path(),
        )?;

        client_cert.write_to_file(&self.cluster.etcd_client_cert_path())?;
        client_key.write_to_file(
            &mut encryptor,
            &self.cluster.etcd_encrypted_client_key_path(),
        )?;

        Ok(None)
    }

    fn generate_etcd_peer_pki(&self, kms_key_id: &str) -> KawsResult {
        let ca = CertificateAuthority::generate(
            &format!("kaws-etcd-peer-ca-{}", self.cluster.name)
        )?;

        let (peer_cert, peer_key) = ca.generate_cert(
            &format!("kaws-etcd-peer-{}", self.cluster.name),
            Some(&[
                "10.0.1.4",
                "10.0.1.5",
                "10.0.1.6",
            ]),
        )?;

        let mut encryptor = Encryptor::new(
            self.aws_credentials_provider.clone(),
            self.cluster.region().parse()?,
            Some(kms_key_id),
        );

        ca.write_to_files(
            &mut encryptor,
            &self.cluster.etcd_peer_ca_cert_path(),
            &self.cluster.etcd_peer_encrypted_ca_key_path(),
        )?;

        peer_cert.write_to_file(&self.cluster.etcd_peer_cert_path())?;
        peer_key.write_to_file(
            &mut encryptor,
            &self.cluster.etcd_peer_encrypted_key_path(),
        )?;

        Ok(None)
    }

    fn generate_k8s_pki(&self, kms_key_id: &str) -> KawsResult {
        let ca = CertificateAuthority::generate(&format!("kaws-k8s-ca-{}", self.cluster.name))?;

        let (master_cert, master_key) = ca.generate_cert(
            &format!("kaws-k8s-master-{}", self.cluster.name),
            Some(&[
                "kubernetes",
                "kubernetes.default",
                "kubernetes.default.svc",
                "kubernetes.default.svc.cluster.local",
                &format!("kubernetes.{}", self.domain),
                "10.3.0.1",
            ]),
        )?;

        let (node_cert, node_key) = ca.generate_cert(
            &format!("kaws-k8s-node-{}", self.cluster.name),
            None,
        )?;

        let mut encryptor = Encryptor::new(
            self.aws_credentials_provider.clone(),
            self.cluster.region().parse()?,
            Some(kms_key_id),
        );

        ca.write_to_files(
            &mut encryptor,
            &self.cluster.k8s_ca_cert_path(),
            &self.cluster.k8s_encrypted_ca_key_path(),
        )?;

        master_cert.write_to_file(&self.cluster.k8s_master_cert_path())?;
        master_key.write_to_file(
            &mut encryptor,
            &self.cluster.k8s_encrypted_master_key_path(),
        )?;

        node_cert.write_to_file(&self.cluster.k8s_node_cert_path())?;
        node_key.write_to_file(
            &mut encryptor,
            &self.cluster.k8s_encrypted_node_key_path(),
        )?;

        Ok(None)
    }
}

impl<'a> NewCluster<'a> {
    pub fn new(matches: &'a ArgMatches) -> Self {
        NewCluster {
            availability_zone: matches
                .value_of("availability-zone")
                .expect("missing availability-zone"),
            aws_account_id: matches.value_of("aws-account-id").expect("missing aws-account-id"),
            cluster: Cluster::new(
                matches.value_of("cluster").expect("missing cluster name"),
                matches.value_of("region").expect("missing region"),
            ),
            coreos_ami: matches.value_of("ami").expect("missing ami"),
            domain: matches.value_of("domain").expect("missing domain"),
            iam_users: matches
                .values_of("iam-user")
                .expect("missing iam-users")
                .collect(),
            instance_size: matches.value_of("size").expect("missing instance size"),
            kubernetes_version: matches.value_of("k8s-version").expect("missing k8s-version"),
            masters_max_size: matches
                .value_of("masters-max-size")
                .expect("missing masters-max-size"),
            masters_min_size: matches
                .value_of("masters-min-size")
                .expect("missing masters-min-size"),
            nodes_max_size: matches
                .value_of("nodes-max-size")
                .expect("missing nodes-max-size"),
            nodes_min_size: matches
                .value_of("nodes-min-size")
                .expect("missing nodes-min-size"),
            rbac_super_user: matches.value_of("rbac-super-user").expect("missing rbac-super-user"),
            ssh_keys: matches.values_of("ssh-key").expect("missing ssh-keys").collect(),
            zone_id: matches.value_of("zone-id").expect("missing zone-id"),
        }
    }

    pub fn init(&mut self) -> KawsResult {
        try!(self.create_directories());
        try!(self.create_gitignore());
        try!(self.create_tfvars());
        try!(self.create_pki_stubs());

        Ok(Some(format!(
            "Cluster \"{name}\" initialized! Commit clusters/{name} to Git.",
            name = self.cluster.name,
        )))
    }

    fn create_directories(&self) -> KawsResult {
        log_wrap!("Creating directories for the new cluster", {
            try!(create_dir_all(format!("clusters/{}", self.cluster.name)));
        });

        Ok(None)
    }

    fn create_gitignore(&self) -> KawsResult {
        log_wrap!("Creating .gitignore file", {
            let mut file = try!(File::create(&self.cluster.gitignore_path()));

            try!(write!(file, "*-key.pem"));
        });

        Ok(None)
    }

    fn create_tfvars(&self) -> KawsResult {
        log_wrap!("Creating tfvars file", {
            let mut file = try!(File::create(&self.cluster.tfvars_path()));

            try!(write!(
                file,
                "\
kaws_account_id = \"{}\"
kaws_availability_zone = \"{}\"
kaws_cluster = \"{}\"
kaws_coreos_ami = \"{}\"
kaws_domain = \"{}\"
kaws_etcd_01_initial_cluster_state = \"new\"
kaws_etcd_02_initial_cluster_state = \"new\"
kaws_etcd_03_initial_cluster_state = \"new\"
kaws_iam_users = [{}]
kaws_instance_size = \"{}\"
kaws_masters_max_size = \"{}\"
kaws_masters_min_size = \"{}\"
kaws_nodes_max_size = \"{}\"
kaws_nodes_min_size = \"{}\"
kaws_propagating_vgws = []
kaws_rbac_super_user = \"{}\"
kaws_region = \"{}\"
kaws_ssh_keys = [{}]
kaws_version = \"{}\"
kaws_zone_id = \"{}\"
",
                self.aws_account_id,
                self.availability_zone,
                self.cluster.name(),
                self.coreos_ami,
                self.domain,
                self.iam_users.iter().map(|iam_user| {
                    format!("\"{}\"", iam_user)
                }).collect::<Vec<String>>().join(", "),
                self.instance_size,
                self.masters_max_size,
                self.masters_min_size,
                self.nodes_max_size,
                self.nodes_min_size,
                self.rbac_super_user,
                self.cluster.region(),
                self.ssh_keys.iter().map(|ssh_key| {
                    format!("\"{}\"", ssh_key)
                }).collect::<Vec<String>>().join(", "),
                self.kubernetes_version,
                self.zone_id,
            ));
        });

        Ok(None)
    }

    fn create_pki_stubs(&self) -> KawsResult {
        let paths = [
            // etcd ca
            &self.cluster.etcd_ca_cert_path(),
            &self.cluster.etcd_encrypted_ca_key_path(),

            // etcd server
            &self.cluster.etcd_server_cert_path(),
            &self.cluster.etcd_encrypted_server_key_path(),

            // etcd clients
            &self.cluster.etcd_client_cert_path(),
            &self.cluster.etcd_encrypted_client_key_path(),

            // etcd peer ca
            &self.cluster.etcd_peer_ca_cert_path(),
            &self.cluster.etcd_peer_encrypted_ca_key_path(),

            // etcd peers
            &self.cluster.etcd_peer_cert_path(),
            &self.cluster.etcd_peer_encrypted_key_path(),

            // k8s ca
            &self.cluster.k8s_ca_cert_path(),
            &self.cluster.k8s_encrypted_ca_key_path(),

            // k8s masters
            &self.cluster.k8s_master_cert_path(),
            &self.cluster.k8s_encrypted_master_key_path(),

            // k8s nodes
            &self.cluster.k8s_node_cert_path(),
            &self.cluster.k8s_encrypted_node_key_path(),
        ];

        for path in paths.iter() {
            File::create(path)?;
        }

        Ok(None)
    }
}
<|endoftext|>


<commit_before>use llvm_sys::core::{LLVMAppendBasicBlockInContext, LLVMContextCreate, LLVMContextDispose, LLVMCreateBuilderInContext, LLVMDoubleTypeInContext, LLVMFloatTypeInContext, LLVMFP128TypeInContext, LLVMInsertBasicBlockInContext, LLVMInt16TypeInContext, LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext, LLVMInt8TypeInContext, LLVMIntTypeInContext, LLVMModuleCreateWithNameInContext, LLVMStructCreateNamed, LLVMStructSetBody, LLVMStructTypeInContext, LLVMVoidTypeInContext, LLVMHalfTypeInContext, LLVMGetGlobalContext, LLVMPPCFP128TypeInContext};
use llvm_sys::prelude::{LLVMContextRef, LLVMTypeRef};

use basic_block::BasicBlock;
use builder::Builder;
use module::Module;
use types::{BasicType, FloatType, IntType, StructType, VoidType};
use values::{AsValueRef, FunctionValue};

use std::ffi::CString;
use std::mem::forget;
use std::ops::Deref;

// From Docs: A single context is not thread safe.
// However, different contexts can execute on different threads simultaneously.
pub struct Context {
    context: LLVMContextRef,
}

impl Context {
    pub(crate) fn new(context: LLVMContextRef) -> Self {
        assert!(!context.is_null());

        Context {
            context: context
        }
    }

    pub fn create() -> Self {
        let context = unsafe {
            LLVMContextCreate()
        };

        Context::new(context)
    }

    pub fn get_global_context() -> ContextRef {
        let context = unsafe {
            LLVMGetGlobalContext()
        };

        ContextRef::new(Context::new(context))
    }

    pub fn create_builder(&self) -> Builder {
        let builder = unsafe {
            LLVMCreateBuilderInContext(self.context)
        };

        Builder::new(builder)
    }

    pub fn create_module(&self, name: &str) -> Module {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let module = unsafe {
            LLVMModuleCreateWithNameInContext(c_string.as_ptr(), self.context)
        };

        Module::new(module)
    }

    pub fn void_type(&self) -> VoidType {
        let void_type = unsafe {
            LLVMVoidTypeInContext(self.context)
        };

        VoidType::new(void_type)
    }

    pub fn bool_type(&self) -> IntType {
        let bool_type = unsafe {
            LLVMInt1TypeInContext(self.context)
        };

        IntType::new(bool_type)
    }

    pub fn i8_type(&self) -> IntType {
        let i8_type = unsafe {
            LLVMInt8TypeInContext(self.context)
        };

        IntType::new(i8_type)
    }

    pub fn i16_type(&self) -> IntType {
        let i16_type = unsafe {
            LLVMInt16TypeInContext(self.context)
        };

        IntType::new(i16_type)
    }

    pub fn i32_type(&self) -> IntType {
        let i32_type = unsafe {
            LLVMInt32TypeInContext(self.context)
        };

        IntType::new(i32_type)
    }

    pub fn i64_type(&self) -> IntType {
        let i64_type = unsafe {
            LLVMInt64TypeInContext(self.context)
        };

        IntType::new(i64_type)
    }

    pub fn i128_type(&self) -> IntType {
        // REVIEW: The docs says there's a LLVMInt128TypeInContext, but
        // it might only be in a newer version

        let i128_type = unsafe {
            LLVMIntTypeInContext(self.context, 128)
        };

        IntType::new(i128_type)
    }

    pub fn custom_width_int_type(&self, bits: u32) -> IntType {
        let int_type = unsafe {
            LLVMIntTypeInContext(self.context, bits)
        };

        IntType::new(int_type)
    }

    pub fn f16_type(&self) -> FloatType {
        let f16_type = unsafe {
            LLVMHalfTypeInContext(self.context)
        };

        FloatType::new(f16_type)
    }

    pub fn f32_type(&self) -> FloatType {
        let f32_type = unsafe {
            LLVMFloatTypeInContext(self.context)
        };

        FloatType::new(f32_type)
    }

    pub fn f64_type(&self) -> FloatType {
        let f64_type = unsafe {
            LLVMDoubleTypeInContext(self.context)
        };

        FloatType::new(f64_type)
    }

    pub fn f128_type(&self) -> FloatType {
        let f128_type = unsafe {
            LLVMFP128TypeInContext(self.context)
        };

        FloatType::new(f128_type)
    }

    pub fn f128_type_ppc(&self) -> FloatType {
        let f128_type = unsafe {
            LLVMPPCFP128TypeInContext(self.context)
        };

        FloatType::new(f128_type)
    }

    // REVIEW: AnyType but VoidType? FunctionType?
    // REVIEW: Changed field_types signature, untested
    pub fn struct_type(&self, field_types: &[&BasicType], packed: bool, name: &str) -> StructType {
        let mut field_types: Vec<LLVMTypeRef> = field_types.iter()
                                                           .map(|val| val.as_type_ref())
                                                           .collect();
        let struct_type = if name.is_empty() {
            unsafe {
                LLVMStructTypeInContext(self.context, field_types.as_mut_ptr(), field_types.len() as u32, packed as i32)
            }
        } else {
            let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

            unsafe {
                let struct_type = LLVMStructCreateNamed(self.context, c_string.as_ptr());

                LLVMStructSetBody(struct_type, field_types.as_mut_ptr(), field_types.len() as u32, packed as i32);

                struct_type
            }
        };

        StructType::new(struct_type)
    }

    pub fn append_basic_block(&self, function: &FunctionValue, name: &str) -> BasicBlock {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let bb = unsafe {
            LLVMAppendBasicBlockInContext(self.context, function.as_value_ref(), c_string.as_ptr())
        };

        BasicBlock::new(bb)
    }

    pub fn insert_basic_block_after(&self, basic_block: &BasicBlock, name: &str) -> BasicBlock {
        match basic_block.get_next_basic_block() {
            Some(next_basic_block) => self.prepend_basic_block(&next_basic_block, name),
            None => {
                let parent_fn = basic_block.get_parent();

                self.append_basic_block(&parent_fn, name)
            },
        }
    }

    pub fn prepend_basic_block(&self, basic_block: &BasicBlock, name: &str) -> BasicBlock {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let bb = unsafe {
            LLVMInsertBasicBlockInContext(self.context, basic_block.basic_block, c_string.as_ptr())
        };

        BasicBlock::new(bb)
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            LLVMContextDispose(self.context);
        }
    }
}

// Alternate strategy would be to just define ownership parameter
// on Context, and only call destructor if true. Not sure of pros/cons
// compared to this approach other than not needing Deref trait's ugly syntax
pub struct ContextRef {
    context: Option<Context>,
}

impl ContextRef {
    pub fn new(context: Context) -> Self {
        ContextRef {
            context: Some(context),
        }
    }
}

impl Deref for ContextRef {
    type Target = Context;

    fn deref(&self) -> &Self::Target {
        self.context.as_ref().expect("ContextRef should never be deref'd after being dropped")
    }
}

impl Drop for ContextRef {
    fn drop(&mut self) {
        forget(self.context.take());
    }
}

#[test]
fn test_no_context_double_free() {
    let context = Context::create();
    let int = context.i8_type();

    {
        int.get_context();
    }
}

#[test]
fn test_no_context_double_free2() {
    let context = Context::create();
    let int = context.i8_type();
    let context2 = int.get_context();

    fn move_(_: Context) {}

    move_(context);

    context2.i8_type().const_int(0, false);
}

#[test]
fn test_no_context_double_free3() {
    Context::get_global_context();
    Context::get_global_context();
}

#[test]
fn test_get_context_from_contextless_value() {
    let int = IntType::i8_type();
    let global_context = unsafe {
        LLVMGetGlobalContext()
    };

    assert!(!(*int.get_context()).context.is_null());
    assert!((*int.get_context()).context == global_context);
}
<commit_msg>More basic block coverage<commit_after>use llvm_sys::core::{LLVMAppendBasicBlockInContext, LLVMContextCreate, LLVMContextDispose, LLVMCreateBuilderInContext, LLVMDoubleTypeInContext, LLVMFloatTypeInContext, LLVMFP128TypeInContext, LLVMInsertBasicBlockInContext, LLVMInt16TypeInContext, LLVMInt1TypeInContext, LLVMInt32TypeInContext, LLVMInt64TypeInContext, LLVMInt8TypeInContext, LLVMIntTypeInContext, LLVMModuleCreateWithNameInContext, LLVMStructCreateNamed, LLVMStructSetBody, LLVMStructTypeInContext, LLVMVoidTypeInContext, LLVMHalfTypeInContext, LLVMGetGlobalContext, LLVMPPCFP128TypeInContext};
use llvm_sys::prelude::{LLVMContextRef, LLVMTypeRef};

use basic_block::BasicBlock;
use builder::Builder;
use module::Module;
use types::{BasicType, FloatType, IntType, StructType, VoidType};
use values::{AsValueRef, FunctionValue};

use std::ffi::CString;
use std::mem::forget;
use std::ops::Deref;

// From Docs: A single context is not thread safe.
// However, different contexts can execute on different threads simultaneously.
pub struct Context {
    context: LLVMContextRef,
}

impl Context {
    pub(crate) fn new(context: LLVMContextRef) -> Self {
        assert!(!context.is_null());

        Context {
            context: context
        }
    }

    pub fn create() -> Self {
        let context = unsafe {
            LLVMContextCreate()
        };

        Context::new(context)
    }

    pub fn get_global_context() -> ContextRef {
        let context = unsafe {
            LLVMGetGlobalContext()
        };

        ContextRef::new(Context::new(context))
    }

    pub fn create_builder(&self) -> Builder {
        let builder = unsafe {
            LLVMCreateBuilderInContext(self.context)
        };

        Builder::new(builder)
    }

    pub fn create_module(&self, name: &str) -> Module {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let module = unsafe {
            LLVMModuleCreateWithNameInContext(c_string.as_ptr(), self.context)
        };

        Module::new(module)
    }

    pub fn void_type(&self) -> VoidType {
        let void_type = unsafe {
            LLVMVoidTypeInContext(self.context)
        };

        VoidType::new(void_type)
    }

    pub fn bool_type(&self) -> IntType {
        let bool_type = unsafe {
            LLVMInt1TypeInContext(self.context)
        };

        IntType::new(bool_type)
    }

    pub fn i8_type(&self) -> IntType {
        let i8_type = unsafe {
            LLVMInt8TypeInContext(self.context)
        };

        IntType::new(i8_type)
    }

    pub fn i16_type(&self) -> IntType {
        let i16_type = unsafe {
            LLVMInt16TypeInContext(self.context)
        };

        IntType::new(i16_type)
    }

    pub fn i32_type(&self) -> IntType {
        let i32_type = unsafe {
            LLVMInt32TypeInContext(self.context)
        };

        IntType::new(i32_type)
    }

    pub fn i64_type(&self) -> IntType {
        let i64_type = unsafe {
            LLVMInt64TypeInContext(self.context)
        };

        IntType::new(i64_type)
    }

    pub fn i128_type(&self) -> IntType {
        // REVIEW: The docs says there's a LLVMInt128TypeInContext, but
        // it might only be in a newer version

        let i128_type = unsafe {
            LLVMIntTypeInContext(self.context, 128)
        };

        IntType::new(i128_type)
    }

    pub fn custom_width_int_type(&self, bits: u32) -> IntType {
        let int_type = unsafe {
            LLVMIntTypeInContext(self.context, bits)
        };

        IntType::new(int_type)
    }

    pub fn f16_type(&self) -> FloatType {
        let f16_type = unsafe {
            LLVMHalfTypeInContext(self.context)
        };

        FloatType::new(f16_type)
    }

    pub fn f32_type(&self) -> FloatType {
        let f32_type = unsafe {
            LLVMFloatTypeInContext(self.context)
        };

        FloatType::new(f32_type)
    }

    pub fn f64_type(&self) -> FloatType {
        let f64_type = unsafe {
            LLVMDoubleTypeInContext(self.context)
        };

        FloatType::new(f64_type)
    }

    pub fn f128_type(&self) -> FloatType {
        let f128_type = unsafe {
            LLVMFP128TypeInContext(self.context)
        };

        FloatType::new(f128_type)
    }

    pub fn f128_type_ppc(&self) -> FloatType {
        let f128_type = unsafe {
            LLVMPPCFP128TypeInContext(self.context)
        };

        FloatType::new(f128_type)
    }

    // REVIEW: AnyType but VoidType? FunctionType?
    // REVIEW: Changed field_types signature, untested
    pub fn struct_type(&self, field_types: &[&BasicType], packed: bool, name: &str) -> StructType {
        let mut field_types: Vec<LLVMTypeRef> = field_types.iter()
                                                           .map(|val| val.as_type_ref())
                                                           .collect();
        let struct_type = if name.is_empty() {
            unsafe {
                LLVMStructTypeInContext(self.context, field_types.as_mut_ptr(), field_types.len() as u32, packed as i32)
            }
        } else {
            let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

            unsafe {
                let struct_type = LLVMStructCreateNamed(self.context, c_string.as_ptr());

                LLVMStructSetBody(struct_type, field_types.as_mut_ptr(), field_types.len() as u32, packed as i32);

                struct_type
            }
        };

        StructType::new(struct_type)
    }

    pub fn append_basic_block(&self, function: &FunctionValue, name: &str) -> BasicBlock {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let bb = unsafe {
            LLVMAppendBasicBlockInContext(self.context, function.as_value_ref(), c_string.as_ptr())
        };

        BasicBlock::new(bb)
    }

    pub fn insert_basic_block_after(&self, basic_block: &BasicBlock, name: &str) -> BasicBlock {
        match basic_block.get_next_basic_block() {
            Some(next_basic_block) => self.prepend_basic_block(&next_basic_block, name),
            None => {
                let parent_fn = basic_block.get_parent();

                self.append_basic_block(&parent_fn, name)
            },
        }
    }

    pub fn prepend_basic_block(&self, basic_block: &BasicBlock, name: &str) -> BasicBlock {
        let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");

        let bb = unsafe {
            LLVMInsertBasicBlockInContext(self.context, basic_block.basic_block, c_string.as_ptr())
        };

        BasicBlock::new(bb)
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            LLVMContextDispose(self.context);
        }
    }
}

// Alternate strategy would be to just define ownership parameter
// on Context, and only call destructor if true. Not sure of pros/cons
// compared to this approach other than not needing Deref trait's ugly syntax
pub struct ContextRef {
    context: Option<Context>,
}

impl ContextRef {
    pub fn new(context: Context) -> Self {
        ContextRef {
            context: Some(context),
        }
    }
}

impl Deref for ContextRef {
    type Target = Context;

    fn deref(&self) -> &Self::Target {
        self.context.as_ref().expect("ContextRef should never be deref'd after being dropped")
    }
}

impl Drop for ContextRef {
    fn drop(&mut self) {
        forget(self.context.take());
    }
}

#[test]
fn test_no_context_double_free() {
    let context = Context::create();
    let int = context.i8_type();

    {
        int.get_context();
    }
}

#[test]
fn test_no_context_double_free2() {
    let context = Context::create();
    let int = context.i8_type();
    let context2 = int.get_context();

    fn move_(_: Context) {}

    move_(context);

    context2.i8_type().const_int(0, false);
}

#[test]
fn test_no_context_double_free3() {
    Context::get_global_context();
    Context::get_global_context();
}

#[test]
fn test_get_context_from_contextless_value() {
    let int = IntType::i8_type();
    let global_context = unsafe {
        LLVMGetGlobalContext()
    };

    assert!(!(*int.get_context()).context.is_null());
    assert!((*int.get_context()).context == global_context);
}

#[test]
fn test_basic_block_ordering() {
    use context::Context;

    let context = Context::create();
    let module = context.create_module("test");

    let i128_type = context.i128_type();
    let fn_type = i128_type.fn_type(&[], false);

    let function = module.add_function("testing", &fn_type);

    let basic_block = context.append_basic_block(&function, "entry");
    let basic_block4 = context.insert_basic_block_after(&basic_block, "block4");
    let basic_block2 = context.insert_basic_block_after(&basic_block, "block2");
    let basic_block3 = context.prepend_basic_block(&basic_block4, "block3");

    let basic_blocks = function.get_basic_blocks();

    assert_eq!(basic_blocks.len(), 4);
    assert_eq!(basic_blocks[0].basic_block, basic_block.basic_block);
    assert_eq!(basic_blocks[1].basic_block, basic_block2.basic_block);
    assert_eq!(basic_blocks[2].basic_block, basic_block3.basic_block);
    assert_eq!(basic_blocks[3].basic_block, basic_block4.basic_block);
}
<|endoftext|>


<commit_before>use raw::*;
use std::mem;
use std::kinds::marker::{NoSync, NoSend};
use util::NativeRef;
use {CompiledFunction, Type, UncompiledFunction};
/// Holds all of the functions you have built and compiled. There can be
/// multiple, but normally there is only one.
pub struct Context {
    _context: jit_context_t
}
native_ref!(Context, _context, jit_context_t)

/// A context that is in the build phase while generating IR
pub struct Builder {
    _context: jit_context_t,
    no_sync: NoSync,
    no_send: NoSend
}
impl NativeRef for Builder {
    #[inline(always)]
    unsafe fn as_ptr(&self) -> jit_context_t {
        self._context
    }
    #[inline(always)]
    unsafe fn from_ptr(ptr:jit_context_t) -> Builder {
        Builder {
            _context: ptr,
            no_sync: NoSync,
            no_send: NoSend
        }
    }
}

impl Context {
    unsafe fn as_builder(&mut self) -> Builder {
        Builder{
            _context: self._context,
            no_sync: NoSync,
            no_send: NoSend
        }
    }
    #[inline(always)]
    /// Create a new JIT Context
    pub fn new() -> Context {
        unsafe {
            NativeRef::from_ptr(jit_context_create())
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR
    pub fn build<R, F:FnOnce(&Builder) -> R>(&mut self, cb: F) -> R {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let r = cb(&self.as_builder());
            jit_context_build_end(self.as_ptr());
            r
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR in a new function on the context which is
    /// compiled for you
    pub fn build_func<'a, F:FnOnce(&UncompiledFunction<'a>)>(&'a mut self, signature: Type, cb: F) -> CompiledFunction {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let builder = self.as_builder();
            let func = UncompiledFunction::new(mem::copy_lifetime(self, &builder), signature.clone());
            cb(&func);
            jit_context_build_end(self.as_ptr());
            func.compile()
        }
    }
}
#[unsafe_destructor]
impl Drop for Context {
    #[inline(always)]
    fn drop(&mut self) {
        unsafe {
            jit_context_destroy(self.as_ptr());
        }
    }
}<commit_msg>Add explicit lifetime to `build_func` result<commit_after>use raw::*;
use std::mem;
use std::kinds::marker::{NoSync, NoSend};
use util::NativeRef;
use {CompiledFunction, Type, UncompiledFunction};
/// Holds all of the functions you have built and compiled. There can be
/// multiple, but normally there is only one.
pub struct Context {
    _context: jit_context_t
}
native_ref!(Context, _context, jit_context_t)

/// A context that is in the build phase while generating IR
pub struct Builder {
    _context: jit_context_t,
    no_sync: NoSync,
    no_send: NoSend
}
impl NativeRef for Builder {
    #[inline(always)]
    unsafe fn as_ptr(&self) -> jit_context_t {
        self._context
    }
    #[inline(always)]
    unsafe fn from_ptr(ptr:jit_context_t) -> Builder {
        Builder {
            _context: ptr,
            no_sync: NoSync,
            no_send: NoSend
        }
    }
}

impl Context {
    unsafe fn as_builder(&mut self) -> Builder {
        Builder{
            _context: self._context,
            no_sync: NoSync,
            no_send: NoSend
        }
    }
    #[inline(always)]
    /// Create a new JIT Context
    pub fn new() -> Context {
        unsafe {
            NativeRef::from_ptr(jit_context_create())
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR
    pub fn build<R, F:FnOnce(&Builder) -> R>(&mut self, cb: F) -> R {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let r = cb(&self.as_builder());
            jit_context_build_end(self.as_ptr());
            r
        }
    }
    #[inline(always)]
    /// Lock the context so you can safely generate IR in a new function on the context which is
    /// compiled for you
    pub fn build_func<'a, F:FnOnce(&UncompiledFunction<'a>)>(&'a mut self, signature: Type, cb: F) -> CompiledFunction<'a> {
        unsafe {
            jit_context_build_start(self.as_ptr());
            let builder = self.as_builder();
            let func = UncompiledFunction::new(mem::copy_lifetime(self, &builder), signature.clone());
            cb(&func);
            jit_context_build_end(self.as_ptr());
            func.compile()
        }
    }
}
#[unsafe_destructor]
impl Drop for Context {
    #[inline(always)]
    fn drop(&mut self) {
        unsafe {
            jit_context_destroy(self.as_ptr());
        }
    }
}<|endoftext|>


<commit_before>use std::rc::Rc;

use state::State;
use super::{Action, config, Conditions, Message, TimerEvent};

use action::ExecResult;
use self::linear::LinearContext;
use self::map::MapContext;

#[derive(Debug)]
pub struct BaseContext {
    conditions: Conditions,
    actions: Vec<Action>
}

impl BaseContext {
    pub fn new(conditions: Conditions) -> BaseContext {
        BaseContext {
            conditions: conditions,
            actions: Vec::new()
        }
    }

    pub fn actions(&self) -> &[Action] {
        &self.actions
    }

    pub fn on_timer(&self, event: &TimerEvent, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.on_timer(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        }
        None
    }

    pub fn on_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.conditions.ignore_message(&event) {
            None
        } else {
            self.on_relevant_message(event, state)
        }
    }

    pub fn on_relevant_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.add_message(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        } else if self.conditions.is_opening(&event) {
            state.add_message(event);
            state.open();
        }
        None
    }

    fn close_state(&self, state: &mut State) -> Option<Vec<ExecResult>> {
        state.close();
        if self.actions.is_empty() {
            None
        } else {
            let commands = self.actions().iter().map(|action| action.execute(state, self)).collect();
            Some(commands)
        }
    }
}

impl From<config::Context> for BaseContext {
    fn from(config: config::Context) -> BaseContext {
        let config::Context{conditions, actions} = config;
        BaseContext {
            conditions: conditions,
            actions: actions
        }
    }
}

#[derive(Debug)]
pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl Context {
    pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_timer(event),
            Context::Map(ref mut context) => context.on_timer(event),
        }
    }

    pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_message(event),
            Context::Map(ref mut context) => context.on_message(event),
        }
    }

    pub fn is_open(&mut self) -> bool {
        match *self {
            Context::Linear(ref context) => context.is_open(),
            Context::Map(ref mut context) => context.is_open(),
        }
    }

    pub fn new_linear(conditions: Conditions) -> Context {
        Context::Linear(
            LinearContext::new(conditions)
        )
    }

    pub fn new_map(conditions: Conditions) -> Context {
        Context::Map(
            MapContext::new(conditions)
        )
    }
}

impl From<config::Context> for Context {
    fn from(config: config::Context) -> Context {
        Context::Linear(LinearContext::from(config))
    }
}

mod linear {
    use std::rc::Rc;

    use action::ExecResult;
    use config;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContext::new(conditions),
                state: State::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.base.on_message(event, &mut self.state)
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }
    }

    impl From<config::Context> for LinearContext {
        fn from(config: config::Context) -> LinearContext {
            LinearContext {
                base: BaseContext::from(config),
                state: State::new()
            }
        }
    }
}

mod map {
    use std::collections::BTreeMap;
    use std::fmt::Write;
    use std::rc::Rc;

    use action::ExecResult;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct MapContext {
        base: BaseContext,
        map: BTreeMap<String, State>,
        format_buffer: String
    }

    impl MapContext {
        pub fn new(conditions: Conditions) -> MapContext {
            MapContext {
                base: BaseContext::new(conditions),
                map: BTreeMap::new(),
                format_buffer: String::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            let mut result: Vec<ExecResult> = Vec::new();

            for (_, mut state) in self.map.iter_mut() {
                if let Some(commands) = self.base.on_timer(event, &mut state) {
                    for i in commands.into_iter() {
                        result.push(i);
                    }
                }
            }

            self.remove_closed_states();
            if result.is_empty() {
                None
            } else {
                Some(result)
            }
        }

        fn get_closed_state_ids(&self) -> Vec<String> {
            self.map.iter().filter_map(|(id, state)| {
                if !state.is_open() {
                    Some(id.clone())
                } else {
                    None
                }
            }).collect::<Vec<String>>()
        }

        fn remove_closed_states(&mut self) {
            for id in self.get_closed_state_ids() {
                let _ = self.map.remove(&id);
            }
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.format_context_id(&event);
            let result = self.update_state(event);
            self.format_buffer.clear();
            self.remove_closed_states();
            result
        }

        fn update_state(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            let id = self.format_buffer.clone();
            let state = self.map.entry(id).or_insert(State::new());
            self.base.on_message(event, state)
        }

        pub fn is_open(&mut self) -> bool {
            !self.map.is_empty()
        }

        fn format_context_id(&mut self, message: &Message) {
            let empty = String::new();
            let _ = self.format_buffer.write_str(message.get("HOST").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PROGRAM").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PID").unwrap_or(&empty));
        }
    }

    #[cfg(test)]
    mod test {
        use conditions::Builder;
        use Context;
        use TimerEvent;
        use message;

        use std::rc::Rc;

        #[test]
        fn test_given_map_context_when_messages_have_the_same_kvpairs_then_they_go_to_the_same_context() {
            let delta = 10;
            let timeout = 30;
            let event = TimerEvent(delta);
            let patterns: Vec<String> = vec!["1".to_string(), "2".to_string(), "3".to_string()];
            let mut context = Context::new_map(Builder::new(timeout).patterns(patterns).build());
            let msg1 = message::Builder::new("1".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();
            let msg2 = message::Builder::new("2".to_string())
                                        .pair("HOST".to_string(), "host2".to_string())
                                        .pair("PROGRAM".to_string(), "program2".to_string())
                                        .pair("PID".to_string(), "pid2".to_string())
                                        .build();
            let msg3 = message::Builder::new("3".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();

            assert_false!(context.is_open());
            context.on_message(Rc::new(msg1));
            assert_true!(context.is_open());
            context.on_timer(&event);
            context.on_message(Rc::new(msg2));
            context.on_message(Rc::new(msg3));
            context.on_timer(&event);
            context.on_timer(&event);
            assert_true!(context.is_open());
            context.on_timer(&event);
            assert_false!(context.is_open());
        }
    }
}

#[cfg(test)]
mod test {
    use std::rc::Rc;

    use message;
    use TimerEvent;
    use super::Context;
    use conditions::Builder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).max_size(max_size).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        println!("{:?}", &context);
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<commit_msg>MapContext: refactor<commit_after>use std::rc::Rc;

use state::State;
use super::{Action, config, Conditions, Message, TimerEvent};

use action::ExecResult;
use self::linear::LinearContext;
use self::map::MapContext;

#[derive(Debug)]
pub struct BaseContext {
    conditions: Conditions,
    actions: Vec<Action>
}

impl BaseContext {
    pub fn new(conditions: Conditions) -> BaseContext {
        BaseContext {
            conditions: conditions,
            actions: Vec::new()
        }
    }

    pub fn actions(&self) -> &[Action] {
        &self.actions
    }

    pub fn on_timer(&self, event: &TimerEvent, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.on_timer(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        }
        None
    }

    pub fn on_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.conditions.ignore_message(&event) {
            None
        } else {
            self.on_relevant_message(event, state)
        }
    }

    pub fn on_relevant_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.add_message(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        } else if self.conditions.is_opening(&event) {
            state.add_message(event);
            state.open();
        }
        None
    }

    fn close_state(&self, state: &mut State) -> Option<Vec<ExecResult>> {
        state.close();
        if self.actions.is_empty() {
            None
        } else {
            let commands = self.actions().iter().map(|action| action.execute(state, self)).collect();
            Some(commands)
        }
    }
}

impl From<config::Context> for BaseContext {
    fn from(config: config::Context) -> BaseContext {
        let config::Context{conditions, actions} = config;
        BaseContext {
            conditions: conditions,
            actions: actions
        }
    }
}

#[derive(Debug)]
pub enum Context {
    Linear(LinearContext),
    Map(MapContext)
}

impl Context {
    pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_timer(event),
            Context::Map(ref mut context) => context.on_timer(event),
        }
    }

    pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
        match *self {
            Context::Linear(ref mut context) => context.on_message(event),
            Context::Map(ref mut context) => context.on_message(event),
        }
    }

    pub fn is_open(&mut self) -> bool {
        match *self {
            Context::Linear(ref context) => context.is_open(),
            Context::Map(ref mut context) => context.is_open(),
        }
    }

    pub fn new_linear(conditions: Conditions) -> Context {
        Context::Linear(
            LinearContext::new(conditions)
        )
    }

    pub fn new_map(conditions: Conditions) -> Context {
        Context::Map(
            MapContext::new(conditions)
        )
    }
}

impl From<config::Context> for Context {
    fn from(config: config::Context) -> Context {
        Context::Linear(LinearContext::from(config))
    }
}

mod linear {
    use std::rc::Rc;

    use action::ExecResult;
    use config;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct LinearContext {
        base: BaseContext,
        state: State
    }

    impl LinearContext {
        pub fn new(conditions: Conditions) -> LinearContext {
            LinearContext {
                base: BaseContext::new(conditions),
                state: State::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            self.base.on_timer(event, &mut self.state)
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.base.on_message(event, &mut self.state)
        }

        pub fn is_open(&self) -> bool {
            self.state.is_open()
        }
    }

    impl From<config::Context> for LinearContext {
        fn from(config: config::Context) -> LinearContext {
            LinearContext {
                base: BaseContext::from(config),
                state: State::new()
            }
        }
    }
}

mod map {
    use std::collections::BTreeMap;
    use std::fmt::Write;
    use std::rc::Rc;

    use action::ExecResult;
    use Conditions;
    use Message;
    use state::State;
    use TimerEvent;
    use super::BaseContext;

    #[derive(Debug)]
    pub struct MapContext {
        base: BaseContext,
        map: BTreeMap<String, State>,
        format_buffer: String
    }

    impl MapContext {
        pub fn new(conditions: Conditions) -> MapContext {
            MapContext {
                base: BaseContext::new(conditions),
                map: BTreeMap::new(),
                format_buffer: String::new()
            }
        }

        pub fn on_timer(&mut self, event: &TimerEvent) -> Option<Vec<ExecResult>> {
            let mut result: Vec<ExecResult> = Vec::new();

            for (_, mut state) in self.map.iter_mut() {
                if let Some(commands) = self.base.on_timer(event, &mut state) {
                    for i in commands.into_iter() {
                        result.push(i);
                    }
                }
            }

            self.remove_closed_states();
            Some(result)
        }

        fn get_closed_state_ids(&self) -> Vec<String> {
            self.map.iter().filter_map(|(id, state)| {
                if !state.is_open() {
                    Some(id.clone())
                } else {
                    None
                }
            }).collect::<Vec<String>>()
        }

        fn remove_closed_states(&mut self) {
            for id in self.get_closed_state_ids() {
                let _ = self.map.remove(&id);
            }
        }

        pub fn on_message(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            self.format_context_id(&event);
            let result = self.update_state(event);
            self.format_buffer.clear();
            self.remove_closed_states();
            result
        }

        fn update_state(&mut self, event: Rc<Message>) -> Option<Vec<ExecResult>> {
            let id = self.format_buffer.clone();
            let state = self.map.entry(id).or_insert(State::new());
            self.base.on_message(event, state)
        }

        pub fn is_open(&mut self) -> bool {
            !self.map.is_empty()
        }

        fn format_context_id(&mut self, message: &Message) {
            let empty = String::new();
            let _ = self.format_buffer.write_str(message.get("HOST").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PROGRAM").unwrap_or(&empty));
            let _ = self.format_buffer.write_str(":");
            let _ = self.format_buffer.write_str(message.get("PID").unwrap_or(&empty));
        }
    }

    #[cfg(test)]
    mod test {
        use conditions::Builder;
        use Context;
        use TimerEvent;
        use message;

        use std::rc::Rc;

        #[test]
        fn test_given_map_context_when_messages_have_the_same_kvpairs_then_they_go_to_the_same_context() {
            let delta = 10;
            let timeout = 30;
            let event = TimerEvent(delta);
            let patterns: Vec<String> = vec!["1".to_string(), "2".to_string(), "3".to_string()];
            let mut context = Context::new_map(Builder::new(timeout).patterns(patterns).build());
            let msg1 = message::Builder::new("1".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();
            let msg2 = message::Builder::new("2".to_string())
                                        .pair("HOST".to_string(), "host2".to_string())
                                        .pair("PROGRAM".to_string(), "program2".to_string())
                                        .pair("PID".to_string(), "pid2".to_string())
                                        .build();
            let msg3 = message::Builder::new("3".to_string())
                                        .pair("HOST".to_string(), "host".to_string())
                                        .pair("PROGRAM".to_string(), "program".to_string())
                                        .pair("PID".to_string(), "pid".to_string())
                                        .build();

            assert_false!(context.is_open());
            context.on_message(Rc::new(msg1));
            assert_true!(context.is_open());
            context.on_timer(&event);
            context.on_message(Rc::new(msg2));
            context.on_message(Rc::new(msg3));
            context.on_timer(&event);
            context.on_timer(&event);
            assert_true!(context.is_open());
            context.on_timer(&event);
            assert_false!(context.is_open());
        }
    }
}

#[cfg(test)]
mod test {
    use std::rc::Rc;

    use message;
    use TimerEvent;
    use super::Context;
    use conditions::Builder;

    #[test]
    fn test_given_close_condition_with_timeout_when_the_timeout_expires_then_the_condition_is_met() {
        let timeout = 100;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        assert_false!(context.is_open());
        context.on_message(event);
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(50));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(49));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_max_size_when_the_max_size_reached_then_the_condition_is_met() {
        let timeout = 100;
        let max_size = 3;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).max_size(max_size).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        println!("{:?}", &context);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_message(event.clone());
        println!("{:?}", &context);
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_without_renewing_messages_then_the_condition_is_met() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_false!(context.is_open());
    }

    #[test]
    fn test_given_close_condition_with_renew_timeout_when_the_timeout_expires_with_renewing_messages_then_the_context_is_not_closed() {
        let timeout = 100;
        let renew_timeout = 10;
        let msg_id = "1".to_string();
        let mut context = Context::new_linear(Builder::new(timeout).renew_timeout(renew_timeout).patterns(vec![msg_id.clone()]).build());
        let msg1 = message::Builder::new(msg_id.clone()).build();
        let event = Rc::new(msg1);
        assert_false!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(8));
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
        context.on_message(event.clone());
        assert_true!(context.is_open());
        context.on_timer(&mut TimerEvent(1));
        assert_true!(context.is_open());
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate chrono;
use std::io::Read;
use std::fs;
use std::path::Path;
use byteorder::{ByteOrder, BigEndian, LittleEndian, ReadBytesExt};
use std::collections::HashMap;
use chrono::*;
use super::fit_header::FitHeader;
use super::global_message_table::GlobalMessage;
use super::file_id_message::FileIdMessage;
use super::field_definition::FieldDefinition;

pub struct Decoder {
    file_name: String,
    fit_buf: Vec<u8>,
    header: FitHeader,
    global_mesage_table: GlobalMessage,
    file_id_table: FileIdMessage,
}

impl Decoder {
    pub fn new(file_name: String) -> Decoder {
        return Decoder {
            file_name: file_name,
            fit_buf: Vec::new(),
            header: FitHeader::default(),
            global_mesage_table: GlobalMessage::new(),
            file_id_table: FileIdMessage::new(),
        }
    }

    pub fn decode(&mut self) {
        self.fit_buf = ::read_bin(&self.file_name);

        /*for w in &self.fit_buf {
            println!("{}", w);
        }
        */
        self.decode_header();
        self.decode_records();
    }

    fn decode_header(&mut self) {
        let header = self.read_header();

        let header_size = header[0];

        let protocol_version = header[1];

        let protocol_profile_major = header[2];

        let protocol_profile_minor = header[3];

        let full_profile_version: u16 = (header[3] as u16) << 8 | (header[2] as u16);

        let record_size_in_bytes: u32 = (header[7] as u32) << 24 |
            (header[6] as u32) << 16 |
            (header[5] as u32) << 8 |
            (header[4] as u32);

        let mut fit_str = String::new();
        fit_str.push(header[8] as char);
        fit_str.push(header[9] as char);
        fit_str.push(header[10] as char);
        fit_str.push(header[11] as char);

        let crc: u16 = (header[13] as u16) << 8 | (header[12] as u16);

       self.header.size = header_size;
       self.header.protocol_version = protocol_version;
       self.header.profile_version = full_profile_version;
       self.header.fit_str = fit_str;
       self.header.data_size = record_size_in_bytes;
       self.header.crc = crc;

       println!("{:?}", self.header);
    }

    fn read_header(&self) -> Vec<u8> {
        let word0 = self.fit_buf[0];
        let word1 = self.fit_buf[1];

        let headerVec: Vec<u8> = self.fit_buf.iter().take(14).map(|b| *b).collect();

        return headerVec;
    }

    fn decode_records(&self) {
        let record_header = self.fit_buf[14];
        println!("{:#b}", record_header);
        let arch = self.fit_buf[16];
        println!("{:#b}", arch);

        let global_message_number: u16 = (self.fit_buf[18] as u16) << 8 | (self.fit_buf[17] as u16);
        println!("Global Message Number: {}", global_message_number);

        let global_message = self.global_mesage_table.get(global_message_number);
        println!("Global Message: {}", global_message);

        let num_fields = self.fit_buf[19];
        println!("Number of Fields: {}", num_fields);

        let index: usize = 20;
        let fields: usize = num_fields as usize;
        let mut pos = index;
        for f in 0..fields {
            let current_index: usize = index + (3 * f);
            let field_def_num = self.fit_buf[current_index];
            let size = self.fit_buf[current_index + 1];
            let base_type = self.fit_buf[current_index + 2];

            let field_kind = self.file_id_table.get(field_def_num);

            println!("{}: {}  {}  {}", field_kind, field_def_num, size, base_type);
            pos += 3;
        }

        //TODO: Handle pos better
        let data_header = self.fit_buf[pos];
        pos += 1;
        println!("{:#b}", data_header);

        let serial_number = LittleEndian::read_u32(&self.fit_buf[pos..]);
        println!("Serial Number: {}", serial_number);
        pos += 4;

        let time_created = LittleEndian::read_u32(&self.fit_buf[pos..]);
        println!("Time Created: {}", time_created);

        let d = UTC.ymd(1989, 12, 31);
        let sum = d + Duration::seconds(time_created as i64);
        println!("Date: {}", sum);
        pos += 4;

        let manufacturer = LittleEndian::read_u16(&self.fit_buf[pos..]);
        println!("Manf: {}", manufacturer);
        pos += 2;

        let product = LittleEndian::read_u16(&self.fit_buf[pos..]);
        println!("Product: {}", product);
        pos += 2;

        let t = self.fit_buf[pos];
        println!("Type: {}", t);
    }
}

/*fn read_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut file = fs::File::open(path).unwrap();
    let mut file_buf = Vec::new();
    file.read_to_end(&mut file_buf).unwrap();
    file_buf
}
*/
<commit_msg>Adding read methods<commit_after>extern crate byteorder;
extern crate chrono;
use std::io::Read;
use std::fs;
use std::path::Path;
use byteorder::{ByteOrder, BigEndian, LittleEndian, ReadBytesExt};
use std::collections::HashMap;
use chrono::*;
use super::fit_header::FitHeader;
use super::global_message_table::GlobalMessage;
use super::file_id_message::FileIdMessage;
use super::field_definition::FieldDefinition;

pub struct Decoder {
    pub file_name: String,
    pub fit_buf: Vec<u8>,
    pub header: FitHeader,
    pub global_mesage_table: GlobalMessage,
    pub file_id_table: FileIdMessage,
    read_pos: u64,
}

impl Decoder {
    pub fn new(file_name: String) -> Decoder {
        return Decoder {
            file_name: file_name,
            fit_buf: Vec::new(),
            header: FitHeader::default(),
            global_mesage_table: GlobalMessage::new(),
            file_id_table: FileIdMessage::new(),
            read_pos: 0,
        }
    }

    pub fn decode(&mut self) {
        self.fit_buf = ::read_bin(&self.file_name);

        self.decode_header();
        self.decode_records();
    }

    fn decode_header(&mut self) {
        let header = self.read_header();

        let header_size = header[0];

        let protocol_version = header[1];

        let protocol_profile_major = header[2];

        let protocol_profile_minor = header[3];

        let full_profile_version: u16 = (header[3] as u16) << 8 | (header[2] as u16);

        let record_size_in_bytes: u32 = (header[7] as u32) << 24 |
            (header[6] as u32) << 16 |
            (header[5] as u32) << 8 |
            (header[4] as u32);

        let mut fit_str = String::new();
        fit_str.push(header[8] as char);
        fit_str.push(header[9] as char);
        fit_str.push(header[10] as char);
        fit_str.push(header[11] as char);

        let crc: u16 = (header[13] as u16) << 8 | (header[12] as u16);

       self.header.size = header_size;
       self.header.protocol_version = protocol_version;
       self.header.profile_version = full_profile_version;
       self.header.fit_str = fit_str;
       self.header.data_size = record_size_in_bytes;
       self.header.crc = crc;

       println!("{:?}", self.header);
    }

    fn read_header(&self) -> Vec<u8> {
        let word0 = self.fit_buf[0];
        let word1 = self.fit_buf[1];

        let headerVec: Vec<u8> = self.fit_buf.iter().take(14).map(|b| *b).collect();

        return headerVec;
    }

    fn decode_records(&self) {
        let record_header = self.fit_buf[14];
        println!("{:#b}", record_header);
        let arch = self.fit_buf[16];
        println!("{:#b}", arch);

        let global_message_number: u16 = (self.fit_buf[18] as u16) << 8 | (self.fit_buf[17] as u16);
        println!("Global Message Number: {}", global_message_number);

        let global_message = self.global_mesage_table.get(global_message_number);
        println!("Global Message: {}", global_message);

        let num_fields = self.fit_buf[19];
        println!("Number of Fields: {}", num_fields);

        let index: usize = 20;
        let fields: usize = num_fields as usize;
        let mut pos = index;
        for f in 0..fields {
            let current_index: usize = index + (3 * f);
            let field_def_num = self.fit_buf[current_index];
            let size = self.fit_buf[current_index + 1];
            let base_type = self.fit_buf[current_index + 2];

            let field_kind = self.file_id_table.get(field_def_num);

            println!("{}: {}  {}  {}", field_kind, field_def_num, size, base_type);
            pos += 3;
        }

        //TODO: Handle pos better
        let data_header = self.fit_buf[pos];
        pos += 1;
        println!("{:#b}", data_header);

        let serial_number = LittleEndian::read_u32(&self.fit_buf[pos..]);
        println!("Serial Number: {}", serial_number);
        pos += 4;

        let time_created = LittleEndian::read_u32(&self.fit_buf[pos..]);
        println!("Time Created: {}", time_created);

        let d = UTC.ymd(1989, 12, 31);
        let sum = d + Duration::seconds(time_created as i64);
        println!("Date: {}", sum);
        pos += 4;

        let manufacturer = LittleEndian::read_u16(&self.fit_buf[pos..]);
        println!("Manf: {}", manufacturer);
        pos += 2;

        let product = LittleEndian::read_u16(&self.fit_buf[pos..]);
        println!("Product: {}", product);
        pos += 2;

        let t = self.fit_buf[pos];
        println!("Type: {}", t);
    }

    fn read_u8(&mut self) -> u8 {
        let byte = self.fit_buf[self.read_pos as usize];
        self.read_pos += 1;
        byte
    }

    fn read_byte(&mut self) -> u8{
        let byte = self.fit_buf[self.read_pos as usize];
        self.read_pos += 1;
        byte
    }

    fn read_bytes(&mut self, amount: u32) -> Vec<u8> {
        let mut result = Vec::new();
        for _ in 0..amount {
            let read0 = self.fit_buf[self.read_pos as usize];
            result.push(read0);
            self.read_pos += 1;
        }

        result
    }
}

/*fn read_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut file = fs::File::open(path).unwrap();
    let mut file_buf = Vec::new();
    file.read_to_end(&mut file_buf).unwrap();
    file_buf
}
*/
<|endoftext|>


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

#![crate_name = "gfx"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#[phase(plugin, link)] extern crate log;
extern crate libc;

extern crate device;
extern crate render;

// public re-exports
pub use render::{DeviceHelper, Renderer};
pub use render::batch;
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::{Slice, ToSlice};
pub use render::mesh::SliceKind;
pub use render::mesh::SliceKind::Vertex as VertexSlice;
pub use render::mesh::SliceKind::Index8 as IndexSlice8;
pub use render::mesh::SliceKind::Index16 as IndexSlice16;
pub use render::mesh::SliceKind::Index32 as IndexSlice32;
pub use render::state::{BlendPreset, DrawState};
pub use render::state::BlendPreset::Additive as BlendAdditive;
pub use render::state::BlendPreset::Alpha as BlendAlpha;
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use render::target::Plane::Surface as PlaneSurface;
pub use render::target::Plane::Texture as PlaneTexture;
pub use device::Device;
pub use device::{attrib, state, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle};
pub use device::BufferUsage;
pub use device::BufferUsage::Static as UsageStatic;
pub use device::BufferUsage::Dynamic as UsageDynamic;
pub use device::BufferUsage::Stream as UsageStream;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::UniformValue;
pub use device::shade::UniformValue::I32 as ValueI32;
pub use device::shade::UniformValue::F32 as ValueF32;
pub use device::shade::UniformValue::I32Vector2 as ValueI32Vector2;
pub use device::shade::UniformValue::I32Vector3 as ValueI32Vector3;
pub use device::shade::UniformValue::I32Vector4 as ValueI32Vector4;
pub use device::shade::UniformValue::F32Vector2 as ValueF32Vector2;
pub use device::shade::UniformValue::F32Vector3 as ValueF32Vector3;
pub use device::shade::UniformValue::F32Vector4 as ValueF32Vector4;
pub use device::shade::UniformValue::F32Matrix2 as ValueF32Matrix2;
pub use device::shade::UniformValue::F32Matrix3 as ValueF32Matrix3;
pub use device::shade::UniformValue::F32Matrix4 as ValueF32Matrix4;
pub use device::shade::{ShaderSource, ProgramInfo};
pub use device::target::{ColorValue, ClearData, Mask, Layer, Level, Rect, Target};
pub use device::target::{COLOR, DEPTH, STENCIL};

// TODO: Remove this re-export once `gl_device` becomes a separate crate.
pub use device::gl_device::{GlDevice, GlCommandBuffer};

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D, C: device::draw::CommandBuffer> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<C>,
    /// Hidden batch context.
    context: batch::Context,
}

impl<D: device::Device<C>, C: device::draw::CommandBuffer> Graphics<D, C> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D, C> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Create a new ref batch.
    pub fn make_batch<L, T: shade::ShaderParam<L>>(&mut self,
                      program: &ProgramHandle,
                      mesh: &Mesh,
                      slice: Slice,
                      state: &DrawState)
                      -> Result<batch::RefBatch<L, T>, batch::BatchError> {
        self.context.make_batch(program, mesh, slice, state)
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a ref batch.
    pub fn draw<'a, L, T: shade::ShaderParam<L>>(&'a mut self,
        batch: &'a batch::RefBatch<L, T>, data: &'a T, frame: &Frame) {
        self.renderer.draw((batch, data, &self.context), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<commit_msg>Remove variant re-exports<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![crate_name = "gfx"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

#[phase(plugin, link)] extern crate log;
extern crate libc;

extern crate device;
extern crate render;

// public re-exports
pub use render::{DeviceHelper, Renderer};
pub use render::batch;
pub use render::mesh::{Attribute, Mesh, VertexFormat};
pub use render::mesh::{Slice, ToSlice};
pub use render::mesh::SliceKind;
pub use render::state::{BlendPreset, DrawState};
pub use render::shade;
pub use render::target::{Frame, Plane};
pub use device::Device;
pub use device::{attrib, state, tex};
pub use device::as_byte_slice;
pub use device::{BufferHandle, BufferInfo, RawBufferHandle, ShaderHandle};
pub use device::{ProgramHandle, SurfaceHandle, TextureHandle};
pub use device::BufferUsage;
pub use device::{VertexCount, InstanceCount};
pub use device::PrimitiveType;
pub use device::draw::CommandBuffer;
pub use device::shade::UniformValue;
pub use device::shade::{ShaderSource, ProgramInfo};
pub use device::target::{ColorValue, ClearData, Mask, Layer, Level, Rect, Target};
pub use device::target::{COLOR, DEPTH, STENCIL};

// TODO: Remove this re-export once `gl_device` becomes a separate crate.
pub use device::gl_device::{GlDevice, GlCommandBuffer};

/// A convenient wrapper suitable for single-threaded operation.
pub struct Graphics<D, C: device::draw::CommandBuffer> {
    /// Graphics device.
    pub device: D,
    /// Renderer front-end.
    pub renderer: Renderer<C>,
    /// Hidden batch context.
    context: batch::Context,
}

impl<D: device::Device<C>, C: device::draw::CommandBuffer> Graphics<D, C> {
    /// Create a new graphics wrapper.
    pub fn new(mut device: D) -> Graphics<D, C> {
        let rend = device.create_renderer();
        Graphics {
            device: device,
            renderer: rend,
            context: batch::Context::new(),
        }
    }

    /// Create a new ref batch.
    pub fn make_batch<L, T: shade::ShaderParam<L>>(&mut self,
                      program: &ProgramHandle,
                      mesh: &Mesh,
                      slice: Slice,
                      state: &DrawState)
                      -> Result<batch::RefBatch<L, T>, batch::BatchError> {
        self.context.make_batch(program, mesh, slice, state)
    }

    /// Clear the `Frame` as the `ClearData` specifies.
    pub fn clear(&mut self, data: ClearData, mask: Mask, frame: &Frame) {
        self.renderer.clear(data, mask, frame)
    }

    /// Draw a ref batch.
    pub fn draw<'a, L, T: shade::ShaderParam<L>>(&'a mut self,
        batch: &'a batch::RefBatch<L, T>, data: &'a T, frame: &Frame) {
        self.renderer.draw((batch, data, &self.context), frame)
    }

    /// Submit the internal command buffer and reset for the next frame.
    pub fn end_frame(&mut self) {
        self.device.submit(self.renderer.as_buffer());
        self.renderer.reset();
    }
}
<|endoftext|>


<commit_before>pub fn bit_length(number: u32) -> u8 {
    32 - number.leading_zeros() as u8
}

pub fn bite_mask(mask: u8) -> u32 {
    debug_assert!(mask <= 32);
    match mask {
        0 => 0,
        n => (!0 << (32 - n)),
    }
}

pub fn bite_mask_u128(mask: u8) -> u128 {
    debug_assert!(mask <= 128);
    match mask {
        0 => 0,
        n => (!0 << (128 - n)),
    }
}

pub fn split_ip_netmask(input: &str) -> Option<(&str, &str)> {
    let delimiter = match input.find('/') {
        Some(pos) => pos,
        None => return None,
    };
    let (ip, mask) = input.split_at(delimiter);
    let mask = &mask[1..];

    if ip.is_empty() || mask.is_empty() {
        None
    } else {
        Some((ip, mask))
    }
}

#[cfg(test)]
mod tests {
    use super::{bite_mask, bite_mask_u128, split_ip_netmask};

    #[test]
    fn get_bite_mask_32() {
        assert_eq!(u32::max_value(), bite_mask(32));
    }

    #[test]
    fn get_bite_mask_0() {
        assert_eq!(0, bite_mask(0));
    }

    #[test]
    fn get_bite_mask_u128_0() {
        assert_eq!(0, bite_mask_u128(0));
    }

    #[test]
    fn get_bite_mask_u128_128() {
        assert_eq!(u128::max_value(), bite_mask_u128(128));
    }

    #[test]
    fn split_ip_netmask_normal() {
        let (ip, netmask) = split_ip_netmask("192.168.1.1/24").unwrap();
        assert_eq!("192.168.1.1", ip);
        assert_eq!("24", netmask);
    }

    #[test]
    fn split_ip_netmask_invalid_1() {
        let a = split_ip_netmask("ab");
        assert!(a.is_none());
    }

    #[test]
    fn split_ip_netmask_invalid_2() {
        let a = split_ip_netmask("/");
        assert!(a.is_none());
    }

    #[test]
    fn split_ip_netmask_invalid_3() {
        let a = split_ip_netmask("192.168.1.1/");
        assert!(a.is_none());
    }
}
<commit_msg>Code style<commit_after>pub fn bit_length(number: u32) -> u8 {
    32 - number.leading_zeros() as u8
}

pub fn bite_mask(mask: u8) -> u32 {
    debug_assert!(mask <= 32);
    match mask {
        0 => 0,
        n => !0 << (32 - n),
    }
}

pub fn bite_mask_u128(mask: u8) -> u128 {
    debug_assert!(mask <= 128);
    match mask {
        0 => 0,
        n => !0 << (128 - n),
    }
}

pub fn split_ip_netmask(input: &str) -> Option<(&str, &str)> {
    let delimiter = match input.find('/') {
        Some(pos) => pos,
        None => return None,
    };
    let (ip, mask) = input.split_at(delimiter);
    let mask = &mask[1..];

    if ip.is_empty() || mask.is_empty() {
        None
    } else {
        Some((ip, mask))
    }
}

#[cfg(test)]
mod tests {
    use super::{bite_mask, bite_mask_u128, split_ip_netmask};

    #[test]
    fn get_bite_mask_32() {
        assert_eq!(u32::MAX, bite_mask(32));
    }

    #[test]
    fn get_bite_mask_0() {
        assert_eq!(0, bite_mask(0));
    }

    #[test]
    fn get_bite_mask_u128_0() {
        assert_eq!(0, bite_mask_u128(0));
    }

    #[test]
    fn get_bite_mask_u128_128() {
        assert_eq!(u128::MAX, bite_mask_u128(128));
    }

    #[test]
    fn split_ip_netmask_normal() {
        let (ip, netmask) = split_ip_netmask("192.168.1.1/24").unwrap();
        assert_eq!("192.168.1.1", ip);
        assert_eq!("24", netmask);
    }

    #[test]
    fn split_ip_netmask_invalid_1() {
        let a = split_ip_netmask("ab");
        assert!(a.is_none());
    }

    #[test]
    fn split_ip_netmask_invalid_2() {
        let a = split_ip_netmask("/");
        assert!(a.is_none());
    }

    #[test]
    fn split_ip_netmask_invalid_3() {
        let a = split_ip_netmask("192.168.1.1/");
        assert!(a.is_none());
    }
}
<|endoftext|>