<commit_before>// Copyright © 2014, Peter Atashian

use image::{
    GenericImage,
    ImageBuffer,
    Pixel,
    RgbaImage,
    SubImage,
    mod,
};
use std::cmp::max;
use std::collections::HashMap;
use std::default::Default;
use std::io::{
    BufferedWriter,
    File,
};
use std::io::fs::{
    PathExtensions,
    walk_dir,
};
use std::mem::swap;
use {
    FloatImage,
    decode_srgb,
    encode_srgb,
    resize,
    save,
};

struct Tilesheet {
    size: u32,
    img: RgbaImage,
}
impl Tilesheet {
    fn grow(&mut self, w: u32, h: u32) {
        let mut img = ImageBuffer::new(w, h);
        for (x, y, &pix) in self.img.enumerate_pixels() {
            img.put_pixel(x, y, pix);
        }
        swap(&mut self.img, &mut img);
    }
    fn insert(&mut self, x: u32, y: u32, img: &FloatImage) {
        let (width, height) = img.dimensions();
        assert!(width == height);
        let img = resize(img, self.size, self.size);
        let img = encode_srgb(&img);
        let (w, h) = self.img.dimensions();
        if (x + 1) * self.size > w || (y + 1) * self.size > h {
            let (nw, nh) = (max((x + 1) * self.size, w), max((y + 1) * self.size, h));
            self.grow(nw, nh)
        }
        let mut sub = SubImage::new(
            &mut self.img,
            x * self.size, y * self.size,
            self.size, self.size,
        );
        for (&from, (_, _, to)) in img.pixels().zip(sub.pixels_mut()) {
            *to = from;
        }
    }
}
struct TilesheetManager {
    name: String,
    lookup: HashMap<String, (u32, u32)>,
    entries: HashMap<(u32, u32), String>,
    tilesheets: Vec<Tilesheet>,
    next: (u32, u32),
}
impl TilesheetManager {
    fn new(name: &str, sizes: &[u32]) -> TilesheetManager {
        let tilesheets = load_tilesheets(name, sizes);
        let lookup = load_tiles(name);
        let entries = load_entries(&lookup);
        TilesheetManager {
            name: name.into_string(),
            lookup: lookup,
            entries: entries,
            tilesheets: tilesheets,
            next: (0, 0),
        }
    }
    fn update(&mut self) {
        let path = Path::new(r"work\tilesheets").join(self.name.as_slice());
        for path in walk_dir(&path).unwrap() {
            if !path.is_file() { continue }
            if path.extension_str() != Some("png") { continue }
            let name = path.filestem_str().unwrap();
            let img = image::open(&path).unwrap().to_rgba();
            let img = decode_srgb(&img);
            let (x, y) = self.lookup(name);
            for tilesheet in self.tilesheets.iter_mut() {
                tilesheet.insert(x, y, &img);
            }
        }
    }
    fn save(&self) {
        for tilesheet in self.tilesheets.iter() {
            let name = format!("Tilesheet {} {}.png", self.name, tilesheet.size);
            let path = Path::new(r"work\tilesheets").join(name.as_slice());
            save(&tilesheet.img, &path);
        }
        let name = format!("Tilesheet {}.txt", self.name);
        let path = Path::new(r"work\tilesheets").join(name.as_slice());
        let mut file = BufferedWriter::new(File::create(&path).unwrap());
        for (&(x, y), tile) in self.entries.iter() {
            (writeln!(&mut file, "{} {} {}", x, y, tile)).unwrap();
        }
    }
    fn increment(&mut self) {
        self.next.1 += 1;
        if self.next.1 > self.next.0 * 2 {
            self.next.0 += 1;
            self.next.1 = 0;
        }
    }
    fn next_pos(&self) -> (u32, u32) {
        if self.next.1 < self.next.0 {
            (self.next.1, self.next.0)
        } else {
            (self.next.0, self.next.1 - self.next.0)
        }
    }
    fn lookup(&mut self, name: &str) -> (u32, u32) {
        match self.lookup.get(name) {
            Some(&x) => return x,
            None => (),
        }
        while self.entries.get(&self.next_pos()).is_some() {
            self.increment();
        }
        let pos = self.next_pos();
        self.lookup.insert(name.into_string(), pos);
        self.entries.insert(pos, name.into_string());
        pos
    }
}
fn load_tiles(name: &str) -> HashMap<String, (u32, u32)> {
    let reg = regex!(r"(\d+) (\d+) (.+?)\r?\n");
    let name = format!("Tilesheet {}.txt", name);
    let path = Path::new(r"work\tilesheets").join(name.as_slice());
    let mut file = match File::open(&path) {
        Ok(x) => x,
        Err(_) => {
            println!("No tilesheet found. Creating new tilesheet.");
            return HashMap::new();
        }
    };
    let data = file.read_to_string().unwrap();
    reg.captures_iter(data.as_slice()).map(|cap| {
        let x = from_str(cap.at(1)).unwrap();
        let y = from_str(cap.at(2)).unwrap();
        let name = cap.at(3).into_string();
        (name, (x, y))
    }).collect()
}
fn load_entries(tiles: &HashMap<String, (u32, u32)>) -> HashMap<(u32, u32), String> {
    tiles.iter().map(|(key, value)| (value.clone(), key.clone())).collect()
}
fn load_tilesheet(name: &str, size: u32) -> Tilesheet {
    let name = format!("Tilesheet {} {}.png", name, size);
    let path = Path::new(r"work\tilesheets").join(name.as_slice());
    let img = match image::open(&path) {
        Ok(img) => img.to_rgba(),
        Err(_) => ImageBuffer::new(size, size),
    };
    Tilesheet { size: size, img: img }
}
fn load_tilesheets(name: &str, sizes: &[u32]) -> Vec<Tilesheet> {
    sizes.iter().map(|&size| load_tilesheet(name, size)).collect()
}
pub fn update_tilesheet(name: &str, sizes: &[u32]) {
    println!("Loading tilesheet");
    let mut manager = TilesheetManager::new(name, sizes);
    println!("Updating tilesheet");
    manager.update();
    println!("Saving tilesheet");
    manager.save();
    println!("Done");
}
<commit_msg>Sort the output<commit_after>// Copyright © 2014, Peter Atashian

use image::{
    GenericImage,
    ImageBuffer,
    Pixel,
    RgbaImage,
    SubImage,
    mod,
};
use std::cmp::max;
use std::collections::HashMap;
use std::default::Default;
use std::io::{
    BufferedWriter,
    File,
};
use std::io::fs::{
    PathExtensions,
    walk_dir,
};
use std::mem::swap;
use {
    FloatImage,
    decode_srgb,
    encode_srgb,
    resize,
    save,
};

