<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! A virtual PA-RoT that can be spoken to over local TCP.

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::io::BufRead as _;
use std::io::BufReader;
use std::process::Child;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::time::Duration;
use std::time::Instant;

use manticore::cert;
use manticore::cert::CertFormat;
use manticore::crypto::ring;
use manticore::mem::Arena;
use manticore::mem::BumpArena;
use manticore::protocol;
use manticore::protocol::capabilities;
use manticore::protocol::device_id::DeviceIdentifier;
use manticore::server;
use manticore::server::pa_rot::PaRot;

use crate::tcp;
use crate::tcp::TcpHostPort;

/// Options for the PA-RoT.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct Options {
    /// A firmware version blob to report to clients.
    pub firmware_version: Vec<u8>,

    /// A unique device identity blob to report to clients.
    pub unique_device_identity: Vec<u8>,

    /// The number of resets to report since power on.
    pub resets_since_power_on: u32,

    /// The maximum message size to report as a capability
    /// (unused by the transport).
    pub max_message_size: u16,
    /// The maximum packet size to report as a capability
    /// (unused by the transport).
    pub max_packet_size: u16,

    /// The timeout to report for a non-cryptographic operation
    /// (unused other than for capabilities requests).
    pub regular_timeout: Duration,
    /// The timeout to report for a cryptographic operation.
    /// (unused other than for capabilities requests)
    pub crypto_timeout: Duration,

    /// The device identifier to report to the client.
    pub device_id: DeviceIdentifier,

    /// The initial certificate chain to provision to the device.
    pub cert_chain: Vec<Vec<u8>>,

    /// The certificate format to parse the cert chain with.
    pub cert_format: CertFormat,

    /// The keypair to use with the certificate chain.
    pub alias_keypair: Option<KeyPairFormat>,

    /// The contents of PMR #0.
    pub pmr0: Vec<u8>,
}

/// See [`Options::alias_keypair`].
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub enum KeyPairFormat {
    /// An RSA PKCS#8-encoded key pair.
    RsaPkcs8(Vec<u8>),
}

impl Default for Options {
    fn default() -> Self {
        Self {
            firmware_version: b"<version unspecified>".to_vec(),
            unique_device_identity: b"<uid unspecified>".to_vec(),
            resets_since_power_on: 5,
            max_message_size: 1024,
            max_packet_size: 256,
            regular_timeout: Duration::from_millis(30),
            crypto_timeout: Duration::from_millis(200),
            device_id: DeviceIdentifier {
                vendor_id: 1,
                device_id: 2,
                subsys_vendor_id: 3,
                subsys_id: 4,
            },
            cert_chain: vec![],
            cert_format: CertFormat::RiotX509,
            alias_keypair: None,
            pmr0: b"<pmr0 unspecified>".to_vec(),
        }
    }
}

/// A virtual PA-RoT, implemented as a subprocess speaking TCP.
pub struct Virtual {
    child: Child,
    port: u16,
}

impl Drop for Virtual {
    fn drop(&mut self) {
        self.child.kill().unwrap();
    }
}

impl Virtual {
    /// Extracts the name of the binary-under-test from the environment.
    ///
    /// If missing, aborts the process. This will bypass the Rust test harness's
    /// attempt to continue running other tests.
    pub fn target_binary() -> &'static OsStr {
        const TARGET_BINARY: &str = "MANTICORE_E2E_TARGET_BINARY";
        lazy_static::lazy_static! {
            static ref BINARY_PATH: OsString = match env::var_os(TARGET_BINARY) {
                Some(bin) => bin,
                None => {
                    // In order to blow up the test binary, we need to call
                    // abort ourselves. Not only that, but we need to be clever
                    // to defeat the standard library's test output capture...
                    use std::os::unix::io::FromRawFd;
                    use std::io::Write;
                    use std::fs::File;
                    use std::process;

                    #[allow(unsafe_code)]
                    let mut stderr = unsafe { File::from_raw_fd(2) };
                    let _ = writeln!(
                        stderr,
                        "Could not find environment variable {}; aborting.",
                        TARGET_BINARY
                    );
                    let _ = writeln!(
                        stderr,
                        "Consider using the e2e/run.sh script, instead."
                    );
                    process::abort();
                }
            };
        }
        &BINARY_PATH
    }

    /// Spawns a virtual PA-RoT subprocess as described by `opts`.
    pub fn spawn(opts: &Options) -> Virtual {
        log::info!("spawning server: {:#?}", opts);
        let opts = serde_json::to_string(opts).unwrap();
        let mut child = Command::new(Self::target_binary())
            .args(&["--start-pa-rot-with-options", &opts])
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .expect("failed to spawn server subprocess");

        // Forward stderr through the eprint! macro, so that tests can capture
        // it.
        let mut stderr = BufReader::new(child.stderr.take().unwrap());
        let mut line = String::new();
        let _ = std::thread::spawn(move || loop {
            line.clear();
            match stderr.read_line(&mut line) {
                Ok(_) => eprint!("{}", line),
                Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => break,
                Err(e) => panic!("unexpected error from virtual rot: {}", e),
            }
        });

        // Wait until the child signals it's ready by writing a line to stdout.
        let mut stdout = BufReader::new(child.stdout.take().unwrap());
        let mut line = String::new();
        loop {
            line.clear();
            stdout.read_line(&mut line).unwrap();
            if line.is_empty() {
                continue;
            }

            if let Some(port) = line.trim().strip_prefix("listening@") {
                log::info!("acked child startup: {}", line);
                return Virtual {
                    child,
                    port: port.parse().unwrap(),
                };
            }
        }
    }
    /// Sends `req` to this virtal RoT, using Cerberus-over-TCP.
    ///
    /// Blocks until a response comes back.
    pub fn send_local<'a, Cmd, A>(
        &self,
        req: Cmd::Req,
        arena: &'a A,
    ) -> Result<Result<Cmd::Resp, protocol::Error>, server::Error>
    where
        Cmd: protocol::Command<'a>,
        A: Arena,
    {
        tcp::send_local::<Cmd, A>(self.port, req, arena)
    }
}

/// Starts a server loop for serving PA-RoT requests, as described by `opts`.
pub fn serve(opts: Options) -> ! {
    log::info!("configuring server...");
    let networking = capabilities::Networking {
        max_message_size: opts.max_message_size,
        max_packet_size: opts.max_packet_size,
        mode: capabilities::RotMode::Platform,
        roles: capabilities::BusRole::HOST,
    };

    let timeouts = capabilities::Timeouts {
        regular: opts.regular_timeout,
        crypto: opts.crypto_timeout,
    };

    struct Id {
        firmware_version: [u8; 32],
        unique_device_identity: Vec<u8>,
    }
    impl manticore::hardware::Identity for Id {
        fn firmware_version(&self) -> &[u8; 32] {
            &self.firmware_version
        }
        fn unique_device_identity(&self) -> &[u8] {
            &self.unique_device_identity[..]
        }
    }
    let mut identity = Id {
        firmware_version: [0; 32],
        unique_device_identity: opts.unique_device_identity,
    };
    let prefix_len = opts.firmware_version.len().min(32);

    identity.firmware_version[..prefix_len]
        .copy_from_slice(&opts.firmware_version[..prefix_len]);

    struct Reset {
        startup_time: Instant,
        resets_since_power_on: u32,
    }
    impl manticore::hardware::Reset for Reset {
        fn resets_since_power_on(&self) -> u32 {
            self.resets_since_power_on
        }

        fn uptime(&self) -> Duration {
            self.startup_time.elapsed()
        }
    }
    let reset = Reset {
        startup_time: Instant::now(),
        resets_since_power_on: opts.resets_since_power_on,
    };

    let sha = ring::sha256::Builder::new();
    let mut ciphers = ring::sig::Ciphers::new();
    let trust_chain_bytes =
        opts.cert_chain.iter().map(Vec::as_ref).collect::<Vec<_>>();
    let mut signer = opts.alias_keypair.as_ref().map(|kp| match kp {
        KeyPairFormat::RsaPkcs8(pk8) => {
            use manticore::crypto::rsa::*;
            let kp = ring::rsa::KeyPair::from_pkcs8(pk8).unwrap();
            let builder = ring::rsa::Builder::new();
            builder.new_signer(kp).unwrap()
        }
    });
    let mut trust_chain = cert::SimpleChain::<8>::parse(
        &trust_chain_bytes,
        opts.cert_format,
        &mut ciphers,
        signer.as_mut().map(|s| s as _),
    )
    .unwrap();

    let mut server = PaRot::new(manticore::server::pa_rot::Options {
        identity: &identity,
        reset: &reset,
        sha: &sha,
        ciphers: &mut ciphers,
        trust_chain: &mut trust_chain,
        pmr0: &opts.pmr0,
        device_id: opts.device_id,
        networking,
        timeouts,
    });

    let mut host = match TcpHostPort::bind() {
        Ok(host) => host,
        Err(e) => {
            log::error!("could not connect to host: {:?}", e);
            std::process::exit(1);
        }
    };
    let port = host.port();
    log::info!("bound to port {}", port);

    // Notify parent that we're listening.
    println!("listening@{}", port);

    let mut arena = BumpArena::new(vec![0; 1024]);

    log::info!("entering server loop");
    loop {
        if let Err(e) = server.process_request(&mut host, &arena) {
            log::error!("failed to process request: {:?}", e);
        }
        arena.reset();
    }
}
<commit_msg>[e2e] Simplify the cannot-find-test-binary error<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! A virtual PA-RoT that can be spoken to over local TCP.