struct Tilesheet {
    size: u32,
    img: RgbaImage,
}
impl Tilesheet {
    fn grow(&mut self, w: u32, h: u32) {
        let mut img = ImageBuffer::new(w, h);
        for (x, y, &pix) in self.img.enumerate_pixels() {
            img.put_pixel(x, y, pix);
        }
        swap(&mut self.img, &mut img);
    }
    fn insert(&mut self, x: u32, y: u32, img: &FloatImage) {
        let (width, height) = img.dimensions();
        assert!(width == height);
        let img = resize(img, self.size, self.size);
        let img = encode_srgb(&img);
        let (w, h) = self.img.dimensions();
        if (x + 1) * self.size > w || (y + 1) * self.size > h {
            let (nw, nh) = (max((x + 1) * self.size, w), max((y + 1) * self.size, h));
            self.grow(nw, nh)
        }
        let mut sub = SubImage::new(
            &mut self.img,
            x * self.size, y * self.size,
            self.size, self.size,
        );
        for (&from, (_, _, to)) in img.pixels().zip(sub.pixels_mut()) {
            *to = from;
        }
    }
}
struct TilesheetManager {
    name: String,
    lookup: HashMap<String, (u32, u32)>,
    entries: HashMap<(u32, u32), String>,
    tilesheets: Vec<Tilesheet>,
    next: (u32, u32),
}
impl TilesheetManager {
    fn new(name: &str, sizes: &[u32]) -> TilesheetManager {
        let tilesheets = load_tilesheets(name, sizes);
        let lookup = load_tiles(name);
        let entries = load_entries(&lookup);
        TilesheetManager {
            name: name.into_string(),
            lookup: lookup,
            entries: entries,
            tilesheets: tilesheets,
            next: (0, 0),
        }
    }
    fn update(&mut self) {
        let path = Path::new(r"work\tilesheets").join(self.name.as_slice());
        for path in walk_dir(&path).unwrap() {
            if !path.is_file() { continue }
            if path.extension_str() != Some("png") { continue }
            let name = path.filestem_str().unwrap();
            let img = image::open(&path).unwrap().to_rgba();
            let img = decode_srgb(&img);
            let (x, y) = self.lookup(name);
            for tilesheet in self.tilesheets.iter_mut() {
                tilesheet.insert(x, y, &img);
            }
        }
    }
    fn save(&self) {
        for tilesheet in self.tilesheets.iter() {
            let name = format!("Tilesheet {} {}.png", self.name, tilesheet.size);
            let path = Path::new(r"work\tilesheets").join(name.as_slice());
            save(&tilesheet.img, &path);
        }
        let name = format!("Tilesheet {}.txt", self.name);
        let path = Path::new(r"work\tilesheets").join(name.as_slice());
        let mut file = BufferedWriter::new(File::create(&path).unwrap());
        let mut stuff = self.entries.iter().map(|(&(x, y), tile)| (x, y, tile)).collect::<Vec<_>>();
        stuff.sort_by(|a, b| if a.1.cmp(&b.1) == Equal { a.0.cmp(&b.0) } else { a.1.cmp(&b.1) });
        for &(x, y, tile) in stuff.iter() {
            (writeln!(&mut file, "{} {} {}", x, y, tile)).unwrap();
        }
    }
    fn increment(&mut self) {
        self.next.1 += 1;
        if self.next.1 > self.next.0 * 2 {
            self.next.0 += 1;
            self.next.1 = 0;
        }
    }
    fn next_pos(&self) -> (u32, u32) {
        if self.next.1 < self.next.0 {
            (self.next.1, self.next.0)
        } else {
            (self.next.0, self.next.1 - self.next.0)
        }
    }
    fn lookup(&mut self, name: &str) -> (u32, u32) {
        match self.lookup.get(name) {
            Some(&x) => return x,
            None => (),
        }
        while self.entries.get(&self.next_pos()).is_some() {
            self.increment();
        }
        let pos = self.next_pos();
        self.lookup.insert(name.into_string(), pos);
        self.entries.insert(pos, name.into_string());
        pos
    }
}
fn load_tiles(name: &str) -> HashMap<String, (u32, u32)> {
    let reg = regex!(r"(\d+) (\d+) (.+?)\r?\n");
    let name = format!("Tilesheet {}.txt", name);
    let path = Path::new(r"work\tilesheets").join(name.as_slice());
    let mut file = match File::open(&path) {
        Ok(x) => x,
        Err(_) => {
            println!("No tilesheet found. Creating new tilesheet.");
            return HashMap::new();
        }
    };
    let data = file.read_to_string().unwrap();
    reg.captures_iter(data.as_slice()).map(|cap| {
        let x = from_str(cap.at(1)).unwrap();
        let y = from_str(cap.at(2)).unwrap();
        let name = cap.at(3).into_string();
        (name, (x, y))
    }).collect()
}
fn load_entries(tiles: &HashMap<String, (u32, u32)>) -> HashMap<(u32, u32), String> {
    tiles.iter().map(|(key, value)| (value.clone(), key.clone())).collect()
}
fn load_tilesheet(name: &str, size: u32) -> Tilesheet {
    let name = format!("Tilesheet {} {}.png", name, size);
    let path = Path::new(r"work\tilesheets").join(name.as_slice());
    let img = match image::open(&path) {
        Ok(img) => img.to_rgba(),
        Err(_) => ImageBuffer::new(size, size),
    };
    Tilesheet { size: size, img: img }
}
fn load_tilesheets(name: &str, sizes: &[u32]) -> Vec<Tilesheet> {
    sizes.iter().map(|&size| load_tilesheet(name, size)).collect()
}
pub fn update_tilesheet(name: &str, sizes: &[u32]) {
    println!("Loading tilesheet");
    let mut manager = TilesheetManager::new(name, sizes);
    println!("Updating tilesheet");
    manager.update();
    println!("Saving tilesheet");
    manager.save();
    println!("Done");
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{aptos_cli::launch_faucet, smoke_test_environment::new_local_swarm_with_aptos};
use aptos::{account::create::DEFAULT_FUNDED_COINS, test::CliTestFramework};
use aptos_config::config::ApiConfig;
use aptos_rosetta::{client::RosettaClient, types::AccountBalanceResponse, CURRENCY, NUM_DECIMALS};
use aptos_types::{account_address::AccountAddress, chain_id::ChainId};
use forge::{LocalSwarm, Node};
use std::{str::FromStr, time::Duration};

pub async fn setup_test(num_nodes: usize) -> (LocalSwarm, CliTestFramework, RosettaClient) {
    let swarm = new_local_swarm_with_aptos(num_nodes).await;
    let chain_id = swarm.chain_id();
    let validator = swarm.validators().next().unwrap();
    let root_key = swarm.root_key();
    let _faucet = launch_faucet(validator.rest_api_endpoint(), root_key, chain_id);

    // Connect the operator tool to the node's JSON RPC API
    let tool = CliTestFramework::new(
        validator.rest_api_endpoint(),
        "http://localhost:9996".parse().unwrap(),
        2,
    )
    .await;

    // And the client
    let rosetta_socket_addr = "127.0.0.1:9997";
    let rosetta_url = format!("http://{}", rosetta_socket_addr).parse().unwrap();
    let rosetta_client = RosettaClient::new(rosetta_url);
    let rosetta_socket_addr = "127.0.0.1:9997";
    let api_config = ApiConfig {
        enabled: true,
        address: rosetta_socket_addr.parse().unwrap(),
        tls_cert_path: None,
        tls_key_path: None,
        content_length_limit: None,
    };

    // Start the server
    let _ = aptos_rosetta::bootstrap_async(
        swarm.chain_id(),
        api_config,
        aptos_rest_client::Client::new(validator.rest_api_endpoint()),
    )
    .await
    .unwrap();

    (swarm, tool, rosetta_client)
}

#[tokio::test]
#[ignore]
async fn test_account_balance() {
    let (_swarm, cli, rosetta_client) = setup_test(1).await;

    cli.create_account_with_faucet(0).await.unwrap();
    let account = CliTestFramework::account_id(0);

    let response = get_account_balance_once_ready(&rosetta_client, account)
        .await
        .unwrap();
    assert_eq!(1, response.balances.len());
    let balance = response.balances.first().unwrap();
    let currency = &balance.currency;
    assert_eq!(CURRENCY, currency.symbol);
    assert_eq!(NUM_DECIMALS, currency.decimals);
    assert_eq!(DEFAULT_FUNDED_COINS, u64::from_str(&balance.value).unwrap());
}

async fn get_account_balance_once_ready(
    rosetta_client: &RosettaClient,
    account: AccountAddress,
) -> anyhow::Result<AccountBalanceResponse> {
    let mut result = Err(anyhow::Error::msg("Failed to get balance"));
    for _ in 1..10 {
        result = rosetta_client
            .account_balance_simple(account, ChainId::test())
            .await;
        if result.is_ok() {
            break;
        }
        tokio::time::sleep(Duration::from_millis(200)).await;
    }

    result
}
<commit_msg>[smoke-test] Re-enable rosetta test<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{aptos_cli::launch_faucet, smoke_test_environment::new_local_swarm_with_aptos};
use aptos::{account::create::DEFAULT_FUNDED_COINS, test::CliTestFramework};
use aptos_config::config::ApiConfig;
use aptos_rosetta::{client::RosettaClient, types::AccountBalanceResponse, CURRENCY, NUM_DECIMALS};
use aptos_types::{account_address::AccountAddress, chain_id::ChainId};
use forge::{LocalSwarm, Node};
use std::{str::FromStr, time::Duration};

pub async fn setup_test(num_nodes: usize) -> (LocalSwarm, CliTestFramework, RosettaClient) {
    let swarm = new_local_swarm_with_aptos(num_nodes).await;
    let chain_id = swarm.chain_id();
    let validator = swarm.validators().next().unwrap();
    let root_key = swarm.root_key();
    let _faucet = launch_faucet(validator.rest_api_endpoint(), root_key, chain_id);

    // Connect the operator tool to the node's JSON RPC API
    let tool = CliTestFramework::new(
        validator.rest_api_endpoint(),
        "http://localhost:9996".parse().unwrap(),
        2,
    )
    .await;

    // And the client
    let rosetta_socket_addr = "127.0.0.1:9997";
    let rosetta_url = format!("http://{}", rosetta_socket_addr).parse().unwrap();
    let rosetta_client = RosettaClient::new(rosetta_url);
    let rosetta_socket_addr = "127.0.0.1:9997";
    let api_config = ApiConfig {
        enabled: true,
        address: rosetta_socket_addr.parse().unwrap(),
        tls_cert_path: None,
        tls_key_path: None,
        content_length_limit: None,
    };

    // Start the server
    let _ = aptos_rosetta::bootstrap_async(
        swarm.chain_id(),
        api_config,
        aptos_rest_client::Client::new(validator.rest_api_endpoint()),
    )
    .await
    .unwrap();

    (swarm, tool, rosetta_client)
}

#[tokio::test]
async fn test_account_balance() {
    let (_swarm, cli, rosetta_client) = setup_test(1).await;

    cli.create_account_with_faucet(0).await.unwrap();
    let account = CliTestFramework::account_id(0);

    let response = get_account_balance_once_ready(&rosetta_client, account)
        .await
        .unwrap();
    assert_eq!(1, response.balances.len());
    let balance = response.balances.first().unwrap();
    let currency = &balance.currency;
    assert_eq!(CURRENCY, currency.symbol);
    assert_eq!(NUM_DECIMALS, currency.decimals);
    assert_eq!(DEFAULT_FUNDED_COINS, u64::from_str(&balance.value).unwrap());
}

async fn get_account_balance_once_ready(
    rosetta_client: &RosettaClient,
    account: AccountAddress,
) -> anyhow::Result<AccountBalanceResponse> {
    let mut result = Err(anyhow::Error::msg("Failed to get balance"));
    for _ in 1..10 {
        result = rosetta_client
            .account_balance_simple(account, ChainId::test())
            .await;
        if result.is_ok() {
            break;
        }
        tokio::time::sleep(Duration::from_millis(200)).await;
    }

    result
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate tempdir;
extern crate zip;

use std::env;
use std::fs;
use std::io::{
    self,
    Cursor,
};
use std::path::{
    Path,
    PathBuf,
};

use curl::easy::Easy;
use tempdir::TempDir;
use zip::ZipArchive;

const VERSION: &'static str = "3.4.0";

fn main() {
    if env_contains_protoc() { return; }

    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR environment variable is invalid"));
    let protoc_dir = out_dir.join("protoc");

    // If the protoc directory doesn't already exist from a previous build, download protoc.
    if !protoc_dir.exists() {
        // The unzipping done by download_protoc is not atomic, so to avoid failing halfway through
        // and leaving trash state, download/unzip to a temporary directory, then rename.
        let tempdir = TempDir::new_in(&out_dir, "protoc").expect("failed to create temporary directory");
        download_protoc(tempdir.path());
        fs::rename(&tempdir.into_path(), &protoc_dir).expect("unable to move temporary directory");
    }
    let mut protoc = protoc_dir.join("bin");
    protoc.push("protoc");
    protoc.set_extension(env::consts::EXE_EXTENSION);

    println!("cargo:rustc-env=PROTOC={}", protoc.display());
    println!("cargo:rustc-env=PROTOC_INCLUDE={}", protoc_dir.join("include").display());
}

/// Returns `true` if the environment already contains the `PROTOC` and `PROTOC_INCLUDE` variables.
fn env_contains_protoc() -> bool {
    let protoc = match env::var("PROTOC") {
        Ok(val) => PathBuf::from(val),
        Err(env::VarError::NotPresent) => return false,
        Err(env::VarError::NotUnicode(..)) => panic!("PROTOC environment variable is not valid UTF-8"),
    };

    let protoc_include = match env::var("PROTOC_INCLUDE") {
        Ok(val) => PathBuf::from(val),
        Err(env::VarError::NotPresent) => panic!("PROTOC_INCLUDE environment variable not set (PROTOC is set)"),
        Err(env::VarError::NotUnicode(..)) => panic!("PROTOC_INCLUDE environment variable is not valid UTF-8"),
    };

    if !protoc.exists() {
        panic!("PROTOC environment variable points to non-existent file ({:?})", protoc);
    }
    if !protoc_include.exists() {
        panic!("PROTOC_INCLUDE environment variable points to non-existent directory ({:?})",
               protoc_include);
    }

    // Even if PROTOC and PROTOC_INCLUDE are set in the environment, still
    println!("cargo:rustc-env=PROTOC={}", protoc.display());
    println!("cargo:rustc-env=PROTOC_INCLUDE={}", protoc_include.display());
    true
}

/// Downloads and unpacks the protoc package for the current architecture to the target path.
/// Returns the paths to `protoc` and the include directory.
fn download_protoc(target: &Path) {
    let url = protoc_url();
    let mut data = Vec::new();
    let mut handle = Easy::new();

    handle.url(&url).expect("failed to set URL");
    handle.follow_location(true).expect("failed to configure follow location");
    {
        let mut transfer = handle.transfer();
        transfer.write_function(|new_data| {
            data.extend_from_slice(new_data);
            Ok(new_data.len())
        }).expect("failed to transfer data");
        transfer.perform().expect("failed to perform transfer");
    }

    let mut archive = ZipArchive::new(Cursor::new(data)).expect("failed to open zip archive");

    for i in 0..archive.len() {
        let mut src = archive.by_index(i).expect("failed to index into zip archive");

        let mut path = target.to_owned();
        path.push(src.name());

        if src.name().ends_with('/') {
            fs::create_dir(&path).unwrap();
        } else {
            let mut dest = &mut fs::File::create(&path).unwrap();
            io::copy(&mut src, &mut dest).unwrap();

            #[cfg(unix)]
            fn convert_permissions(mode: u32) -> Option<fs::Permissions> {
                use std::os::unix::fs::PermissionsExt;
                Some(fs::Permissions::from_mode(mode))
            }
            #[cfg(not(unix))]
            fn convert_permissions(_mode: u32) -> Option<fs::Permissions> {
                None
            }
            if let Some(permissions) = src.unix_mode().and_then(convert_permissions) {
                fs::set_permissions(&path, permissions).unwrap();
            }
        }
    }
}

fn protoc_url() -> String {
    let platform = match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86")    => "linux-x86_32",
        ("linux", "x86_64") => "linux-x86_64",
        ("macos", "x86")    => "osx-x86_32",
        ("macos", "x86_64") => "osx-x86_64",
        ("windows", _)      => "win32",
        _ => panic!("no precompiled protoc binary for the current platform: {}-{}",
                    env::consts::OS, env::consts::ARCH),
    };
    format!("https://github.com/google/protobuf/releases/download/v{version}/protoc-{version}-{platform}.zip",
            version = VERSION,
            platform = platform)
}
<commit_msg>prost-build: add rerun-if-env-changed directives<commit_after>extern crate curl;
extern crate tempdir;
extern crate zip;

use std::env;
use std::fs;
use std::io::{
    self,
    Cursor,
};
use std::path::{
    Path,
    PathBuf,
};

use curl::easy::Easy;
use tempdir::TempDir;
use zip::ZipArchive;

const VERSION: &'static str = "3.4.0";

fn main() {
    if env_contains_protoc() { return; }

    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR environment variable is invalid"));
    let protoc_dir = out_dir.join("protoc");

    // If the protoc directory doesn't already exist from a previous build, download protoc.
    if !protoc_dir.exists() {
        // The unzipping done by download_protoc is not atomic, so to avoid failing halfway through
        // and leaving trash state, download/unzip to a temporary directory, then rename.
        let tempdir = TempDir::new_in(&out_dir, "protoc").expect("failed to create temporary directory");
        download_protoc(tempdir.path());
        fs::rename(&tempdir.into_path(), &protoc_dir).expect("unable to move temporary directory");
    }
    let mut protoc = protoc_dir.join("bin");
    protoc.push("protoc");
    protoc.set_extension(env::consts::EXE_EXTENSION);

    println!("cargo:rustc-env=PROTOC={}", protoc.display());
    println!("cargo:rustc-env=PROTOC_INCLUDE={}", protoc_dir.join("include").display());
    println!("cargo:rerun-if-env-changed=PROTOC");
    println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE");
}

/// Returns `true` if the environment already contains the `PROTOC` and `PROTOC_INCLUDE` variables.
fn env_contains_protoc() -> bool {
    let protoc = match env::var("PROTOC") {
        Ok(val) => PathBuf::from(val),
        Err(env::VarError::NotPresent) => return false,
        Err(env::VarError::NotUnicode(..)) => panic!("PROTOC environment variable is not valid UTF-8"),
    };

    let protoc_include = match env::var("PROTOC_INCLUDE") {
        Ok(val) => PathBuf::from(val),
        Err(env::VarError::NotPresent) => panic!("PROTOC_INCLUDE environment variable not set (PROTOC is set)"),
        Err(env::VarError::NotUnicode(..)) => panic!("PROTOC_INCLUDE environment variable is not valid UTF-8"),
    };

    if !protoc.exists() {
        panic!("PROTOC environment variable points to non-existent file ({:?})", protoc);
    }
    if !protoc_include.exists() {
        panic!("PROTOC_INCLUDE environment variable points to non-existent directory ({:?})",
               protoc_include);
    }

    // Even if PROTOC and PROTOC_INCLUDE are set in the environment, still
    println!("cargo:rustc-env=PROTOC={}", protoc.display());
    println!("cargo:rustc-env=PROTOC_INCLUDE={}", protoc_include.display());
    println!("cargo:rerun-if-env-changed=PROTOC");
    println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE");
    true
}

/// Downloads and unpacks the protoc package for the current architecture to the target path.
/// Returns the paths to `protoc` and the include directory.
fn download_protoc(target: &Path) {
    let url = protoc_url();
    let mut data = Vec::new();
    let mut handle = Easy::new();

    handle.url(&url).expect("failed to set URL");
    handle.follow_location(true).expect("failed to configure follow location");
    {
        let mut transfer = handle.transfer();
        transfer.write_function(|new_data| {
            data.extend_from_slice(new_data);
            Ok(new_data.len())
        }).expect("failed to transfer data");
        transfer.perform().expect("failed to perform transfer");
    }

    let mut archive = ZipArchive::new(Cursor::new(data)).expect("failed to open zip archive");

    for i in 0..archive.len() {
        let mut src = archive.by_index(i).expect("failed to index into zip archive");

        let mut path = target.to_owned();
        path.push(src.name());

        if src.name().ends_with('/') {
            fs::create_dir(&path).unwrap();
        } else {
            let mut dest = &mut fs::File::create(&path).unwrap();
            io::copy(&mut src, &mut dest).unwrap();

            #[cfg(unix)]
            fn convert_permissions(mode: u32) -> Option<fs::Permissions> {
                use std::os::unix::fs::PermissionsExt;
                Some(fs::Permissions::from_mode(mode))
            }
            #[cfg(not(unix))]
            fn convert_permissions(_mode: u32) -> Option<fs::Permissions> {
                None
            }
            if let Some(permissions) = src.unix_mode().and_then(convert_permissions) {
                fs::set_permissions(&path, permissions).unwrap();
            }
        }
    }
}

fn protoc_url() -> String {
    let platform = match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86")    => "linux-x86_32",
        ("linux", "x86_64") => "linux-x86_64",
        ("macos", "x86")    => "osx-x86_32",
        ("macos", "x86_64") => "osx-x86_64",
        ("windows", _)      => "win32",
        _ => panic!("no precompiled protoc binary for the current platform: {}-{}",
                    env::consts::OS, env::consts::ARCH),
    };
    format!("https://github.com/google/protobuf/releases/download/v{version}/protoc-{version}-{platform}.zip",
            version = VERSION,
            platform = platform)
}
<|endoftext|>