use std::env;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::io::BufRead as _;
use std::io::BufReader;
use std::process::Child;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::time::Duration;
use std::time::Instant;

use manticore::cert;
use manticore::cert::CertFormat;
use manticore::crypto::ring;
use manticore::mem::Arena;
use manticore::mem::BumpArena;
use manticore::protocol;
use manticore::protocol::capabilities;
use manticore::protocol::device_id::DeviceIdentifier;
use manticore::server;
use manticore::server::pa_rot::PaRot;

use crate::tcp;
use crate::tcp::TcpHostPort;

/// Options for the PA-RoT.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct Options {
    /// A firmware version blob to report to clients.
    pub firmware_version: Vec<u8>,

    /// A unique device identity blob to report to clients.
    pub unique_device_identity: Vec<u8>,

    /// The number of resets to report since power on.
    pub resets_since_power_on: u32,

    /// The maximum message size to report as a capability
    /// (unused by the transport).
    pub max_message_size: u16,
    /// The maximum packet size to report as a capability
    /// (unused by the transport).
    pub max_packet_size: u16,

    /// The timeout to report for a non-cryptographic operation
    /// (unused other than for capabilities requests).
    pub regular_timeout: Duration,
    /// The timeout to report for a cryptographic operation.
    /// (unused other than for capabilities requests)
    pub crypto_timeout: Duration,

    /// The device identifier to report to the client.
    pub device_id: DeviceIdentifier,

    /// The initial certificate chain to provision to the device.
    pub cert_chain: Vec<Vec<u8>>,

    /// The certificate format to parse the cert chain with.
    pub cert_format: CertFormat,

    /// The keypair to use with the certificate chain.
    pub alias_keypair: Option<KeyPairFormat>,

    /// The contents of PMR #0.
    pub pmr0: Vec<u8>,
}

/// See [`Options::alias_keypair`].
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub enum KeyPairFormat {
    /// An RSA PKCS#8-encoded key pair.
    RsaPkcs8(Vec<u8>),
}

impl Default for Options {
    fn default() -> Self {
        Self {
            firmware_version: b"<version unspecified>".to_vec(),
            unique_device_identity: b"<uid unspecified>".to_vec(),
            resets_since_power_on: 5,
            max_message_size: 1024,
            max_packet_size: 256,
            regular_timeout: Duration::from_millis(30),
            crypto_timeout: Duration::from_millis(200),
            device_id: DeviceIdentifier {
                vendor_id: 1,
                device_id: 2,
                subsys_vendor_id: 3,
                subsys_id: 4,
            },
            cert_chain: vec![],
            cert_format: CertFormat::RiotX509,
            alias_keypair: None,
            pmr0: b"<pmr0 unspecified>".to_vec(),
        }
    }
}

/// A virtual PA-RoT, implemented as a subprocess speaking TCP.
pub struct Virtual {
    child: Child,
    port: u16,
}

impl Drop for Virtual {
    fn drop(&mut self) {
        self.child.kill().unwrap();
    }
}

impl Virtual {
    /// Extracts the name of the binary-under-test from the environment.
    ///
    /// If missing, aborts the process. This will bypass the Rust test harness's
    /// attempt to continue running other tests.
    pub fn target_binary() -> &'static OsStr {
        const TARGET_BINARY: &str = "MANTICORE_E2E_TARGET_BINARY";
        lazy_static::lazy_static! {
            static ref BINARY_PATH: OsString = match env::var_os(TARGET_BINARY) {
                Some(bin) => bin,
                None => {
                    use std::io;
                    use std::io::Write;
                    use std::process;

                    let _ = writeln!(
                        io::stderr(),
                        "Could not find environment variable {}; aborting.",
                        TARGET_BINARY
                    );
                    let _ = writeln!(
                        io::stderr(),
                        "Consider using the e2e/run.sh script, instead."
                    );

                    process::exit(255);
                }
            };
        }
        &BINARY_PATH
    }

    /// Spawns a virtual PA-RoT subprocess as described by `opts`.
    pub fn spawn(opts: &Options) -> Virtual {
        log::info!("spawning server: {:#?}", opts);
        let opts = serde_json::to_string(opts).unwrap();
        let mut child = Command::new(Self::target_binary())
            .args(&["--start-pa-rot-with-options", &opts])
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .expect("failed to spawn server subprocess");

        // Forward stderr through the eprint! macro, so that tests can capture
        // it.
        let mut stderr = BufReader::new(child.stderr.take().unwrap());
        let mut line = String::new();
        let _ = std::thread::spawn(move || loop {
            line.clear();
            match stderr.read_line(&mut line) {
                Ok(_) => eprint!("{}", line),
                Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => break,
                Err(e) => panic!("unexpected error from virtual rot: {}", e),
            }
        });

        // Wait until the child signals it's ready by writing a line to stdout.
        let mut stdout = BufReader::new(child.stdout.take().unwrap());
        let mut line = String::new();
        loop {
            line.clear();
            stdout.read_line(&mut line).unwrap();
            if line.is_empty() {
                continue;
            }

            if let Some(port) = line.trim().strip_prefix("listening@") {
                log::info!("acked child startup: {}", line);
                return Virtual {
                    child,
                    port: port.parse().unwrap(),
                };
            }
        }
    }
    /// Sends `req` to this virtal RoT, using Cerberus-over-TCP.
    ///
    /// Blocks until a response comes back.
    pub fn send_local<'a, Cmd, A>(
        &self,
        req: Cmd::Req,
        arena: &'a A,
    ) -> Result<Result<Cmd::Resp, protocol::Error>, server::Error>
    where
        Cmd: protocol::Command<'a>,
        A: Arena,
    {
        tcp::send_local::<Cmd, A>(self.port, req, arena)
    }
}

/// Starts a server loop for serving PA-RoT requests, as described by `opts`.
pub fn serve(opts: Options) -> ! {
    log::info!("configuring server...");
    let networking = capabilities::Networking {
        max_message_size: opts.max_message_size,
        max_packet_size: opts.max_packet_size,
        mode: capabilities::RotMode::Platform,
        roles: capabilities::BusRole::HOST,
    };

    let timeouts = capabilities::Timeouts {
        regular: opts.regular_timeout,
        crypto: opts.crypto_timeout,
    };

    struct Id {
        firmware_version: [u8; 32],
        unique_device_identity: Vec<u8>,
    }
    impl manticore::hardware::Identity for Id {
        fn firmware_version(&self) -> &[u8; 32] {
            &self.firmware_version
        }
        fn unique_device_identity(&self) -> &[u8] {
            &self.unique_device_identity[..]
        }
    }
    let mut identity = Id {
        firmware_version: [0; 32],
        unique_device_identity: opts.unique_device_identity,
    };
    let prefix_len = opts.firmware_version.len().min(32);

    identity.firmware_version[..prefix_len]
        .copy_from_slice(&opts.firmware_version[..prefix_len]);

    struct Reset {
        startup_time: Instant,
        resets_since_power_on: u32,
    }
    impl manticore::hardware::Reset for Reset {
        fn resets_since_power_on(&self) -> u32 {
            self.resets_since_power_on
        }

        fn uptime(&self) -> Duration {
            self.startup_time.elapsed()
        }
    }
    let reset = Reset {
        startup_time: Instant::now(),
        resets_since_power_on: opts.resets_since_power_on,
    };

    let sha = ring::sha256::Builder::new();
    let mut ciphers = ring::sig::Ciphers::new();
    let trust_chain_bytes =
        opts.cert_chain.iter().map(Vec::as_ref).collect::<Vec<_>>();
    let mut signer = opts.alias_keypair.as_ref().map(|kp| match kp {
        KeyPairFormat::RsaPkcs8(pk8) => {
            use manticore::crypto::rsa::*;
            let kp = ring::rsa::KeyPair::from_pkcs8(pk8).unwrap();
            let builder = ring::rsa::Builder::new();
            builder.new_signer(kp).unwrap()
        }
    });
    let mut trust_chain = cert::SimpleChain::<8>::parse(
        &trust_chain_bytes,
        opts.cert_format,
        &mut ciphers,
        signer.as_mut().map(|s| s as _),
    )
    .unwrap();

    let mut server = PaRot::new(manticore::server::pa_rot::Options {
        identity: &identity,
        reset: &reset,
        sha: &sha,
        ciphers: &mut ciphers,
        trust_chain: &mut trust_chain,
        pmr0: &opts.pmr0,
        device_id: opts.device_id,
        networking,
        timeouts,
    });

    let mut host = match TcpHostPort::bind() {
        Ok(host) => host,
        Err(e) => {
            log::error!("could not connect to host: {:?}", e);
            std::process::exit(1);
        }
    };
    let port = host.port();
    log::info!("bound to port {}", port);

    // Notify parent that we're listening.
    println!("listening@{}", port);

    let mut arena = BumpArena::new(vec![0; 1024]);

    log::info!("entering server loop");
    loop {
        if let Err(e) = server.process_request(&mut host, &arena) {
            log::error!("failed to process request: {:?}", e);
        }
        arena.reset();
    }
}
<|endoftext|>


<commit_before>extern crate google_maps_services;
extern crate dotenv;

use dotenv::dotenv;
use google_maps_services::structs::LatLng;
use google_maps_services::distance_matrix::lat_lng_request;
use google_maps_services::distance_matrix::address_request;
use std::env;

#[test]
fn lat_lng() {
    // Get API key from .env file
    dotenv().ok();
    let api_key = env::var("API_KEY").expect("API_KEY must be set in the .env file");

    // Melbourne CBD
    let origin = LatLng::new(-37.8274812, 144.9352466);

    // Ballarat CBD
    let destination = LatLng::new(-37.5674314, 143.7827008);

    let result = lat_lng_request(api_key, origin, destination);

    assert_eq!(result.destination_addresses.len(), 1);
}

#[test]
fn address() {
    dotenv().ok();
    let api_key = env::var("API_KEY").expect("API_KEY must be set in the .env file");

    let origin = "Melbourne GPO";
    let destination = "Ballarat CBD";

    let result = address_request(api_key, origin.to_string(), destination.to_string());

    assert_eq!(result.destination_addresses.len(), 1);
}
<commit_msg>Updated tests<commit_after>extern crate google_maps_services;
extern crate dotenv;

use dotenv::dotenv;
use google_maps_services::structs::LatLng;
use google_maps_services::distance_matrix::lat_lng_request;
use google_maps_services::distance_matrix::address_request;
use std::env;

#[test]
fn lat_lng() {
    // Get API key from .env file
    dotenv().ok();
    let api_key = env::var("API_KEY").expect("API_KEY must be set in the .env file");

    // Melbourne CBD
    let origin = LatLng::new(-37.8274812, 144.9352466);

    // Ballarat CBD
    let destination = LatLng::new(-37.5674314, 143.7827008);

    let result = lat_lng_request(api_key, origin, destination);

    assert_eq!(result.status, "OK");
}

#[test]
fn address() {
    dotenv().ok();
    let api_key = env::var("API_KEY").expect("API_KEY must be set in the .env file");

    let origin = "Melbourne GPO".to_string();
    let destination = "Ballarat CBD".to_string();

    let result = address_request(api_key, origin, destination);

    assert_eq!(result.status, "OK");
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

/// An enum for the package types.
pub enum PackageType {
    /// Stands for binary
    Bin,
    /// Stands for library
    Lib,
    /// Stands for source
    Src,

    // the comments are really obvious, haha
}

/// A struct made for storing the version of the packages.
///
/// The format follows [semver 2.0](http://semver.org/), meaning that:
///
/// - versions with different `major` indicates that they are incompatible.
/// - versions with different `minor` but same `major` are largely compatible.
/// - versions with different `patch` but same `major` and `minor` are
///   compatible.
///
/// The `additional` field is an optional field for the package host to put
/// text such as `alpha` or `stable`, it's not involved in the comparisons.
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

/// A struct for storing package informations, such as its name and version.
pub struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self == other
    }
}

impl Eq for Version {}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    /// This compares one `Version` with another. It only compares the
    /// three main parts of Version (`major`, `minor`, `patch`) and ignores
    /// `additional` as it is meant to let the package host to put additional
    /// messages such as `alpha`, `beta`.
    ///
    /// This functions compares the two `Version`s *absolutely*, meaning that
    /// it doesn't care about whether the two versions are breaking-changes or
    /// not - it just compares.
    fn cmp(&self, other: &Self) -> Ordering {
        if self.major > other.major { Ordering::Greater } else
        if self.major < other.major { Ordering::Less }
        else {
            if self.minor > other.minor { Ordering::Greater } else
            if self.minor < other.minor { Ordering::Less }
            else {
                if self.patch > other.patch { Ordering::Greater } else
                if self.patch < other.patch { Ordering::Less }
                else { Ordering::Equal }
            }
        }
    }
}

impl Version {
    /// Returns the major version X (X.y.z).
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the minor version Y (x.Y.z).
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the patch version Z (x.y.Z).
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the additional message added by package host or its developers.
    pub fn additional(&self) -> &Option<String> {
        &self.additional
    }

    /// A helper function for checking whether the two versions contains
    /// breaking changes.
    pub fn is_back_compatible(&self, other: &Self) -> bool {
        self.major == other.major
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name &&
        self.version == other.version
    }
}

impl Package {
    /// Returns the name of the package.
    fn name(&self) -> &str {
        &self.name
    }

    /// Returns the version of the package.
    fn version(&self) -> &Version {
        &self.version
    }

    /// Returns the hash of the package.
    fn hash(&self) -> u32 {
        self.hash
    }

    /// Returns the type of the package.
    fn package_type(&self) -> &PackageType {
        &self.package_type
    }
}<commit_msg>Adding the missing `pub`s<commit_after>use std::cmp::Ordering;

/// An enum for the package types.
pub enum PackageType {
    /// Stands for binary
    Bin,
    /// Stands for library
    Lib,
    /// Stands for source
    Src,

    // the comments are really obvious, haha
}

/// A struct made for storing the version of the packages.
///
/// The format follows [semver 2.0](http://semver.org/), meaning that:
///
/// - versions with different `major` indicates that they are incompatible.
/// - versions with different `minor` but same `major` are largely compatible.
/// - versions with different `patch` but same `major` and `minor` are
///   compatible.
///
/// The `additional` field is an optional field for the package host to put
/// text such as `alpha` or `stable`, it's not involved in the comparisons.
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

/// A struct for storing package informations, such as its name and version.
pub struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self == other
    }
}

impl Eq for Version {}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    /// This compares one `Version` with another. It only compares the
    /// three main parts of Version (`major`, `minor`, `patch`) and ignores
    /// `additional` as it is meant to let the package host to put additional
    /// messages such as `alpha`, `beta`.
    ///
    /// This functions compares the two `Version`s *absolutely*, meaning that
    /// it doesn't care about whether the two versions are breaking-changes or
    /// not - it just compares.
    fn cmp(&self, other: &Self) -> Ordering {
        if self.major > other.major { Ordering::Greater } else
        if self.major < other.major { Ordering::Less }
        else {
            if self.minor > other.minor { Ordering::Greater } else
            if self.minor < other.minor { Ordering::Less }
            else {
                if self.patch > other.patch { Ordering::Greater } else
                if self.patch < other.patch { Ordering::Less }
                else { Ordering::Equal }
            }
        }
    }
}

impl Version {
    /// Returns the major version X (X.y.z).
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the minor version Y (x.Y.z).
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the patch version Z (x.y.Z).
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the additional message added by package host or its developers.
    pub fn additional(&self) -> &Option<String> {
        &self.additional
    }

    /// A helper function for checking whether the two versions contains
    /// breaking changes.
    pub fn is_back_compatible(&self, other: &Self) -> bool {
        self.major == other.major
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name &&
        self.version == other.version
    }
}

impl Package {
    /// Returns the name of the package.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Returns the version of the package.
    pub fn version(&self) -> &Version {
        &self.version
    }