<commit_before>// Copyright © 2018, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;

use cosmogony::{Zone, ZoneIndex};
use failure::Error;
use mimir::objects::Admin;
use mimir::rubber::{IndexSettings, Rubber};
use mimirsbrunn::osm_reader::admin;
use mimirsbrunn::osm_reader::osm_utils;
use mimirsbrunn::utils::normalize_weight;
use std::collections::BTreeMap;
use structopt::StructOpt;

trait IntoAdmin {
    fn into_admin(
        self,
        _: &BTreeMap<ZoneIndex, (String, Option<String>)>,
        langs: &[String],
        retrocompat_on_french_id: bool,
        max_weight: f64,
    ) -> Admin;
}

fn get_weight(tags: &osmpbfreader::Tags, center_tags: &osmpbfreader::Tags) -> f64 {
    // to have an admin weight we use the osm 'population' tag to priorize
    // the big zones over the small one.
    // Note: this tags is not often filled , so only some zones
    // will have a weight (but the main cities have it).
    tags.get("population")
        .and_then(|p| p.parse().ok())
        .or_else(|| center_tags.get("population")?.parse().ok())
        .unwrap_or(0.)
}

impl IntoAdmin for Zone {
    fn into_admin(
        self,
        zones_osm_id: &BTreeMap<ZoneIndex, (String, Option<String>)>,
        langs: &[String],
        french_id_retrocompatibility: bool,
        max_weight: f64,
    ) -> Admin {
        let insee = admin::read_insee(&self.tags).map(|s| s.to_owned());
        let zip_codes = admin::read_zip_codes(&self.tags);
        let label = self.label;
        let weight = get_weight(&self.tags, &self.center_tags);
        let center = self.center.map_or(mimir::Coord::default(), |c| {
            mimir::Coord::new(c.lng(), c.lat())
        });
        let format_id = |id, insee| {
            // for retrocompatibity reasons, Navitia needs the
            // french admins to have an id with the insee
            match insee {
                Some(insee) if french_id_retrocompatibility => format!("admin:fr:{}", insee),
                _ => format!("admin:osm:{}", id),
            }
        };
        let parent_osm_id = self
            .parent
            .and_then(|id| zones_osm_id.get(&id))
            .map(|(id, insee)| format_id(id, insee.as_ref()));
        Admin {
            id: format_id(&self.osm_id, insee.as_ref()),
            insee: insee.unwrap_or("".to_owned()),
            level: self.admin_level.unwrap_or(0),
            label: label,
            name: self.name,
            zip_codes: zip_codes,
            weight: normalize_weight(weight, max_weight),
            bbox: self.bbox,
            boundary: self.boundary,
            coord: center,
            zone_type: self.zone_type,
            parent_id: parent_osm_id,
            codes: osm_utils::get_osm_codes_from_tags(&self.tags),
            names: osm_utils::get_names_from_tags(&self.tags, &langs),
            labels: self
                .international_labels
                .into_iter()
                .filter(|(k, _)| langs.contains(&k))
                .collect(),
            distance: None,
        }
    }
}