    /// Returns the hash of the package.
    pub fn hash(&self) -> u32 {
        self.hash
    }

    /// Returns the type of the package.
    pub fn package_type(&self) -> &PackageType {
        &self.package_type
    }
}<|endoftext|>


<commit_before>use num::bigint::ToBigUint;
use num::{BigUint, Zero, One};
use std::fmt;

pub use self::FromBase58Error::*;

static BTC_ALPHA: &'static[u8] = b"123456789\
                                   ABCDEFGHJKLMNPQRSTUVWXYZ\
                                   abcdefghijkmnopqrstuvwxyz";

static FLICKR_ALPHA: &'static[u8] = b"123456789\
                                      abcdefghijkmnopqrstuvwxyz\
                                      ABCDEFGHJKLMNPQRSTUVWXYZ";

/// A trait for converting base58-encoded values
// TODO: This should incorporate the alphabet used as an associated constant.
// However, associated constants are not implemented in Rust yet. There is a
// PR though: https://github.com/rust-lang/rust/pull/23606
pub trait FromBase58 {
    /// Converts the value of `self`, interpreted as base58 encoded data,
    /// into an owned vector of bytes, returning the vector.
    fn from_base58(&self) -> Result<Vec<u8>, FromBase58Error>;
}

/// Errors that can occur when decoding a base58-encoded string
#[derive(Clone, Copy)]
pub enum FromBase58Error {
    /// The input contained a character not part of the base58 alphabet
    InvalidBase58Byte(u8, usize),
}

impl fmt::Debug for FromBase58Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidBase58Byte(ch, idx) =>
                write!(f, "Invalid character '{}' at position {}", ch, idx),
        }
    }
}

impl fmt::Display for FromBase58Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self, f)
    }
}

impl FromBase58 for str {
    fn from_base58(&self) -> Result<Vec<u8>, FromBase58Error> {
        self.as_bytes().from_base58()
    }
}

impl FromBase58 for [u8] {
    // TODO: fix some of the below when the binary assignment operators +=, *=
    // are overloadable
    fn from_base58(&self) -> Result<Vec<u8>, FromBase58Error> {
        let radix = 58.to_biguint().unwrap();
        let mut x: BigUint = Zero::zero();
        let mut rad_mult: BigUint = One::one();

        // Convert the base58 string to a BigUint `x`
        for (idx, &byte) in self.iter().enumerate().rev() {
            let first_idx = BTC_ALPHA.iter()
                                     .enumerate()
                                     .find(|x| *x.1 == byte)
                                     .map(|x| x.0);
            match first_idx {
                Some(i) => { x = x + i.to_biguint().unwrap() * &rad_mult; },
                None => return Err(InvalidBase58Byte(self[idx], idx))
            }

            rad_mult = &rad_mult * &radix;
        }

        let mut r = Vec::with_capacity(self.len());
        for _ in self.iter().take_while(|&x| *x == BTC_ALPHA[0]) {
            r.push(0);
        }
        if x > Zero::zero() {
            r.append(&mut x.to_bytes_be());
        }
        Ok(r)
    }
}

#[cfg(test)]
mod tests {
    use base58::FromBase58;

    #[test]
    fn test_from_base58_basic() {
        assert_eq!("".from_base58().unwrap(), b"");
        assert_eq!("z".from_base58().unwrap(), b"9");
        assert_eq!("21".from_base58().unwrap(), b":");
        assert_eq!("2g".from_base58().unwrap(), b"a");
        assert_eq!("8Qq".from_base58().unwrap(), b"ab");
        assert_eq!("ZiCa".from_base58().unwrap(), b"abc");
    }

    #[test]
    fn test_from_base58_bytes() {
        assert_eq!(b"ZiCa".from_base58().unwrap(), b"abc");
    }

    #[test]
    fn test_from_base58_invalid_char() {
        assert!("AC0".from_base58().is_err());
        assert!("s5<".from_base58().is_err());
    }

    #[test]
    fn test_from_base58_initial_zeros() {
        assert_eq!("1ZiCa".from_base58().unwrap(), b"\0abc");
        assert_eq!("11ZiCa".from_base58().unwrap(), b"\0\0abc");
        assert_eq!("111ZiCa".from_base58().unwrap(), b"\0\0\0abc");
        assert_eq!("1111ZiCa".from_base58().unwrap(), b"\0\0\0\0abc");
    }
}
<commit_msg>Add some more from_base58 tests because why not<commit_after>use num::bigint::ToBigUint;
use num::{BigUint, Zero, One};
use std::fmt;

pub use self::FromBase58Error::*;

static BTC_ALPHA: &'static[u8] = b"123456789\
                                   ABCDEFGHJKLMNPQRSTUVWXYZ\
                                   abcdefghijkmnopqrstuvwxyz";

static FLICKR_ALPHA: &'static[u8] = b"123456789\
                                      abcdefghijkmnopqrstuvwxyz\
                                      ABCDEFGHJKLMNPQRSTUVWXYZ";

/// A trait for converting base58-encoded values
// TODO: This should incorporate the alphabet used as an associated constant.
// However, associated constants are not implemented in Rust yet. There is a
// PR though: https://github.com/rust-lang/rust/pull/23606
pub trait FromBase58 {
    /// Converts the value of `self`, interpreted as base58 encoded data,
    /// into an owned vector of bytes, returning the vector.
    fn from_base58(&self) -> Result<Vec<u8>, FromBase58Error>;
}

/// Errors that can occur when decoding a base58-encoded string
#[derive(Clone, Copy)]
pub enum FromBase58Error {
    /// The input contained a character not part of the base58 alphabet
    InvalidBase58Byte(u8, usize),
}

impl fmt::Debug for FromBase58Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidBase58Byte(ch, idx) =>
                write!(f, "Invalid character '{}' at position {}", ch, idx),
        }
    }
}

impl fmt::Display for FromBase58Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self, f)
    }
}

impl FromBase58 for str {
    fn from_base58(&self) -> Result<Vec<u8>, FromBase58Error> {
        self.as_bytes().from_base58()
    }
}

impl FromBase58 for [u8] {
    // TODO: fix some of the below when the binary assignment operators +=, *=
    // are overloadable
    fn from_base58(&self) -> Result<Vec<u8>, FromBase58Error> {
        let radix = 58.to_biguint().unwrap();
        let mut x: BigUint = Zero::zero();
        let mut rad_mult: BigUint = One::one();

        // Convert the base58 string to a BigUint `x`
        for (idx, &byte) in self.iter().enumerate().rev() {
            let first_idx = BTC_ALPHA.iter()
                                     .enumerate()
                                     .find(|x| *x.1 == byte)
                                     .map(|x| x.0);
            match first_idx {
                Some(i) => { x = x + i.to_biguint().unwrap() * &rad_mult; },
                None => return Err(InvalidBase58Byte(self[idx], idx))
            }

            rad_mult = &rad_mult * &radix;
        }

        let mut r = Vec::with_capacity(self.len());
        for _ in self.iter().take_while(|&x| *x == BTC_ALPHA[0]) {
            r.push(0);
        }
        if x > Zero::zero() {
            r.append(&mut x.to_bytes_be());
        }
        Ok(r)
    }
}

#[cfg(test)]
mod tests {
    use base58::FromBase58;

    #[test]
    fn test_from_base58_basic() {
        assert_eq!("".from_base58().unwrap(), b"");
        assert_eq!("Z".from_base58().unwrap(), &[32]);
        assert_eq!("n".from_base58().unwrap(), &[45]);
        assert_eq!("q".from_base58().unwrap(), &[48]);
        assert_eq!("r".from_base58().unwrap(), &[49]);
        assert_eq!("z".from_base58().unwrap(), &[57]);
        assert_eq!("4SU".from_base58().unwrap(), &[45, 49]);
        assert_eq!("4k8".from_base58().unwrap(), &[49, 49]);
        assert_eq!("ZiCa".from_base58().unwrap(), &[97, 98, 99]);
        assert_eq!("3mJr7AoUXx2Wqd".from_base58().unwrap(), b"1234598760");
        assert_eq!("3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f".from_base58().unwrap(), b"abcdefghijklmnopqrstuvwxyz");
    }

    #[test]
    fn test_from_base58_bytes() {
        assert_eq!(b"ZiCa".from_base58().unwrap(), b"abc");
    }

    #[test]
    fn test_from_base58_invalid_char() {
        assert!("0".from_base58().is_err());
        assert!("O".from_base58().is_err());
        assert!("I".from_base58().is_err());
        assert!("l".from_base58().is_err());
        assert!("3mJr0".from_base58().is_err());
        assert!("O3yxU".from_base58().is_err());
        assert!("3sNI".from_base58().is_err());
        assert!("4kl8".from_base58().is_err());
        assert!("s!5<".from_base58().is_err());
        assert!("t$@mX<*".from_base58().is_err());
    }

    #[test]
    fn test_from_base58_initial_zeros() {
        assert_eq!("1ZiCa".from_base58().unwrap(), b"\0abc");
        assert_eq!("11ZiCa".from_base58().unwrap(), b"\0\0abc");
        assert_eq!("111ZiCa".from_base58().unwrap(), b"\0\0\0abc");
        assert_eq!("1111ZiCa".from_base58().unwrap(), b"\0\0\0\0abc");
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate record_query;

use std::io;
use std::path;

use record_query as rq;

const ABOUT: &'static str = r#"
A tool for manipulating data records.  Similar in spirit to awk(1),
but on steroids.  Inspired by jq(1), but supports more record formats
and operations.

Records are read from stdin, processed, and written to stdout.  The
tool accepts a query in the custom rq query language as its main
command-line arguments.

Flags can be used to control the input and output formats of the tool.
By default, the input and output format is JSON.

See 'man rq' for in-depth documentation."#;

const AUTHOR: &'static str = "David Flemström <david.flemstrom@gmail.com>";

const INPUT_FORMAT_GROUP: &'static str = "input-format";
const OUTPUT_FORMAT_GROUP: &'static str = "output-format";

const PROTOBUF_CMD: &'static str = "protobuf";
const PROTOBUF_ADD_CMD: &'static str = "add";
const PROTOBUF_ADD_INPUT_ARG: &'static str = "protobuf-add-input";

const INPUT_JSON_ARG: &'static str = "input-json";
const OUTPUT_JSON_ARG: &'static str = "output-json";
const INPUT_PROTOBUF_ARG: &'static str = "input-protobuf";
const OUTPUT_PROTOBUF_ARG: &'static str = "output-protobuf";

const QUERY_ARG: &'static str = "query";

fn main() {
    use std::io::Read;

    env_logger::init().unwrap();

    let paths = rq::config::Paths::new().unwrap();
    let matches = match_args();

    if let Some(matches) = matches.subcommand_matches(PROTOBUF_CMD) {
        if let Some(matches) = matches.subcommand_matches(PROTOBUF_ADD_CMD) {
            let input = matches.value_of(PROTOBUF_ADD_INPUT_ARG).unwrap();
            rq::proto_index::add_file(&paths, path::Path::new(input)).unwrap();
        }
    } else {

        let query = rq::query::Query::parse(matches.value_of(QUERY_ARG).unwrap());

        let stdin = io::stdin();
        let mut input = stdin.lock();

        if matches.is_present(INPUT_PROTOBUF_ARG) {
            let name = matches.value_of(INPUT_PROTOBUF_ARG).unwrap();
            debug!("Input is protobuf with argument {}", name);

            let descriptors_proto = rq::proto_index::compile_descriptor_set(&paths).unwrap();
            let descriptors =
                rq::value::protobuf::descriptor::Descriptors::from_proto(&descriptors_proto);
            let stream = protobuf::CodedInputStream::new(&mut input);
            let values = rq::value::protobuf::ProtobufValues::new(descriptors,
                                                                  name.to_owned(),
                                                                  stream);
            run(values, query);
        } else {
            run(rq::value::json::JsonValues::new(input.bytes()), query);
        }
    }
}

fn match_args<'a>() -> clap::ArgMatches<'a> {
    clap::App::new("rq - Record query")
        .version(env!("CARGO_PKG_VERSION"))
        .author(AUTHOR)
        .about(ABOUT)
        .setting(clap::AppSettings::SubcommandsNegateReqs)
        .group(clap::ArgGroup::with_name(INPUT_FORMAT_GROUP))
        .group(clap::ArgGroup::with_name(OUTPUT_FORMAT_GROUP))
        .arg(clap::Arg::with_name(INPUT_JSON_ARG)
                 .group(INPUT_FORMAT_GROUP)
                 .short("j")
                 .long("input-json")
                 .help("Input is white-space separated JSON values."))
        .arg(clap::Arg::with_name(OUTPUT_JSON_ARG)
                 .group(OUTPUT_FORMAT_GROUP)
                 .short("J")
                 .long("output-json")
                 .help("Output should be formatted as JSON values."))
        .arg(clap::Arg::with_name(INPUT_PROTOBUF_ARG)
                 .group(INPUT_FORMAT_GROUP)
                 .short("p")
                 .long("input-protobuf")
                 .takes_value(true)
                 .value_name("schema-alias:MessageType")
                 .next_line_help(true)
                 .help("Input is a single protocol buffer object.  The \
                        argument refers to a schema alias defined in the \
                        config."))
        .arg(clap::Arg::with_name(OUTPUT_PROTOBUF_ARG)
                 .group(OUTPUT_FORMAT_GROUP)
                 .short("P")
                 .long("output-protobuf")
                 .takes_value(true)
                 .value_name("schema-alias:MessageType")
                 .next_line_help(true)
                 .help("Output should be formatted as protocol buffer \
                        objects.  The argument refers to a schema alias \
                        defined in the config, but if it is omitted and -p \
                        was used, the input schema is used instead."))
        .arg(clap::Arg::with_name(QUERY_ARG)
                 .required(true)
                 .help("The query to apply."))
        .subcommand(clap::SubCommand::with_name(PROTOBUF_CMD)
                        .about("Control protobuf configuration and data")
                        .author(AUTHOR)
                        .subcommand(clap::SubCommand::with_name(PROTOBUF_ADD_CMD)
                                        .about("Add a schema file to the rq registry")
                                        .author(AUTHOR)
                                        .arg(clap::Arg::with_name(PROTOBUF_ADD_INPUT_ARG)
                                                 .required(true)
                                                 .value_name("schema")
                                                 .help("The path to a .proto file to add to \
                                                        the rq registry"))))
        .get_matches()
}

fn run<Iter>(input: Iter, query: rq::query::Query)
    where Iter: Iterator<Item = rq::error::Result<rq::value::Value>>
{
    use std::io::Write;
    let mut stdout = io::stdout();
    let context = rq::query::Context::new();

    debug!("Starting input consumption");

    for value in input {
        debug!("Consuming an input value");
        query.evaluate(&context, value.unwrap()).to_json(&mut stdout).unwrap();
        stdout.write(&[10]).unwrap();
        stdout.flush().unwrap();
    }
}
<commit_msg>Give up on rustfmt and clap; manually indent<commit_after>extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate record_query;

use std::io;
use std::path;

use record_query as rq;

const ABOUT: &'static str = r#"
A tool for manipulating data records.  Similar in spirit to awk(1),
but on steroids.  Inspired by jq(1), but supports more record formats
and operations.

Records are read from stdin, processed, and written to stdout.  The
tool accepts a query in the custom rq query language as its main
command-line arguments.

Flags can be used to control the input and output formats of the tool.
By default, the input and output format is JSON.

See 'man rq' for in-depth documentation."#;

const AUTHOR: &'static str = "David Flemström <david.flemstrom@gmail.com>";

const INPUT_FORMAT_GROUP: &'static str = "input-format";
const OUTPUT_FORMAT_GROUP: &'static str = "output-format";

const PROTOBUF_CMD: &'static str = "protobuf";
const PROTOBUF_ADD_CMD: &'static str = "add";
const PROTOBUF_ADD_INPUT_ARG: &'static str = "protobuf-add-input";

const INPUT_JSON_ARG: &'static str = "input-json";
const OUTPUT_JSON_ARG: &'static str = "output-json";
const INPUT_PROTOBUF_ARG: &'static str = "input-protobuf";
const OUTPUT_PROTOBUF_ARG: &'static str = "output-protobuf";

const QUERY_ARG: &'static str = "query";

fn main() {
    use std::io::Read;

    env_logger::init().unwrap();

    let paths = rq::config::Paths::new().unwrap();
    let matches = match_args();

    if let Some(matches) = matches.subcommand_matches(PROTOBUF_CMD) {
        if let Some(matches) = matches.subcommand_matches(PROTOBUF_ADD_CMD) {
            let input = matches.value_of(PROTOBUF_ADD_INPUT_ARG).unwrap();
            rq::proto_index::add_file(&paths, path::Path::new(input)).unwrap();
        }
    } else {

        let query = rq::query::Query::parse(matches.value_of(QUERY_ARG).unwrap());

        let stdin = io::stdin();
        let mut input = stdin.lock();

        if matches.is_present(INPUT_PROTOBUF_ARG) {
            let name = matches.value_of(INPUT_PROTOBUF_ARG).unwrap();
            debug!("Input is protobuf with argument {}", name);

            let descriptors_proto = rq::proto_index::compile_descriptor_set(&paths).unwrap();
            let descriptors =
                rq::value::protobuf::descriptor::Descriptors::from_proto(&descriptors_proto);
            let stream = protobuf::CodedInputStream::new(&mut input);
            let values = rq::value::protobuf::ProtobufValues::new(descriptors,
                                                                  name.to_owned(),
                                                                  stream);
            run(values, query);
        } else {
            run(rq::value::json::JsonValues::new(input.bytes()), query);
        }
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn match_args<'a>() -> clap::ArgMatches<'a> {
    use clap::AppSettings;
    use clap::Arg;
    use clap::ArgGroup;
    use clap::SubCommand;

    clap::App::new("rq - Record query")
        .version(env!("CARGO_PKG_VERSION"))
        .author(AUTHOR)
        .about(ABOUT)
        .setting(AppSettings::SubcommandsNegateReqs)
        .group(ArgGroup::with_name(INPUT_FORMAT_GROUP))
        .group(ArgGroup::with_name(OUTPUT_FORMAT_GROUP))
        .arg(Arg::with_name(INPUT_JSON_ARG)
             .group(INPUT_FORMAT_GROUP)
             .short("j")
             .long("input-json")
             .help("Input is white-space separated JSON values."))
        .arg(Arg::with_name(OUTPUT_JSON_ARG)
             .group(OUTPUT_FORMAT_GROUP)
             .short("J")
             .long("output-json")
             .help("Output should be formatted as JSON values."))
        .arg(Arg::with_name(INPUT_PROTOBUF_ARG)
             .group(INPUT_FORMAT_GROUP)
             .short("p")
             .long("input-protobuf")
             .takes_value(true)
             .value_name(".package.MessageType")
             .next_line_help(true)
             .help("Input is a single protocol buffer object.  The argument refers to the fully \
                    qualified name of the message type (including the leading '.')"))
        .arg(Arg::with_name(OUTPUT_PROTOBUF_ARG)
             .group(OUTPUT_FORMAT_GROUP)
             .short("P")
             .long("output-protobuf")
             .takes_value(true)
             .value_name(".package.MessageType")
             .next_line_help(true)
             .help("Output should be formatted as protocol buffer objects.  The argument refers \
                    to the fully qualified name of the message type (including the leading '.'), \
                    but if it is omitted and -p was used, the input schema is used instead."))
        .arg(Arg::with_name(QUERY_ARG)
             .required(true)
             .help("The query to apply."))
        .subcommand(SubCommand::with_name(PROTOBUF_CMD)
                    .about("Control protobuf configuration and data")
                    .author(AUTHOR)
                    .subcommand(SubCommand::with_name(PROTOBUF_ADD_CMD)
                                .about("Add a schema file to the rq registry")
                                .author(AUTHOR)
                                .arg(Arg::with_name(PROTOBUF_ADD_INPUT_ARG)
                                     .required(true)
                                     .value_name("schema")
                                     .help("The path to a .proto file to add to the rq registry"))))
        .get_matches()
}

fn run<Iter>(input: Iter, query: rq::query::Query)
    where Iter: Iterator<Item = rq::error::Result<rq::value::Value>>
{
    use std::io::Write;
    let mut stdout = io::stdout();
    let context = rq::query::Context::new();

    debug!("Starting input consumption");

    for value in input {
        debug!("Consuming an input value");
        query.evaluate(&context, value.unwrap()).to_json(&mut stdout).unwrap();
        stdout.write(&[10]).unwrap();
        stdout.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>
use std;
use ffi;

#[allow(missing_copy_implementations)]
pub struct Bitmap {
    raw: *const ffi::FT_Bitmap,
}

impl Bitmap {
    pub fn from_raw(raw: *const ffi::FT_Bitmap) -> Bitmap {
        Bitmap {
            raw: raw,
        }
    }

    #[inline(always)]
    pub fn buffer(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_buf(
                &(*self.raw).buffer,
                (self.width() * self.rows()) as usize,
            )
        }
    }

    #[inline(always)]
    pub fn width(&self) -> i32 {
        unsafe {
            (*self.raw).width
        }
    }

    #[inline(always)]
    pub fn rows(&self) -> i32 {
        unsafe {
            (*self.raw).rows
        }
    }

    #[inline(always)]
    pub fn raw(&self) -> &ffi::FT_Bitmap {
        unsafe {
            &*self.raw
        }
    }
}

<commit_msg>add more bitmap API<commit_after>use std;
use ffi;

/// An enumeration type used to describe the format of pixels in a given bitmap. Note that
/// additional formats may be added in the future.
#[derive(Copy)]
pub enum PixelMode {
    /// This value is reserved.
    None,

    /// A monochrome bitmap, using 1 bit per pixel. Note that pixels are
    /// stored in most-significant order (MSB), which means that the left-most
    /// pixel in a byte has value 128.
    Mono,

    /// An 8-bit bitmap, generally used to represent anti-aliased glyph images.
    /// Each pixel is stored in one byte. Note that the number of `gray`
    /// levels is stored in the `num_grays` field of the FT_Bitmap structure
    /// (it generally is 256).
    Gray,

    /// A 2-bit per pixel bitmap, used to represent embedded anti-aliased
    /// bitmaps in font files according to the OpenType specification. We
    /// haven't found a single font using this format, however.
    Gray2,

    /// A 4-bit per pixel bitmap, representing embedded anti-aliased bitmaps in
    /// font files according to the OpenType specification. We haven't found a
    /// single font using this format, however.
    Gray4,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used
    /// for display on LCD displays; the bitmap is three times wider than the
    /// original glyph image. See also FT_RENDER_MODE_LCD.
    Lcd,

    /// An 8-bit bitmap, representing RGB or BGR decimated glyph images used for
    /// display on rotated LCD displays; the bitmap is three times taller than
    /// the original glyph image. See also FT_RENDER_MODE_LCD_V.
    LcdV,

    /// An image with four 8-bit channels per pixel, representing a color image
    /// (such as emoticons) with alpha channel. For each pixel, the format is
    /// BGRA, which means, the blue channel comes first in memory. The color
    /// channels are pre-multiplied and in the sRGB colorspace. For example,
    /// full red at half-translucent opacity will be represented as
    /// `00,00,80,80`, not `00,00,FF,80`. See also FT_LOAD_COLOR.
    Bgra,
}

#[allow(missing_copy_implementations)]
pub struct Bitmap {
    raw: *const ffi::FT_Bitmap,
}

impl Bitmap {
    pub fn from_raw(raw: *const ffi::FT_Bitmap) -> Bitmap {
        Bitmap {
            raw: raw,
        }
    }

    /// A typeless pointer to the bitmap buffer. This value should be aligned
    /// on 32-bit boundaries in most cases.
    pub fn buffer(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_buf(
                &(*self.raw).buffer,
                (self.width() * self.rows()) as usize,
            )
        }
    }

    /// The number of pixels in bitmap row.
    pub fn width(&self) -> i32 {
        unsafe {
            (*self.raw).width
        }
    }

    /// The number of bitmap rows.
    pub fn rows(&self) -> i32 {
        unsafe {
            (*self.raw).rows
        }
    }

    pub fn raw(&self) -> &ffi::FT_Bitmap {
        unsafe {
            &*self.raw
        }
    }

    /// The pixel mode, i.e., how pixel bits are stored. See `PixelMode` for
    /// possible values.
    pub fn pixel_mode(&self) -> PixelMode {
        unsafe {
            match (*self.raw).pixel_mode as u32 {
                ffi::FT_PIXEL_MODE_NONE  => PixelMode::None,
                ffi::FT_PIXEL_MODE_MONO  => PixelMode::Mono,
                ffi::FT_PIXEL_MODE_GRAY  => PixelMode::Gray,
                ffi::FT_PIXEL_MODE_GRAY2 => PixelMode::Gray2,
                ffi::FT_PIXEL_MODE_GRAY4 => PixelMode::Gray4,
                ffi::FT_PIXEL_MODE_LCD   => PixelMode::Lcd,
                ffi::FT_PIXEL_MODE_LCD_V => PixelMode::LcdV,
                ffi::FT_PIXEL_MODE_BGRA  => PixelMode::Bgra,
                _ => panic!("unexpected pixel mode"),
            }
        }
    }

    /// The pitch's absolute value is the number of bytes taken by one bitmap row, including
    /// padding. However, the pitch is positive when the bitmap has a ‘down’ flow, and negative
    /// when it has an ‘up’ flow. In all cases, the pitch is an offset to add to a bitmap pointer
    /// in order to go down one row.
    ///
    /// Note that ‘padding’ means the alignment of a bitmap to a byte border, and FreeType
    /// functions normally align to the smallest possible integer value.
    /// For the B/W rasterizer, ‘pitch’ is always an even number.
    ///
    /// To change the pitch of a bitmap (say, to make it a multiple of 4), use FT_Bitmap_Convert.
    /// Alternatively, you might use callback functions to directly render to the application's
    /// surface; see the file ‘example2.cpp’ in the tutorial for a demonstration.
    pub fn pitch(&self) -> isize {
        unsafe {
            (*self.raw).pitch as isize
        }
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate rand;
extern crate timely;
extern crate radix_sort;

use rand::{Rng, SeedableRng, StdRng};
use radix_sort::RadixSorter;

use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::dataflow::channels::pact::Exchange;

fn main() {

    // command-line args: numbers of nodes and edges in the random graph.
    let nodes: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();

    timely::execute_from_args(std::env::args().skip(3), move |root| {

        let index = root.index();
        let peers = root.peers();

        let seed: &[_] = &[1, 2, 3, root.index()];
        let mut rng: StdRng = SeedableRng::from_seed(seed);
        let mut sorter = RadixSorter::new();

        let mut offsets = Vec::new();
        let mut targets = Vec::new();
        let mut recents = Vec::new();
        let mut parents = vec![u32::max_value(); nodes / peers];

        let start = time::precise_time_s();

        root.scoped(move |scope| {

            // generate part of a random graph.
            let graph = (0..edges / peers)
                .map(move |_| (rng.gen_range(0u32, nodes as u32), rng.gen_range(0u32, nodes as u32)))
                .to_stream(scope);

            // define a loop variable, for the (node, root) pairs.
            let (handle, stream) = scope.loop_variable(usize::max_value(), 1);

            // use the stream of edges
            graph.binary_notify(
                &stream,
                Exchange::new(|x: &(u32, u32)| x.0 as u64),
                Exchange::new(|x: &(u32, u32)| x.0 as u64),
                "BFS",
                vec![],
                move |input1, input2, output, notify| {

                    // receive edges, start to sort them
                    input1.for_each(|time, data| {
                        notify.notify_at(time);
                        for &edge in data.iter() { sorter.push(edge, &|x| x.0); }
                    });

                    // receive (node, root) pairs, note any new ones.
                    input2.for_each(|time, data| {
                        notify.notify_at(time);
                        for &(node, root) in data.iter() {
                            // println!("received: {:?}, parents[{}] = {}", (node, root), node, parents[node as usize]);
                            if parents[(node as usize) / peers] == u32::max_value() {
                                // println!("keeping: {:?}", node);
                                parents[(node as usize) / peers] = root;
                                recents.push(node);
                            }
                        }
                    });

                    notify.for_each(|time, _count| {

                        // maybe process the graph
                        if time.inner == 0 {

                            if index == 0 {
                                println!("{}:\tstarting sort", time::precise_time_s() - start);
                            }

                            // construct the graph
                            offsets.push(0);
                            let mut prev_node = 0;
                            let sorted = sorter.finish(&|x| x.0);
                            for buffer in &sorted {
                                for &(node, edge) in buffer {
                                    let node = node / peers as u32;
                                    while prev_node < node {
                                        prev_node += 1;
                                        offsets.push(targets.len())
                                    }
                                    targets.push(edge);
                                }
                            }
                            offsets.push(targets.len())

                        }

                        if index == 0 {
                            println!("{}:\tworker: {}, todo.len(): {}", time::precise_time_s() - start, index, recents.len());
                        }
                        let mut session = output.session(&time);
                        while let Some(next) = recents.pop() {
                            let lower = offsets[(next as usize) / peers];
                            let upper = offsets[((next as usize) / peers) + 1];
                            // println!("degree[{}]: {}", next, upper-lower);
                            for &target in &targets[lower..upper] {
                                session.give((target, next));
                            }
                        }

                    });
                }
            )
            .concat(&(0..1).map(|x| (x,x)).to_stream(scope))
            .connect_loop(handle);

        });

    });

}
<commit_msg>updated example<commit_after>extern crate time;
extern crate rand;
extern crate timely;
extern crate radix_sort;

use std::collections::HashMap;

use rand::{Rng, SeedableRng, StdRng};
use radix_sort::RadixSorter;

use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::dataflow::channels::pact::Exchange;

use timely::drain::DrainExt;

fn main() {

    // command-line args: numbers of nodes and edges in the random graph.
    let nodes: usize = std::env::args().nth(1).unwrap().parse().unwrap();
    let edges: usize = std::env::args().nth(2).unwrap().parse().unwrap();

    timely::execute_from_args(std::env::args().skip(3), move |root| {

        let index = root.index();
        let peers = root.peers();

        let seed: &[_] = &[1, 2, 3, root.index()];
        let mut rng: StdRng = SeedableRng::from_seed(seed);
        let mut sorter = RadixSorter::new();

        // pending edges and node updates.
        let mut edge_list = Vec::new();
        let mut node_lists = HashMap::new();

        // graph data; offsets into targets.
        let mut offsets = Vec::new();
        let mut targets = Vec::new();

        // holds the bfs parent of each node, or u32::max_value() if unset.
        let mut done = vec![u32::max_value(); 1 + (nodes / peers)];

        let start = time::precise_time_s();

        root.scoped(move |scope| {

            // generate part of a random graph.
            let graph = (0..edges / peers)
                .map(move |_| (rng.gen_range(0u32, nodes as u32), rng.gen_range(0u32, nodes as u32)))
                .to_stream(scope);

            // define a loop variable, for the (node, root) pairs.
            let (handle, stream) = scope.loop_variable(usize::max_value(), 1);

            // use the stream of edges
            graph.binary_notify(
                &stream,
                Exchange::new(|x: &(u32, u32)| x.0 as u64),
                Exchange::new(|x: &(u32, u32)| x.0 as u64),
                "BFS",
                vec![],
                move |input1, input2, output, notify| {

                    // receive edges, start to sort them
                    input1.for_each(|time, data| {
                        notify.notify_at(time);
                        edge_list.push(data.replace_with(Vec::new()));
                    });

                    // receive (node, root) pairs, note any new ones.
                    input2.for_each(|&time, data| {
                        node_lists.entry(time)
                                  .or_insert_with(|| {
                                      notify.notify_at(&time);
                                      Vec::new()
                                  })
                                  .push(data.replace_with(Vec::new()));
                    });

                    notify.for_each(|time, _num| {

                        // maybe process the graph
                        if time.inner == 0 {

                            // print some diagnostic timing information
                            if index == 0 { println!("{}:\tsorting", time::precise_time_s() - start); }

                            // sort the edges
                            sorter.sort(&mut edge_list, &|x| x.0);

                            let mut count = 0;
                            for buffer in &edge_list { count += buffer.len(); }

                            // allocate sufficient memory, to avoid resizing.
                            offsets = Vec::with_capacity(1 + (nodes / peers));
                            targets = Vec::with_capacity(count);

                            // construct the graph
                            offsets.push(0);
                            let mut prev_node = 0;
                            for buffer in edge_list.drain_temp() {
                                for (node, edge) in buffer {
                                    let temp = node / peers as u32;
                                    while prev_node < temp {
                                        prev_node += 1;
                                        offsets.push(targets.len() as u32)
                                    }
                                    targets.push(edge);
                                }
                            }
                            offsets.push(targets.len() as u32);
                        }

                        // print some diagnostic timing information
                        if index == 0 { println!("{}:\ttime: {:?}", time::precise_time_s() - start, time); }

                        if let Some(mut todo) = node_lists.remove(&time) {
                            let mut session = output.session(&time);

                            // we could sort these, or not. try it out!
                            // sorter.sort(&mut todo, &|x| x.0);

                            for buffer in todo.drain_temp() {
                                for (node, prev) in buffer {
                                    let temp = (node as usize) / peers;
                                    if done[temp] == u32::max_value() {
                                        done[temp] = prev;
                                        let lower = offsets[temp] as usize;
                                        let upper = offsets[temp + 1] as usize;
                                        for &target in &targets[lower..upper] {
                                            session.give((target, node));
                                        }
                                    }
                                }
                            }
                        }
                    });
                }
            )
            .concat(&(0..1).map(|x| (x,x)).to_stream(scope))
            .connect_loop(handle);
        });
    });
}
<|endoftext|>


<commit_before>//! A buffer for reading data from the network.
//!
//! The `ReadBuffer` is a buffer of bytes similar to a first-in, first-out queue.
//! It is filled by reading from a stream supporting `Read` and is then
//! accessible as a cursor for reading bytes.

use std::io::{Cursor, Read, Result as IoResult};

use bytes::Buf;

/// A FIFO buffer for reading packets from the network.
#[derive(Debug)]
pub struct ReadBuffer<const CHUNK_SIZE: usize> {
    storage: Cursor<Vec<u8>>,
    chunk: [u8; CHUNK_SIZE],
}

impl<const CHUNK_SIZE: usize> ReadBuffer<CHUNK_SIZE> {
    /// Create a new empty input buffer.
    pub fn new() -> Self {
        Self::with_capacity(CHUNK_SIZE)
    }

    /// Create a new empty input buffer with a given `capacity`.
    pub fn with_capacity(capacity: usize) -> Self {
        Self::from_partially_read(Vec::with_capacity(capacity))
    }

    /// Create a input buffer filled with previously read data.
    pub fn from_partially_read(part: Vec<u8>) -> Self {
        Self { storage: Cursor::new(part), chunk: [0; CHUNK_SIZE] }
    }

    /// Get a cursor to the data storage.
    pub fn as_cursor(&self) -> &Cursor<Vec<u8>> {
        &self.storage
    }

    /// Get a cursor to the mutable data storage.
    pub fn as_cursor_mut(&mut self) -> &mut Cursor<Vec<u8>> {
        &mut self.storage
    }

    /// Consume the `ReadBuffer` and get the internal storage.
    pub fn into_vec(mut self) -> Vec<u8> {
        // Current implementation of `tungstenite-rs` expects that the `into_vec()` drains
        // the data from the container that has already been read by the cursor.
        self.clean_up();

        // Now we can safely return the internal container.
        self.storage.into_inner()
    }

    /// Read next portion of data from the given input stream.
    pub fn read_from<S: Read>(&mut self, stream: &mut S) -> IoResult<usize> {
        self.clean_up();
        let size = stream.read(&mut self.chunk)?;
        self.storage.get_mut().extend_from_slice(&self.chunk[..size]);
        Ok(size)
    }

    /// Cleans ups the part of the vector that has been already read by the cursor.
    fn clean_up(&mut self) {
        let pos = self.storage.position() as usize;
        self.storage.get_mut().drain(0..pos).count();
        self.storage.set_position(0);
    }
}

impl<const CHUNK_SIZE: usize> Buf for ReadBuffer<CHUNK_SIZE> {
    fn remaining(&self) -> usize {
        Buf::remaining(self.as_cursor())
    }

    fn chunk(&self) -> &[u8] {
        Buf::chunk(self.as_cursor())
    }

    fn advance(&mut self, cnt: usize) {
        Buf::advance(self.as_cursor_mut(), cnt)
    }
}

impl<const CHUNK_SIZE: usize> Default for ReadBuffer<CHUNK_SIZE> {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn simple_reading() {
        let mut input = Cursor::new(b"Hello World!".to_vec());
        let mut buffer = ReadBuffer::<4096>::new();
        let size = buffer.read_from(&mut input).unwrap();
        assert_eq!(size, 12);
        assert_eq!(buffer.chunk(), b"Hello World!");
    }

    #[test]
    fn reading_in_chunks() {
        let mut inp = Cursor::new(b"Hello World!".to_vec());
        let mut buf = ReadBuffer::<4>::new();

        let size = buf.read_from(&mut inp).unwrap();
        assert_eq!(size, 4);
        assert_eq!(buf.chunk(), b"Hell");

        buf.advance(2);
        assert_eq!(buf.chunk(), b"ll");
        assert_eq!(buf.storage.get_mut(), b"Hell");

        let size = buf.read_from(&mut inp).unwrap();
        assert_eq!(size, 4);
        assert_eq!(buf.chunk(), b"llo Wo");
        assert_eq!(buf.storage.get_mut(), b"llo Wo");

        let size = buf.read_from(&mut inp).unwrap();
        assert_eq!(size, 4);
        assert_eq!(buf.chunk(), b"llo World!");
    }
}
<commit_msg>Move ReadBuffer chunk to heap<commit_after>//! A buffer for reading data from the network.
//!
//! The `ReadBuffer` is a buffer of bytes similar to a first-in, first-out queue.
//! It is filled by reading from a stream supporting `Read` and is then
//! accessible as a cursor for reading bytes.

use std::io::{Cursor, Read, Result as IoResult};

use bytes::Buf;

/// A FIFO buffer for reading packets from the network.
#[derive(Debug)]
pub struct ReadBuffer<const CHUNK_SIZE: usize> {
    storage: Cursor<Vec<u8>>,
    chunk: Box<[u8; CHUNK_SIZE]>,
}

impl<const CHUNK_SIZE: usize> ReadBuffer<CHUNK_SIZE> {
    /// Create a new empty input buffer.
    pub fn new() -> Self {
        Self::with_capacity(CHUNK_SIZE)
    }

    /// Create a new empty input buffer with a given `capacity`.
    pub fn with_capacity(capacity: usize) -> Self {
        Self::from_partially_read(Vec::with_capacity(capacity))
    }

    /// Create a input buffer filled with previously read data.
    pub fn from_partially_read(part: Vec<u8>) -> Self {
        Self { storage: Cursor::new(part), chunk: Box::new([0; CHUNK_SIZE]) }
    }

    /// Get a cursor to the data storage.
    pub fn as_cursor(&self) -> &Cursor<Vec<u8>> {
        &self.storage
    }

    /// Get a cursor to the mutable data storage.
    pub fn as_cursor_mut(&mut self) -> &mut Cursor<Vec<u8>> {
        &mut self.storage
    }

    /// Consume the `ReadBuffer` and get the internal storage.
    pub fn into_vec(mut self) -> Vec<u8> {
        // Current implementation of `tungstenite-rs` expects that the `into_vec()` drains
        // the data from the container that has already been read by the cursor.
        self.clean_up();

        // Now we can safely return the internal container.
        self.storage.into_inner()
    }

    /// Read next portion of data from the given input stream.
    pub fn read_from<S: Read>(&mut self, stream: &mut S) -> IoResult<usize> {
        self.clean_up();
        let size = stream.read(&mut *self.chunk)?;
        self.storage.get_mut().extend_from_slice(&self.chunk[..size]);
        Ok(size)
    }

    /// Cleans ups the part of the vector that has been already read by the cursor.
    fn clean_up(&mut self) {
        let pos = self.storage.position() as usize;
        self.storage.get_mut().drain(0..pos).count();
        self.storage.set_position(0);
    }
}

impl<const CHUNK_SIZE: usize> Buf for ReadBuffer<CHUNK_SIZE> {
    fn remaining(&self) -> usize {
        Buf::remaining(self.as_cursor())
    }

    fn chunk(&self) -> &[u8] {
        Buf::chunk(self.as_cursor())
    }

    fn advance(&mut self, cnt: usize) {
        Buf::advance(self.as_cursor_mut(), cnt)
    }
}

impl<const CHUNK_SIZE: usize> Default for ReadBuffer<CHUNK_SIZE> {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn simple_reading() {
        let mut input = Cursor::new(b"Hello World!".to_vec());
        let mut buffer = ReadBuffer::<4096>::new();
        let size = buffer.read_from(&mut input).unwrap();
        assert_eq!(size, 12);
        assert_eq!(buffer.chunk(), b"Hello World!");
    }

    #[test]
    fn reading_in_chunks() {
        let mut inp = Cursor::new(b"Hello World!".to_vec());
        let mut buf = ReadBuffer::<4>::new();

        let size = buf.read_from(&mut inp).unwrap();
        assert_eq!(size, 4);
        assert_eq!(buf.chunk(), b"Hell");

        buf.advance(2);
        assert_eq!(buf.chunk(), b"ll");
        assert_eq!(buf.storage.get_mut(), b"Hell");

        let size = buf.read_from(&mut inp).unwrap();
        assert_eq!(size, 4);
        assert_eq!(buf.chunk(), b"llo Wo");
        assert_eq!(buf.storage.get_mut(), b"llo Wo");

        let size = buf.read_from(&mut inp).unwrap();
        assert_eq!(size, 4);
        assert_eq!(buf.chunk(), b"llo World!");
    }
}
<|endoftext|>