fn send_to_es(
    admins: impl Iterator<Item = Admin>,
    cnx_string: &str,
    dataset: &str,
    index_settings: IndexSettings,
) -> Result<(), Error> {
    let mut rubber = Rubber::new(cnx_string);
    rubber.initialize_templates()?;
    let nb_admins = rubber.index(dataset, &index_settings, admins)?;
    info!("{} admins added.", nb_admins);
    Ok(())
}

fn read_zones(input: &str) -> Result<impl Iterator<Item = Zone>, Error> {
    Ok(cosmogony::read_zones_from_file(input)?.filter_map(|r| {
        r.map_err(|e| log::warn!("impossible to read zone: {}", e))
            .ok()
    }))
}

fn index_cosmogony(args: Args) -> Result<(), Error> {
    info!("building maps");

    let mut max_weight = 1.0;
    let mut cosmogony_id_to_osm_id = BTreeMap::new();
    for z in read_zones(&args.input)? {
        max_weight = f64::max(max_weight, get_weight(&z.tags, &z.center_tags));
        let insee = admin::read_insee(&z.tags).map(|s| s.to_owned());
        cosmogony_id_to_osm_id.insert(z.id.clone(), (z.osm_id.clone(), insee));
    }
    let max_weight = max_weight;
    let cosmogony_id_to_osm_id = cosmogony_id_to_osm_id;

    info!("importing cosmogony into Mimir");
    let admins = read_zones(&args.input)?.map(|z| {
        z.into_admin(
            &cosmogony_id_to_osm_id,
            &args.langs,
            args.french_id_retrocompatibility,
            max_weight,
        )
    });

    let index_settings = IndexSettings {
        nb_shards: args.nb_shards,
        nb_replicas: args.nb_replicas,
    };
    send_to_es(
        admins,
        &args.connection_string,
        &args.dataset,
        index_settings,
    )?;

    Ok(())
}

#[derive(StructOpt, Debug)]
struct Args {
    /// cosmogony file
    #[structopt(short = "i", long = "input")]
    input: String,
    /// Elasticsearch parameters.
    #[structopt(
        short = "c",
        long = "connection-string",
        default_value = "http://localhost:9200/munin"
    )]
    connection_string: String,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset", default_value = "fr")]
    dataset: String,
    /// Number of shards for the es index
    #[structopt(short = "s", long = "nb-shards", default_value = "1")]
    nb_shards: usize,
    /// Number of replicas for the es index
    #[structopt(short = "r", long = "nb-replicas", default_value = "1")]
    nb_replicas: usize,
    /// Languages codes, used to build i18n names and labels
    #[structopt(name = "lang", short, long)]
    langs: Vec<String>,
    /// Retrocompatibiilty on french admin id
    /// if activated, the french administrative regions will have an id like 'admin:fr:{insee}'
    /// instead of 'admin:osm:{osm_id}'
    #[structopt(long = "french-id-retrocompatibility")]
    french_id_retrocompatibility: bool,
}

fn main() {
    mimirsbrunn::utils::launch_run(index_cosmogony);
}
<commit_msg>Only use french retrocompatible id for cities<commit_after>// Copyright © 2018, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;

use cosmogony::{Zone, ZoneIndex};
use failure::Error;
use mimir::objects::Admin;
use mimir::rubber::{IndexSettings, Rubber};
use mimirsbrunn::osm_reader::admin;
use mimirsbrunn::osm_reader::osm_utils;
use mimirsbrunn::utils::normalize_weight;
use std::collections::BTreeMap;
use structopt::StructOpt;

trait IntoAdmin {
    fn into_admin(
        self,
        _: &BTreeMap<ZoneIndex, (String, Option<String>)>,
        langs: &[String],
        retrocompat_on_french_id: bool,
        max_weight: f64,
    ) -> Admin;
}

fn get_weight(tags: &osmpbfreader::Tags, center_tags: &osmpbfreader::Tags) -> f64 {
    // to have an admin weight we use the osm 'population' tag to priorize
    // the big zones over the small one.
    // Note: this tags is not often filled , so only some zones
    // will have a weight (but the main cities have it).
    tags.get("population")
        .and_then(|p| p.parse().ok())
        .or_else(|| center_tags.get("population")?.parse().ok())
        .unwrap_or(0.)
}

impl IntoAdmin for Zone {
    fn into_admin(
        self,
        zones_osm_id: &BTreeMap<ZoneIndex, (String, Option<String>)>,
        langs: &[String],
        french_id_retrocompatibility: bool,
        max_weight: f64,
    ) -> Admin {
        let insee = admin::read_insee(&self.tags).map(|s| s.to_owned());
        let zip_codes = admin::read_zip_codes(&self.tags);
        let label = self.label;
        let weight = get_weight(&self.tags, &self.center_tags);
        let center = self.center.map_or(mimir::Coord::default(), |c| {
            mimir::Coord::new(c.lng(), c.lat())
        });
        let format_id = |id, insee| {
            // for retrocompatibity reasons, Navitia needs the
            // french admins to have an id with the insee for cities
            match insee {
                Some(insee) if french_id_retrocompatibility => format!("admin:fr:{}", insee),
                _ => format!("admin:osm:{}", id),
            }
        };
        let parent_osm_id = self
            .parent
            .and_then(|id| zones_osm_id.get(&id))
            .map(|(id, insee)| format_id(id, insee.as_ref()));
        Admin {
            id: zones_osm_id
                .get(&self.id)
                .map(|(id, insee)| format_id(id, insee.as_ref()))
                .expect("unable to find zone id in zones_osm_id"),
            insee: insee.unwrap_or("".to_owned()),
            level: self.admin_level.unwrap_or(0),
            label: label,
            name: self.name,
            zip_codes: zip_codes,
            weight: normalize_weight(weight, max_weight),
            bbox: self.bbox,
            boundary: self.boundary,
            coord: center,
            zone_type: self.zone_type,
            parent_id: parent_osm_id,
            codes: osm_utils::get_osm_codes_from_tags(&self.tags),
            names: osm_utils::get_names_from_tags(&self.tags, &langs),
            labels: self
                .international_labels
                .into_iter()
                .filter(|(k, _)| langs.contains(&k))
                .collect(),
            distance: None,
        }
    }
}

fn send_to_es(
    admins: impl Iterator<Item = Admin>,
    cnx_string: &str,
    dataset: &str,
    index_settings: IndexSettings,
) -> Result<(), Error> {
    let mut rubber = Rubber::new(cnx_string);
    rubber.initialize_templates()?;
    let nb_admins = rubber.index(dataset, &index_settings, admins)?;
    info!("{} admins added.", nb_admins);
    Ok(())
}

fn read_zones(input: &str) -> Result<impl Iterator<Item = Zone>, Error> {
    Ok(cosmogony::read_zones_from_file(input)?.filter_map(|r| {
        r.map_err(|e| log::warn!("impossible to read zone: {}", e))
            .ok()
    }))
}

fn index_cosmogony(args: Args) -> Result<(), Error> {
    info!("building maps");
    use cosmogony::zone::ZoneType::City;

    let mut max_weight = 1.0;
    let mut cosmogony_id_to_osm_id = BTreeMap::new();
    for z in read_zones(&args.input)? {
        max_weight = f64::max(max_weight, get_weight(&z.tags, &z.center_tags));
        let insee = match z.zone_type {
            Some(City) => admin::read_insee(&z.tags).map(|s| s.to_owned()),
            _ => None,
        };
        cosmogony_id_to_osm_id.insert(z.id.clone(), (z.osm_id.clone(), insee));
    }
    let max_weight = max_weight;
    let cosmogony_id_to_osm_id = cosmogony_id_to_osm_id;

    info!("importing cosmogony into Mimir");
    let admins = read_zones(&args.input)?.map(|z| {
        z.into_admin(
            &cosmogony_id_to_osm_id,
            &args.langs,
            args.french_id_retrocompatibility,
            max_weight,
        )
    });

    let index_settings = IndexSettings {
        nb_shards: args.nb_shards,
        nb_replicas: args.nb_replicas,
    };
    send_to_es(
        admins,
        &args.connection_string,
        &args.dataset,
        index_settings,
    )?;

    Ok(())
}

#[derive(StructOpt, Debug)]
struct Args {
    /// cosmogony file
    #[structopt(short = "i", long = "input")]
    input: String,
    /// Elasticsearch parameters.
    #[structopt(
        short = "c",
        long = "connection-string",
        default_value = "http://localhost:9200/munin"
    )]
    connection_string: String,
    /// Name of the dataset.
    #[structopt(short = "d", long = "dataset", default_value = "fr")]
    dataset: String,
    /// Number of shards for the es index
    #[structopt(short = "s", long = "nb-shards", default_value = "1")]
    nb_shards: usize,
    /// Number of replicas for the es index
    #[structopt(short = "r", long = "nb-replicas", default_value = "1")]
    nb_replicas: usize,
    /// Languages codes, used to build i18n names and labels
    #[structopt(name = "lang", short, long)]
    langs: Vec<String>,
    /// Retrocompatibiilty on french admin id
    /// if activated, the french administrative regions will have an id like 'admin:fr:{insee}'
    /// instead of 'admin:osm:{osm_id}'
    #[structopt(long = "french-id-retrocompatibility")]
    french_id_retrocompatibility: bool,
}

fn main() {
    mimirsbrunn::utils::launch_run(index_cosmogony);
}
<|endoftext|>


<commit_before>use parking_lot::{Mutex, MutexGuard};
use std::{fmt, sync::Arc};

#[derive(Clone, Default)]
pub(crate) struct ConsumerStatus(Arc<Mutex<ConsumerStatusInner>>);

impl ConsumerStatus {
    pub(crate) fn state(&self) -> ConsumerState {
        self.lock().state()
    }

    pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, ConsumerStatusInner>> {
        self.0.try_lock()
    }

    pub(crate) fn lock(&self) -> MutexGuard<'_, ConsumerStatusInner> {
        self.0.lock()
    }
}

impl fmt::Debug for ConsumerStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("ConsumerStatus");
        if let Some(inner) = self.try_lock() {
            debug.field("state", &inner.state());
        }
        debug.finish()
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConsumerState {
    Active,
    ActiveWithDelegate,
    Canceling,
    Canceled,
}

impl ConsumerState {
    pub fn is_active(self) -> bool {
        match self {
            ConsumerState::Active | ConsumerState::ActiveWithDelegate => true,
            _ => false,
        }
    }
}

impl Default for ConsumerState {
    fn default() -> Self {
        Self::Active
    }
}

#[derive(Default)]
pub(crate) struct ConsumerStatusInner(ConsumerState);

impl ConsumerStatusInner {
    pub(crate) fn state(&self) -> ConsumerState {
        self.0
    }

    pub(crate) fn set_delegate(&mut self) {
        if self.0 == ConsumerState::Active {
            self.0 = ConsumerState::ActiveWithDelegate;
        }
    }

    pub(crate) fn start_cancel(&mut self) {
        self.0 = ConsumerState::Canceling;
    }

    pub(crate) fn cancel(&mut self) {
        self.0 = ConsumerState::Canceled;
    }
}
<commit_msg>clippy<commit_after>use parking_lot::{Mutex, MutexGuard};
use std::{fmt, sync::Arc};

#[derive(Clone, Default)]
pub(crate) struct ConsumerStatus(Arc<Mutex<ConsumerStatusInner>>);

impl ConsumerStatus {
    pub(crate) fn state(&self) -> ConsumerState {
        self.lock().state()
    }

    pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, ConsumerStatusInner>> {
        self.0.try_lock()
    }

    pub(crate) fn lock(&self) -> MutexGuard<'_, ConsumerStatusInner> {
        self.0.lock()
    }
}

impl fmt::Debug for ConsumerStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("ConsumerStatus");
        if let Some(inner) = self.try_lock() {
            debug.field("state", &inner.state());
        }
        debug.finish()
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ConsumerState {
    Active,
    ActiveWithDelegate,
    Canceling,
    Canceled,
}

impl ConsumerState {
    pub fn is_active(self) -> bool {
        matches!(
            self,
            ConsumerState::Active | ConsumerState::ActiveWithDelegate
        )
    }
}

impl Default for ConsumerState {
    fn default() -> Self {
        Self::Active
    }
}

#[derive(Default)]
pub(crate) struct ConsumerStatusInner(ConsumerState);

impl ConsumerStatusInner {
    pub(crate) fn state(&self) -> ConsumerState {
        self.0
    }

    pub(crate) fn set_delegate(&mut self) {
        if self.0 == ConsumerState::Active {
            self.0 = ConsumerState::ActiveWithDelegate;
        }
    }

    pub(crate) fn start_cancel(&mut self) {
        self.0 = ConsumerState::Canceling;
    }

    pub(crate) fn cancel(&mut self) {
        self.0 = ConsumerState::Canceled;
    }
}
<|endoftext|>


<commit_before>use std::num::{One, Zero, IntConvertible, ToStrRadix};
use bigint_helper::*;
use extra::bigint::BigInt;

pub struct Rational {
    priv d: BigInt,
    priv n: BigInt,
}

impl Rational {
    pub fn new(d: BigInt, n: BigInt) -> Rational {
        if n.is_zero() {
            fail!(~"divide by zero");
        }

        let g = d.gcd(&n);

        if n.is_negative() {
            Rational { d: -d/g, n: -n/g }
        } else {
            Rational { d: d/g, n: n/g }
        }
    }

    pub fn new_int(new_d: int, new_n: int) -> Rational {
        let d = IntConvertible::from_int::<BigInt>(new_d);
        let n = IntConvertible::from_int::<BigInt>(new_n);

        Rational::new(d, n)
    }

    pub fn denominator<'r>(&'r self) -> &'r BigInt {
        &self.d
    }

    pub fn numerator<'r>(&'r self) -> &'r BigInt {
        &self.n
    }

    pub fn to_float<T:Float + NumCast + Zero>(&self) -> T {
        let d:T = bigint_to_float(&self.d);
        let n:T = bigint_to_float(&self.n);
        d / n
    }

    pub fn from_float<T:Float>(f: T) -> Rational {
        match float_disassemble(f) {
            None => fail!(~"f is not normal float"),
            Some((mantissa, exp)) => if exp < 0 {
                    let n = One::one::<BigInt>() << (-exp as uint);
                    Rational::new(mantissa, n)
                } else {
                    let d = mantissa << (exp as uint);
                    Rational::new(d, One::one())
                }
        }
    }
}

impl Round for Rational {
    fn floor(&self) -> Rational {
        Rational {
            d: self.d.div_floor(&self.n),
            n: One::one(),
        }
    }

    fn ceil(&self) -> Rational {
        Rational {
            d: -((-self.d).div_floor(&self.n)),
            n: One::one(),
        }
    }

    fn round(&self) -> Rational {
        Rational {
            d: IntConvertible::from_int::<BigInt>(self.to_float::<f64>().round() as int),
            n: One::one(),
        }
    }

    fn trunc(&self) -> Rational {
        Rational {
            d: IntConvertible::from_int::<BigInt>(self.to_float::<f64>().trunc() as int),
            n: One::one(),
        }
    }

    fn fract(&self) -> Rational {
        Rational {
            d: IntConvertible::from_int::<BigInt>(self.to_float::<f64>().fract() as int),
            n: One::one(),
        }
    }
}

impl One for Rational {
    fn one() -> Rational {
        Rational {
            d: One::one(),
            n: One::one(),
        }
    }
}

impl Zero for Rational {
    fn zero() -> Rational {
        Rational {
            d: Zero::zero(),
            n: One::one(),
        }
    }

    fn is_zero(&self) -> bool {
        self.d.is_zero()
    }
}

impl Signed for Rational {
    fn abs(&self) -> Rational {
        Rational { d: self.d.abs(), n: self.n.clone() }
    }

    fn abs_sub(&self, other: &Rational) -> Rational {
        if *self <= *other {
            Zero::zero()
        } else {
            *self - *other
        }
    }

    fn signum(&self) -> Rational {
        Rational { d: self.d.signum(), n: One::one() }
    }

    fn is_positive(&self) -> bool {
        self.d.is_positive()
    }

    fn is_negative(&self) -> bool {
        self.d.is_negative()
    }
}

impl Clone for Rational {
    fn clone(&self) -> Rational {
        Rational {
            d: self.d.clone(),
            n: self.n.clone(),
        }
    }
}

impl Neg<Rational> for Rational {
    fn neg(&self) -> Rational {
        Rational {
            d: -self.d,
            n: self.n.clone(),
        }
    }
}

impl Eq for Rational {
    fn eq(&self, other: &Rational) -> bool {
        self.d == other.d && self.n == other.n
    }
    fn ne(&self, other: &Rational) -> bool {
        self.d != other.d || self.n != other.n
    }
}

impl Ord for Rational {
    fn lt(&self, other: &Rational) -> bool {
        self.d * other.n < other.d * self.n
    }
    fn le(&self, other: &Rational) -> bool {
        self.d * other.n <= other.d * self.n
    }
    fn gt(&self, other: &Rational) -> bool {
        self.d * other.n > other.d * self.n
    }
    fn ge(&self, other: &Rational) -> bool {
        self.d * other.n >= other.d * self.n
    }
}

impl Add<Rational, Rational> for Rational {
    fn add(&self, rhs: &Rational) -> Rational {
        let g = self.n.gcd(&rhs.n);
        let ln = self.n / g;
        let rn = rhs.n / g;
        Rational {
            d: self.d * rn + rhs.d * ln,
            n: self.n * rn,
        }
    }
}

impl Sub<Rational, Rational> for Rational {
    fn sub(&self, rhs: &Rational) -> Rational {
        let g = self.n.gcd(&rhs.n);
        let ln = self.n / g;
        let rn = rhs.n / g;
        Rational {
            d: self.d * rn - rhs.d * ln,
            n: self.n * rn,
        }
    }
}

impl Mul<Rational, Rational> for Rational {
    fn mul(&self, rhs: &Rational) -> Rational {
        let d = self.d * rhs.d;
        let n = self.n * rhs.n;
        let g = d.gcd(&n);
        Rational {
            d: d / g,
            n: n / g,
        }
    }
}

impl Div<Rational, Rational> for Rational {
    fn div(&self, rhs: &Rational) -> Rational {
        let d = self.d * rhs.n;
        let n = self.n * rhs.d;
        let g = d.gcd(&n);
        Rational {
            d: d / g,
            n: n / g,
        }
    }
}

impl Rem<Rational, Rational> for Rational {
    fn rem(&self, rhs: &Rational) -> Rational {
        let q = self / *rhs;
        let int_q = q.d / q.n;
        self - rhs * Rational { d: int_q, n: One::one() }
    }
}

impl Num for Rational;

impl ToStr for Rational {
    fn to_str(&self) -> ~str {
        self.to_str_radix(10)
    }
}

impl ToStrRadix for Rational {
    fn to_str_radix(&self, radix: uint) -> ~str {
        if self.n == One::one() {
            self.d.to_str_radix(radix)
        } else {
            self.d.to_str_radix(radix) + "/" + self.n.to_str_radix(radix)
        }
    }
}
<commit_msg>fix implementation for trunc and fract<commit_after>use std::num::{One, Zero, IntConvertible, ToStrRadix};
use bigint_helper::*;
use extra::bigint::BigInt;

pub struct Rational {
    priv d: BigInt,
    priv n: BigInt,
}

impl Rational {
    pub fn new(d: BigInt, n: BigInt) -> Rational {
        if n.is_zero() {
            fail!(~"divide by zero");
        }

        let g = d.gcd(&n);

        if n.is_negative() {
            Rational { d: -d/g, n: -n/g }
        } else {
            Rational { d: d/g, n: n/g }
        }
    }

    pub fn new_int(new_d: int, new_n: int) -> Rational {
        let d = IntConvertible::from_int::<BigInt>(new_d);
        let n = IntConvertible::from_int::<BigInt>(new_n);

        Rational::new(d, n)
    }

    pub fn denominator<'r>(&'r self) -> &'r BigInt {
        &self.d
    }

    pub fn numerator<'r>(&'r self) -> &'r BigInt {
        &self.n
    }

    pub fn to_float<T:Float + NumCast + Zero>(&self) -> T {
        let d:T = bigint_to_float(&self.d);
        let n:T = bigint_to_float(&self.n);
        d / n
    }

    pub fn from_float<T:Float>(f: T) -> Rational {
        match float_disassemble(f) {
            None => fail!(~"f is not normal float"),
            Some((mantissa, exp)) => if exp < 0 {
                    let n = One::one::<BigInt>() << (-exp as uint);
                    Rational::new(mantissa, n)
                } else {
                    let d = mantissa << (exp as uint);
                    Rational::new(d, One::one())
                }
        }
    }
}

impl Round for Rational {
    fn floor(&self) -> Rational {
        Rational {
            d: self.d.div_floor(&self.n),
            n: One::one(),
        }
    }

    fn ceil(&self) -> Rational {
        Rational {
            d: -((-self.d).div_floor(&self.n)),
            n: One::one(),
        }
    }

    fn round(&self) -> Rational {
        Rational {
            d: IntConvertible::from_int::<BigInt>(self.to_float::<f64>().round() as int),
            n: One::one(),
        }
    }

    fn trunc(&self) -> Rational {
        Rational {
            d: self.d / self.n,
            n: One::one(),
        }
    }

    fn fract(&self) -> Rational {
        Rational {
            d: self.d % self.n,
            n: self.n.clone(),
        }
    }
}

impl One for Rational {
    fn one() -> Rational {
        Rational {
            d: One::one(),
            n: One::one(),
        }
    }
}

impl Zero for Rational {
    fn zero() -> Rational {
        Rational {
            d: Zero::zero(),
            n: One::one(),
        }
    }

    fn is_zero(&self) -> bool {
        self.d.is_zero()
    }
}

impl Signed for Rational {
    fn abs(&self) -> Rational {
        Rational { d: self.d.abs(), n: self.n.clone() }
    }

    fn abs_sub(&self, other: &Rational) -> Rational {
        if *self <= *other {
            Zero::zero()
        } else {
            *self - *other
        }
    }

    fn signum(&self) -> Rational {
        Rational { d: self.d.signum(), n: One::one() }
    }

    fn is_positive(&self) -> bool {
        self.d.is_positive()
    }

    fn is_negative(&self) -> bool {
        self.d.is_negative()
    }
}

impl Clone for Rational {
    fn clone(&self) -> Rational {
        Rational {
            d: self.d.clone(),
            n: self.n.clone(),
        }
    }
}

impl Neg<Rational> for Rational {
    fn neg(&self) -> Rational {
        Rational {
            d: -self.d,
            n: self.n.clone(),
        }
    }
}

impl Eq for Rational {
    fn eq(&self, other: &Rational) -> bool {
        self.d == other.d && self.n == other.n
    }
    fn ne(&self, other: &Rational) -> bool {
        self.d != other.d || self.n != other.n
    }
}

impl Ord for Rational {
    fn lt(&self, other: &Rational) -> bool {
        self.d * other.n < other.d * self.n
    }
    fn le(&self, other: &Rational) -> bool {
        self.d * other.n <= other.d * self.n
    }
    fn gt(&self, other: &Rational) -> bool {
        self.d * other.n > other.d * self.n
    }
    fn ge(&self, other: &Rational) -> bool {
        self.d * other.n >= other.d * self.n
    }
}

impl Add<Rational, Rational> for Rational {
    fn add(&self, rhs: &Rational) -> Rational {
        let g = self.n.gcd(&rhs.n);
        let ln = self.n / g;
        let rn = rhs.n / g;
        Rational {
            d: self.d * rn + rhs.d * ln,
            n: self.n * rn,
        }
    }
}

impl Sub<Rational, Rational> for Rational {
    fn sub(&self, rhs: &Rational) -> Rational {
        let g = self.n.gcd(&rhs.n);
        let ln = self.n / g;
        let rn = rhs.n / g;
        Rational {
            d: self.d * rn - rhs.d * ln,
            n: self.n * rn,
        }
    }
}

impl Mul<Rational, Rational> for Rational {
    fn mul(&self, rhs: &Rational) -> Rational {
        let d = self.d * rhs.d;
        let n = self.n * rhs.n;
        let g = d.gcd(&n);
        Rational {
            d: d / g,
            n: n / g,
        }
    }
}

impl Div<Rational, Rational> for Rational {
    fn div(&self, rhs: &Rational) -> Rational {
        let d = self.d * rhs.n;
        let n = self.n * rhs.d;
        let g = d.gcd(&n);
        Rational {
            d: d / g,
            n: n / g,
        }
    }
}

impl Rem<Rational, Rational> for Rational {
    fn rem(&self, rhs: &Rational) -> Rational {
        let q = self / *rhs;
        let int_q = q.d / q.n;
        self - rhs * Rational { d: int_q, n: One::one() }
    }
}

impl Num for Rational;

impl ToStr for Rational {
    fn to_str(&self) -> ~str {
        self.to_str_radix(10)
    }
}

impl ToStrRadix for Rational {
    fn to_str_radix(&self, radix: uint) -> ~str {
        if self.n == One::one() {
            self.d.to_str_radix(radix)
        } else {
            self.d.to_str_radix(radix) + "/" + self.n.to_str_radix(radix)
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(asm)]
#![feature(lang_items)]
#![allow(unknown_lints)]

use ::log::{error, info, trace, LevelFilter};

mod debug;
pub mod interrupt_controller;
mod interrupts;
mod isr;
mod msr;
mod panic;
mod register_state;
pub mod segmentation;
mod vcpu;
mod vmcs;
mod vmcs_dump;
mod vmcs_fields;
mod vmexit_handlers;
mod vmexit_reasons;
pub mod vmx;
use pcuart::logger;

pub static LOGGER: logger::UartLogger = logger::UartLogger::new(pcuart::UartComPort::Com1);
pub static UNSYNCHRONIZED_LOGGER: logger::UnsynchronizedUartLogger =
    logger::UnsynchronizedUartLogger::new(pcuart::UartComPort::Com1);

#[derive(Debug)]
#[repr(C)]
pub struct VCpu {
    pub this_vcpu: *mut VCpu,
    pub vmxon_region: *mut u32,
    pub vmcs: *mut u32,
    pub vmxon_region_phys: u64,
    pub vmcs_phys: u64,
    pub vmxon_region_size: usize,
    pub vmcs_size: usize,
    pub loaded_successfully: bool,
    pub stack_base: *mut u32,
    pub stack_size: usize,
    pub stack_top: *mut u32,
    pub host_gdt_base: *mut u64,
    pub host_gdt_limit: u64,
    pub virtual_local_interrupt_controller:
        *mut interrupt_controller::VirtualLocalInterruptController,
    pub msr_bitmap: u64,
    pub tr_base: u64,
    pub tr_selector: u16,
}

#[no_mangle]
pub extern "C" fn rustyvisor_load() -> i32 {
    let logger_result = log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Trace));
    match logger_result {
        Ok(()) => {}
        Err(_) => return -1,
    }

    info!("{}", "rustyvisor_load");

    interrupts::init_interrupt_handlers(vmx::read_cs());

    #[cfg(feature = "runtime_tests")]
    runtime_tests();

    0
}

#[no_mangle]
pub extern "C" fn rustyvisor_core_load(data: &VCpu) -> i32 {
    trace!(
        "VCPU in rustyvisor_core_load {:x?} {:x?}\r\n",
        data,
        data as *const VCpu
    );
    trace!("Enabling vmx");
    if vmx::enable(
        data.vmxon_region,
        data.vmxon_region_phys,
        data.vmxon_region_size,
    )
    .is_err()
    {
        error!("Failed to enable VMX");
        return -1;
    }
    trace!(
        "VCPU in rustyvisor_core_load enable {:x?} {:x?}\r\n",
        data,
        data as *const VCpu
    );

    trace!("Vmx enabled");
    trace!("Loading vmm {:x?}", data);
    if vmx::load_vm(data).is_err() {
        error!("Failed to load VMX");
        return 1;
    }
    0
}

#[no_mangle]
pub extern "C" fn rustyvisor_core_unload() {
    info!("Core unload");
    vmx::unload_vm();
    vmx::disable();
}

#[no_mangle]
pub extern "C" fn rustyvisor_unload() {
    info!("Hypervisor unloaded.");
}

#[cfg(feature = "runtime_tests")]
fn runtime_tests() {
    info!("Executing runtime tests...");
    info!("Runtime tests succeeded");
}
<commit_msg>Fix types for vcpu stack pointers<commit_after>#![no_std]
#![feature(asm)]
#![feature(lang_items)]
#![allow(unknown_lints)]

use ::log::{error, info, trace, LevelFilter};

mod debug;
pub mod interrupt_controller;
mod interrupts;
mod isr;
mod msr;
mod panic;
mod register_state;
pub mod segmentation;
mod vcpu;
mod vmcs;
mod vmcs_dump;
mod vmcs_fields;
mod vmexit_handlers;
mod vmexit_reasons;
pub mod vmx;
use pcuart::logger;

pub static LOGGER: logger::UartLogger = logger::UartLogger::new(pcuart::UartComPort::Com1);
pub static UNSYNCHRONIZED_LOGGER: logger::UnsynchronizedUartLogger =
    logger::UnsynchronizedUartLogger::new(pcuart::UartComPort::Com1);

#[derive(Debug)]
#[repr(C)]
pub struct VCpu {
    pub this_vcpu: *mut VCpu,
    pub vmxon_region: *mut u32,
    pub vmcs: *mut u32,
    pub vmxon_region_phys: u64,
    pub vmcs_phys: u64,
    pub vmxon_region_size: usize,
    pub vmcs_size: usize,
    pub loaded_successfully: bool,
    pub stack_base: *mut u8,
    pub stack_size: usize,
    pub stack_top: *mut u8,
    pub host_gdt_base: *mut u64,
    pub host_gdt_limit: u64,
    pub virtual_local_interrupt_controller:
        *mut interrupt_controller::VirtualLocalInterruptController,
    pub msr_bitmap: u64,
    pub tr_base: u64,
    pub tr_selector: u16,
}

#[no_mangle]
pub extern "C" fn rustyvisor_load() -> i32 {
    let logger_result = log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Trace));
    match logger_result {
        Ok(()) => {}
        Err(_) => return -1,
    }

    info!("{}", "rustyvisor_load");

    interrupts::init_interrupt_handlers(vmx::read_cs());

    #[cfg(feature = "runtime_tests")]
    runtime_tests();

    0
}

#[no_mangle]
pub extern "C" fn rustyvisor_core_load(data: &VCpu) -> i32 {
    trace!(
        "VCPU in rustyvisor_core_load {:x?} {:x?}\r\n",
        data,
        data as *const VCpu
    );
    trace!("Enabling vmx");
    if vmx::enable(
        data.vmxon_region,
        data.vmxon_region_phys,
        data.vmxon_region_size,
    )
    .is_err()
    {
        error!("Failed to enable VMX");
        return -1;
    }
    trace!(
        "VCPU in rustyvisor_core_load enable {:x?} {:x?}\r\n",
        data,
        data as *const VCpu
    );

    trace!("Vmx enabled");
    trace!("Loading vmm {:x?}", data);
    if vmx::load_vm(data).is_err() {
        error!("Failed to load VMX");
        return 1;
    }
    0
}

#[no_mangle]
pub extern "C" fn rustyvisor_core_unload() {
    info!("Core unload");
    vmx::unload_vm();
    vmx::disable();
}

#[no_mangle]
pub extern "C" fn rustyvisor_unload() {
    info!("Hypervisor unloaded.");
}

#[cfg(feature = "runtime_tests")]
fn runtime_tests() {
    info!("Executing runtime tests...");
    info!("Runtime tests succeeded");
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    mock_tree_store::MockTreeStore, restore::JellyfishMerkleRestore, JellyfishMerkleTree,
    TreeReader,
};
use crypto::HashValue;
use proptest::{collection::btree_map, prelude::*};
use std::collections::BTreeMap;
use types::{account_state_blob::AccountStateBlob, transaction::Version};

proptest! {
    #![proptest_config(ProptestConfig::with_cases(10))]

    #[test]
    fn test_restore_without_interruption(
        btree in btree_map(any::<HashValue>(), any::<AccountStateBlob>(), 1..1000),
    ) {
        let version = btree.len() as Version - 1;
        let expected_root_hash = get_expected_root_hash(&btree);

        // For this test, restore everything without interruption.
        let db = MockTreeStore::default();
        let mut restore = JellyfishMerkleRestore::new(&db, version).unwrap();
        for (key, value) in &btree {
            restore.add_chunk(vec![(*key, value.clone())]).unwrap();
        }
        restore.finish().unwrap();

        assert_success(&db, expected_root_hash, &btree, version);
    }

    #[test]
    fn test_restore_with_interruption(
        btree1 in btree_map(any::<HashValue>(), any::<AccountStateBlob>(), 1..500),
        btree2 in btree_map(any::<HashValue>(), any::<AccountStateBlob>(), 1..500),
    ) {
        let batch1_size = btree1.len();
        let all: BTreeMap<_, _> = btree1.into_iter().chain(btree2.into_iter()).collect();
        let version = all.len() as Version - 1;

        let expected_root_hash = get_expected_root_hash(&all);
        let batch1: Vec<_> = all.clone().into_iter().take(batch1_size).collect();
        let db = MockTreeStore::default();

        {
            let mut restore = JellyfishMerkleRestore::new(&db, version).unwrap();
            restore.add_chunk(batch1).unwrap();
            // Do not call `finish`.
        }

        {
            let rightmost_key = match db.get_rightmost_leaf().unwrap() {
                None => {
                    // Sometimes the batch is too small so nothing is written to DB.
                    return Ok(());
                }
                Some((_, node)) => node.account_key(),
            };
            let remaining_accounts: Vec<_> = all.clone()
                .into_iter()
                .filter(|(k, _v)| *k > rightmost_key)
                .collect();
            let mut restore = JellyfishMerkleRestore::new(&db, version).unwrap();
            restore.add_chunk(remaining_accounts).unwrap();
            restore.finish().unwrap();
        }

        assert_success(&db, expected_root_hash, &all, version);
    }
}

fn get_expected_root_hash(btree: &BTreeMap<HashValue, AccountStateBlob>) -> HashValue {
    let db = MockTreeStore::default();
    let tree = JellyfishMerkleTree::new(&db);

    for (i, (key, value)) in btree.iter().enumerate() {
        let (_root_hash, batch) = tree
            .put_blob_set(vec![(*key, value.clone())], i as Version)
            .unwrap();
        db.write_tree_update_batch(batch).unwrap();
    }
    tree.get_root_hash(btree.len() as Version - 1).unwrap()
}

fn assert_success(
    db: &MockTreeStore,
    expected_root_hash: HashValue,
    btree: &BTreeMap<HashValue, AccountStateBlob>,
    version: Version,
) {
    let tree = JellyfishMerkleTree::new(db);
    for (key, value) in btree {
        assert_eq!(tree.get(*key, version).unwrap(), Some(value.clone()));
    }

    let actual_root_hash = tree.get_root_hash(version).unwrap();
    assert_eq!(actual_root_hash, expected_root_hash);
}
<commit_msg>[Storage] Small improvements to jellyfish merkle restore tests<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    mock_tree_store::MockTreeStore, restore::JellyfishMerkleRestore, JellyfishMerkleTree,
    TreeReader,
};
use crypto::HashValue;
use proptest::{collection::btree_map, prelude::*};
use std::collections::BTreeMap;
use types::{account_state_blob::AccountStateBlob, transaction::Version};

proptest! {
    #![proptest_config(ProptestConfig::with_cases(10))]

    #[test]
    fn test_restore_without_interruption(
        btree in btree_map(any::<HashValue>(), any::<AccountStateBlob>(), 1..1000),
    ) {
        let version = (btree.len() - 1) as Version;
        let expected_root_hash = get_expected_root_hash(&btree);

        // For this test, restore everything without interruption.
        let db = MockTreeStore::default();
        let mut restore = JellyfishMerkleRestore::new(&db, version).unwrap();
        for (key, value) in &btree {
            restore.add_chunk(vec![(*key, value.clone())]).unwrap();
        }
        restore.finish().unwrap();

        assert_success(&db, expected_root_hash, &btree, version);
    }

    #[test]
    fn test_restore_with_interruption(
        (all, batch1_size) in btree_map(any::<HashValue>(), any::<AccountStateBlob>(), 2..1000)
            .prop_flat_map(|btree| {
                let len = btree.len();
                (Just(btree), 1..len)
            })
    ) {
        let version = (all.len() - 1) as Version;
        let expected_root_hash = get_expected_root_hash(&all);
        let batch1: Vec<_> = all.clone().into_iter().take(batch1_size).collect();
        let db = MockTreeStore::default();

        {
            let mut restore = JellyfishMerkleRestore::new(&db, version).unwrap();
            restore.add_chunk(batch1).unwrap();
            // Do not call `finish`.
        }

        {
            let rightmost_key = match db.get_rightmost_leaf().unwrap() {
                None => {
                    // Sometimes the batch is too small so nothing is written to DB.
                    return Ok(());
                }
                Some((_, node)) => node.account_key(),
            };
            let remaining_accounts: Vec<_> = all.clone()
                .into_iter()
                .filter(|(k, _v)| *k > rightmost_key)
                .collect();
            let mut restore = JellyfishMerkleRestore::new(&db, version).unwrap();
            restore.add_chunk(remaining_accounts).unwrap();
            restore.finish().unwrap();
        }

        assert_success(&db, expected_root_hash, &all, version);
    }
}

fn get_expected_root_hash(btree: &BTreeMap<HashValue, AccountStateBlob>) -> HashValue {
    let db = MockTreeStore::default();
    let tree = JellyfishMerkleTree::new(&db);

    for (i, (key, value)) in btree.iter().enumerate() {
        let (_root_hash, batch) = tree
            .put_blob_set(vec![(*key, value.clone())], i as Version)
            .unwrap();
        db.write_tree_update_batch(batch).unwrap();
    }
    tree.get_root_hash((btree.len() - 1) as Version).unwrap()
}

fn assert_success(
    db: &MockTreeStore,
    expected_root_hash: HashValue,
    btree: &BTreeMap<HashValue, AccountStateBlob>,
    version: Version,
) {
    let tree = JellyfishMerkleTree::new(db);
    for (key, value) in btree {
        assert_eq!(tree.get(*key, version).unwrap(), Some(value.clone()));
    }

    let actual_root_hash = tree.get_root_hash(version).unwrap();
    assert_eq!(actual_root_hash, expected_root_hash);
}
<|endoftext|>


<commit_before>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Create a new SoundData from the file at the given path.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let file = &mut context.filesystem.open(path)?;
        SoundData::from_read(file)
    }

    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
    repeat: bool,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = SoundData::new(context, path)?;
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
            repeat: false,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        use rodio::Source;
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        if self.repeat {
            let repeating = decoder.repeat_infinite();
            self.sink.append(repeating);
        } else {
            self.sink.append(decoder);
        }
        Ok(())
    }

    /// Sets the source to repeat playback infinitely on next `play()`
    pub fn set_repeat(&mut self, repeat: bool) {
        self.repeat = repeat;
    }

    /// Gets whether or not the source is set to repeat.
    pub fn repeat(&self) -> self {
        self.repeat
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Returns whether or not the source is stopped
    /// -- that is, has no more data to play.
    pub fn stopped(&self) -> bool {
        self.sink.empty()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing (ie, not paused
    /// and not stopped)
    pub fn playing(&self) -> bool {
        !self.paused() && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}
<commit_msg>Fixed foolish typo.  :/<commit_after>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Create a new SoundData from the file at the given path.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let file = &mut context.filesystem.open(path)?;
        SoundData::from_read(file)
    }

    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
    repeat: bool,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = SoundData::new(context, path)?;
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
            repeat: false,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        use rodio::Source;
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        if self.repeat {
            let repeating = decoder.repeat_infinite();
            self.sink.append(repeating);
        } else {
            self.sink.append(decoder);
        }
        Ok(())
    }

    /// Sets the source to repeat playback infinitely on next `play()`
    pub fn set_repeat(&mut self, repeat: bool) {
        self.repeat = repeat;
    }

    /// Gets whether or not the source is set to repeat.
    pub fn repeat(&self) -> bool {
        self.repeat
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Returns whether or not the source is stopped
    /// -- that is, has no more data to play.
    pub fn stopped(&self) -> bool {
        self.sink.empty()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing (ie, not paused
    /// and not stopped)
    pub fn playing(&self) -> bool {
        !self.paused() && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}
<|endoftext|>