<commit_before>use bidir_map::BidirMap;

use hmac::{Hmac, Mac};
use sha2::{Sha256};

use serde_json;
use serde_json::Value;
use serde_json::value::Map;

use error::*;
use helpers;
use types::Currency;
use types::Pair;
use types::Pair::*;

lazy_static! {
    static ref PAIRS_STRING: BidirMap<Pair, &'static str> = {
        let mut m = BidirMap::new();
        m.insert(BTC_USD, "btcusd");
        m.insert(BTC_EUR, "btceur");
        m.insert(EUR_USD, "eurusd");
        m.insert(XRP_USD, "xrpusd");
        m.insert(XRP_EUR, "xrpeur");
        m.insert(XRP_BTC, "xrpbtc");
        m
    };
}

/// Return the name associated to pair used by Bitstamp
/// If the Pair is not supported, None is returned.
pub fn get_pair_string(pair: &Pair) -> Option<&&str> {
    PAIRS_STRING.get_by_first(pair)
}

/// Return the Pair enum associated to the string used by Bitstamp
/// If the Pair is not supported, None is returned.
pub fn get_pair_enum(pair: &str) -> Option<&Pair> {
    PAIRS_STRING.get_by_second(&pair)
}

pub fn build_signature(nonce: &str,
                       customer_id: &str,
                       api_key: &str,
                       api_secret: &str)
                       -> Result<String> {
    const C: &'static [u8] = b"0123456789ABCDEF";

    let message = nonce.to_owned() + customer_id + api_key;

    let mut mac = Hmac::<Sha256>::new(api_secret.as_bytes());

    mac.input(message.as_bytes());
    let result = mac.result();

    let raw_signature = result.code();
    let mut signature = Vec::with_capacity(raw_signature.len() * 2);
    for &byte in raw_signature {
        signature.push(C[(byte >> 4) as usize]);
        signature.push(C[(byte & 0xf) as usize]);
    }
    // TODO: Handle correctly the from_utf8 errors with error_chain.
    Ok(String::from_utf8(signature)?)
}

pub fn build_url(method: &str, pair: &str) -> String {
    "https://www.bitstamp.net/api/v2/".to_string() + method + "/" + pair + "/"
}

pub fn deserialize_json(json_string: &str) -> Result<Map<String, Value>> {
    let data: Value = match serde_json::from_str(json_string) {
        Ok(data) => data,
        Err(_) => return Err(ErrorKind::BadParse.into()),
    };

    match data.as_object() {
        Some(value) => Ok(value.clone()),
        None => Err(ErrorKind::BadParse.into()),
    }
}

pub fn generate_nonce(fixed_nonce: Option<String>) -> String {
    match fixed_nonce {
        Some(v) => v,
        None => helpers::get_unix_timestamp_ms().to_string(),
    }
}

/// If error array is null, return the result (encoded in a json object)
/// else return the error string found in array
pub fn parse_result(response: &Map<String, Value>) -> Result<Map<String, Value>> {
    let error_msg = match response.get("error") {
        Some(error) => {
            error
                .as_str()
                .ok_or_else(|| ErrorKind::InvalidFieldFormat("error".to_string()))?
        }
        None => return Ok(response.clone()),
    };

    match error_msg.as_ref() {
        "Invalid command." => Err(ErrorKind::InvalidArguments.into()),
        "Invalid API key/secret pair." => Err(ErrorKind::BadCredentials.into()),
        "Total must be at least 0.0001." => Err(ErrorKind::InsufficientOrderSize.into()),
        other => Err(ErrorKind::ExchangeSpecificError(other.to_string()).into()),
    }
}

/// Return the currency enum associated with the
/// string used by Bitstamp. If no currency is found,
/// return None
/// # Examples
///
/// ```
/// use coinnect::bitstamp::utils::get_currency_enum;
/// use coinnect::types::Currency;
///
/// let currency = get_currency_enum("usd_balance");
/// assert_eq!(Some(Currency::USD), currency);
/// ```
pub fn get_currency_enum(currency: &str) -> Option<Currency> {
    match currency {
        "usd_balance" => Some(Currency::USD),
        "btc_balance" => Some(Currency::BTC),
        "eur_balance" => Some(Currency::EUR),
        "xrp_balance" => Some(Currency::XRP),
        _ => None,
    }
}

/// Return the currency string associated with the
/// enum used by Bitstamp. If no currency is found,
/// return None
/// # Examples
///
/// ```
/// use coinnect::bitstamp::utils::get_currency_string;
/// use coinnect::types::Currency;
///
/// let currency = get_currency_string(Currency::USD);
/// assert_eq!(currency, Some("USD".to_string()));
/// ```
pub fn get_currency_string(currency: Currency) -> Option<String> {
    match currency {
        Currency::USD => Some("USD".to_string()),
        Currency::BTC => Some("BTC".to_string()),
        Currency::EUR => Some("EUR".to_string()),
        Currency::XRP => Some("XRP".to_string()),
        _ => None,
    }
}
<commit_msg>Add mapping to name for all supported bitstamp currencies<commit_after>use bidir_map::BidirMap;

use hmac::{Hmac, Mac};
use sha2::{Sha256};

use serde_json;
use serde_json::Value;
use serde_json::value::Map;

use error::*;
use helpers;
use types::Currency;
use types::Pair;
use types::Pair::*;

lazy_static! {
    static ref PAIRS_STRING: BidirMap<Pair, &'static str> = {
        let mut m = BidirMap::new();
        m.insert(BTC_USD, "btcusd");
        m.insert(BTC_EUR, "btceur");
        m.insert(EUR_USD, "eurusd");
        m.insert(XRP_USD, "xrpusd");
        m.insert(XRP_EUR, "xrpeur");
        m.insert(XRP_BTC, "xrpbtc");
        m.insert(LTC_USD, "ltcusd");
        m.insert(LTC_EUR, "ltceur");
        m.insert(LTC_BTC, "ltcbtc");
        m.insert(ETH_USD, "ethusd");
        m.insert(ETH_EUR, "etheur");
        m.insert(ETH_BTC, "ethbtc");
        m.insert(BCH_USD, "bchusd");
        m.insert(BCH_EUR, "bcheur");
        m.insert(BCH_BTC, "bchbtc");
        m
    };
}

/// Return the name associated to pair used by Bitstamp
/// If the Pair is not supported, None is returned.
pub fn get_pair_string(pair: &Pair) -> Option<&&str> {
    PAIRS_STRING.get_by_first(pair)
}

/// Return the Pair enum associated to the string used by Bitstamp
/// If the Pair is not supported, None is returned.
pub fn get_pair_enum(pair: &str) -> Option<&Pair> {
    PAIRS_STRING.get_by_second(&pair)
}

pub fn build_signature(nonce: &str,
                       customer_id: &str,
                       api_key: &str,
                       api_secret: &str)
                       -> Result<String> {
    const C: &'static [u8] = b"0123456789ABCDEF";

    let message = nonce.to_owned() + customer_id + api_key;

    let mut mac = Hmac::<Sha256>::new(api_secret.as_bytes());

    mac.input(message.as_bytes());
    let result = mac.result();

    let raw_signature = result.code();
    let mut signature = Vec::with_capacity(raw_signature.len() * 2);
    for &byte in raw_signature {
        signature.push(C[(byte >> 4) as usize]);
        signature.push(C[(byte & 0xf) as usize]);
    }
    // TODO: Handle correctly the from_utf8 errors with error_chain.
    Ok(String::from_utf8(signature)?)
}

pub fn build_url(method: &str, pair: &str) -> String {
    "https://www.bitstamp.net/api/v2/".to_string() + method + "/" + pair + "/"
}

pub fn deserialize_json(json_string: &str) -> Result<Map<String, Value>> {
    let data: Value = match serde_json::from_str(json_string) {
        Ok(data) => data,
        Err(_) => return Err(ErrorKind::BadParse.into()),
    };

    match data.as_object() {
        Some(value) => Ok(value.clone()),
        None => Err(ErrorKind::BadParse.into()),
    }
}

pub fn generate_nonce(fixed_nonce: Option<String>) -> String {
    match fixed_nonce {
        Some(v) => v,
        None => helpers::get_unix_timestamp_ms().to_string(),
    }
}

/// If error array is null, return the result (encoded in a json object)
/// else return the error string found in array
pub fn parse_result(response: &Map<String, Value>) -> Result<Map<String, Value>> {
    let error_msg = match response.get("error") {
        Some(error) => {
            error
                .as_str()
                .ok_or_else(|| ErrorKind::InvalidFieldFormat("error".to_string()))?
        }
        None => return Ok(response.clone()),
    };

    match error_msg.as_ref() {
        "Invalid command." => Err(ErrorKind::InvalidArguments.into()),
        "Invalid API key/secret pair." => Err(ErrorKind::BadCredentials.into()),
        "Total must be at least 0.0001." => Err(ErrorKind::InsufficientOrderSize.into()),
        other => Err(ErrorKind::ExchangeSpecificError(other.to_string()).into()),
    }
}

/// Return the currency enum associated with the
/// string used by Bitstamp. If no currency is found,
/// return None
/// # Examples
///
/// ```
/// use coinnect::bitstamp::utils::get_currency_enum;
/// use coinnect::types::Currency;
///
/// let currency = get_currency_enum("usd_balance");
/// assert_eq!(Some(Currency::USD), currency);
/// ```
pub fn get_currency_enum(currency: &str) -> Option<Currency> {
    match currency {
        "usd_balance" => Some(Currency::USD),
        "btc_balance" => Some(Currency::BTC),
        "eur_balance" => Some(Currency::EUR),
        "xrp_balance" => Some(Currency::XRP),
        _ => None,
    }
}

/// Return the currency string associated with the
/// enum used by Bitstamp. If no currency is found,
/// return None
/// # Examples
///
/// ```
/// use coinnect::bitstamp::utils::get_currency_string;
/// use coinnect::types::Currency;
///
/// let currency = get_currency_string(Currency::USD);
/// assert_eq!(currency, Some("USD".to_string()));
/// ```
pub fn get_currency_string(currency: Currency) -> Option<String> {
    match currency {
        Currency::USD => Some("USD".to_string()),
        Currency::BTC => Some("BTC".to_string()),
        Currency::EUR => Some("EUR".to_string()),
        Currency::XRP => Some("XRP".to_string()),
        _ => None,
    }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]

pub extern crate futures;
extern crate c3po;
extern crate mainsail;
extern crate rigging;
pub extern crate serde;
pub extern crate serde_json as json;
pub extern crate tokio_redis as redis;

#[allow(unused_imports)]
#[macro_use] extern crate compass_rose;
#[macro_use] extern crate proc_macro_hack;

#[doc(hidden)]
pub use compass_rose::*;

proc_macro_item_decl! {
    /// The routes DSL
    routes! => routes_impl
}

#[macro_use]
pub mod api {
    pub use rigging::{Resource, Error};
    pub use rigging::environment::Environment;
    pub use mainsail::methods::{Get, Index, Post};

    pub use rigging::Relationship;
    pub use mainsail::methods::{GetOne, GetMany};

    #[macro_export]
    macro_rules! relation {
        ($rel:ident => $resource:ident) => {
            pub struct $rel;

            impl $crate::api::Relationship for $rel {
                type Related = $resource;
            }
        }
    }
}

#[doc(hidden)]
pub mod routing {
    pub use rigging::{ResourceEndpoint, RelationEndpoint, RelationshipLink};
    pub use rigging::endpoint::{Endpoint, endpoint};
    pub use rigging::routes::{Kind, RoutingTable, RouteKey, Handler, not_found};
    pub use rigging::environment::EnvBuilder;
}

pub use server::serve;

pub mod server {
    pub use rigging::http::{Request, Response, Error, Service, NewService, serve, Handle};

    pub mod pool {
        pub use rigging::connections::Configure;
        pub use c3po::{Pool, Config};
    }
}

pub mod clients {
    pub use rigging::connections::{Client, Configure, RedisConfig};
    pub use c3po::{Config as PoolConfig, Conn};
}

pub mod method {
    pub use rigging::method::Method;
    pub use rigging::request::{Request, ResourceRequest, CollectionRequest};
    pub use rigging::routes::Route;
    pub use mainsail::methods::{GetRequest, IndexRequest, PostRequest, PatchRequest};
}

pub mod format {

    pub use mainsail::formats::Debug;

    pub mod presenter {
        pub use rigging::format::{Present, PresentResource, PresentCollection, Template};
    }

    pub mod receiver {
        pub use rigging::format::Receive;
    }
}
<commit_msg>Expose Display formatter.<commit_after>#![feature(associated_consts)]

pub extern crate futures;
extern crate c3po;
extern crate mainsail;
extern crate rigging;
pub extern crate serde;
pub extern crate serde_json as json;
pub extern crate tokio_redis as redis;

#[allow(unused_imports)]
#[macro_use] extern crate compass_rose;
#[macro_use] extern crate proc_macro_hack;

#[doc(hidden)]
pub use compass_rose::*;

proc_macro_item_decl! {
    /// The routes DSL
    routes! => routes_impl
}

#[macro_use]
pub mod api {
    pub use rigging::{Resource, Error};
    pub use rigging::environment::Environment;
    pub use mainsail::methods::{Get, Index, Post};

    pub use rigging::Relationship;
    pub use mainsail::methods::{GetOne, GetMany};

    #[macro_export]
    macro_rules! relation {
        ($rel:ident => $resource:ident) => {
            pub struct $rel;

            impl $crate::api::Relationship for $rel {
                type Related = $resource;
            }
        }
    }
}

#[doc(hidden)]
pub mod routing {
    pub use rigging::{ResourceEndpoint, RelationEndpoint, RelationshipLink};
    pub use rigging::endpoint::{Endpoint, endpoint};
    pub use rigging::routes::{Kind, RoutingTable, RouteKey, Handler, not_found};
    pub use rigging::environment::EnvBuilder;
}

pub use server::serve;

pub mod server {
    pub use rigging::http::{Request, Response, Error, Service, NewService, serve, Handle};

    pub mod pool {
        pub use rigging::connections::Configure;
        pub use c3po::{Pool, Config};
    }
}

pub mod clients {
    pub use rigging::connections::{Client, Configure, RedisConfig};
    pub use c3po::{Config as PoolConfig, Conn};
}

pub mod method {
    pub use rigging::method::Method;
    pub use rigging::request::{Request, ResourceRequest, CollectionRequest};
    pub use rigging::routes::Route;
    pub use mainsail::methods::{GetRequest, IndexRequest, PostRequest, PatchRequest};
}

pub mod format {

    pub use mainsail::formats::{Debug, Display};

    pub mod presenter {
        pub use rigging::format::{Present, PresentResource, PresentCollection, Template};
    }

    pub mod receiver {
        pub use rigging::format::Receive;
    }
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * kit/kernel/process/x86_64.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 ******************************************************************************/

//! x86-64 architecture-specific process logic and hardware state.

use crate::memory;

use core::isize;
use core::ptr;
use core::mem;

/// A complete set of registers
#[repr(C, align(16))]
#[derive(Debug)]
pub struct Registers {
    rax:     usize,       // 0x00
    rcx:     usize,       // 0x08
    rdx:     usize,       // 0x10
    rbx:     usize,       // 0x18
    rsp:     usize,       // 0x20
    rbp:     usize,       // 0x28
    rsi:     usize,       // 0x30
    rdi:     usize,       // 0x38
    r8:      usize,       // 0x40
    r9:      usize,       // 0x48
    r10:     usize,       // 0x50
    r11:     usize,       // 0x58
    r12:     usize,       // 0x60
    r13:     usize,       // 0x68
    r14:     usize,       // 0x70
    r15:     usize,       // 0x78
    rip:     usize,       // 0x80
    eflags:  u32,         // 0x88
    fxsave:  [SSEReg; 32] // 0x90
    // 0x290
}

assert_eq_size!(Registers, [u8; 0x290]);

impl Default for Registers {
    fn default() -> Registers {
        Registers {
            rax: 0, rcx: 0, rdx: 0, rbx: 0,
            rsp: 0, rbp: 0, rsi: 0, rdi: 0,
            r8:  0, r9:  0, r10: 0, r11: 0,
            r12: 0, r13: 0, r14: 0, r15: 0,
            rip: 0,
            eflags: 0,
            fxsave: [SSEReg::default(); 32]
        }
    }
}

#[repr(simd, align(16))]
#[derive(Debug, Default, Clone, Copy)]
pub struct SSEReg(u32, u32, u32, u32);

pub const ARGS_TOP_ADDR:   usize = 0x0000_7fee_ffff_ffff;
pub const STACK_BASE_ADDR: usize = 0x0000_7fff_ffff_f000;
pub const HEAP_BASE_ADDR:  usize = 0x0000_0001_0000_0000;

pub const STACK_SIZE:      usize = 8192;

/// The hardware state of a process. Usually mutated by foreign code.
#[repr(C, align(16))]
#[derive(Debug)]
pub struct HwState {
    kernel: KernelHwState, // offset 0x00
    user: UserHwState,     // offset 0x50
}

impl HwState {
    pub fn new() -> HwState {
        HwState {
            kernel: KernelHwState::new(),
            user: UserHwState::new(),
        }
    }

    pub fn kernel(&self) -> &KernelHwState {
        &self.kernel
    }

    pub fn kernel_mut(&mut self) -> &mut KernelHwState {
        &mut self.kernel
    }

    pub fn user(&self) -> &UserHwState {
        &self.user
    }

    pub fn user_mut(&mut self) -> &mut UserHwState {
        &mut self.user
    }
}

/// The kernel part of the hardware state
#[repr(C, align(16))]
#[derive(Debug)]
pub struct KernelHwState {
    kstack: *mut u8,            // 0x00
    registers: KernelRegisters, // 0x10
}

assert_eq_size!(KernelHwState, [u8; 0x50]);

impl KernelHwState {
    fn new() -> KernelHwState {
        let kstack = memory::allocate_kernel_stack();

        KernelHwState {
            kstack,
            registers: KernelRegisters {
                rsp: kstack as usize,
                rbp: kstack as usize,
                ..KernelRegisters::default()
            }
        }
    }

    /// Set the address to jump to on process switch.
    ///
    /// # Unsafety
    ///
    /// This can result in any code (safe or unsafe) being executed at kernel
    /// level, and dereference of invalid addresses, so it's up to the caller to
    /// ensure the value provided will do something safe.
    pub unsafe fn set_instruction_pointer(&mut self, ip: usize) {
        self.registers.rip = ip;
    }

    /// Push a value onto the stack. The stack pointer advanced by the size of
    /// `T` and then aligned as required for `T`.
    ///
    /// # Unsafety
    ///
    /// As this modifies the kernel stack directly, this could cause a violation
    /// of expectations. It's up to the caller to ensure the instruction pointer
    /// is set to a place that can handle the argument passed.
    ///
    /// The kernel stack set must also be mapped to valid, nonoverlapping
    /// memory.
    pub unsafe fn push_stack<T>(&mut self, arg: T) {
        // Alignment must be power of two. This should be guaranteed, but I
        // didn't see that the Rust docs guarantee it.
        let align = mem::align_of::<T>();
        debug_assert_eq!(align & (align - 1), 0);

        // Subtract size
        self.registers.rsp -= mem::size_of::<T>();

        // Align downward
        self.registers.rsp &= !(align - 1);

        // Put the value in
        *(self.registers.rsp as *mut T) = arg;
    }
}

impl Drop for KernelHwState {
    fn drop(&mut self) {
        // TODO: free the kernel stack
    }
}

/// The registers here are chosen because they are those required to be
/// preserved between calls by the ABI. A process switch just looks like a call.
#[repr(C, align(16))]
#[derive(Debug, Default, Clone)]
struct KernelRegisters {
    rip: usize, // 0x00
    rsp: usize, // 0x08
    rbp: usize, // 0x10
    rbx: usize, // 0x18
    r12: usize, // 0x20
    r13: usize, // 0x28
    r14: usize, // 0x30
    r15: usize, // 0x38
    // 0x40
}

assert_eq_size!(KernelRegisters, [u8; 0x40]);

/// The userland part of the hardware state.
#[repr(C, align(16))]
#[derive(Debug)]
pub struct UserHwState {
    registers: Registers,
}

assert_eq_size!(UserHwState, [u8; 0x290]);

impl UserHwState {
    fn new() -> UserHwState {
        UserHwState {
            registers: Registers::default(),
        }
    }

    /// Set the entry point arguments to `(argc, argv)`.
    ///
    /// Pass `None` to set to `(0, NULL)`.
    pub fn set_args(&mut self, args: Option<(i32, usize)>) {
        if let Some((argc, argv)) = args {
            self.registers.rdi = argc as usize;
            self.registers.rsi = argv;
        } else {
            self.registers.rdi = 0;
            self.registers.rsi = ptr::null::<u8>() as usize;
        }
    }

    /// Set the instruction pointer to the given address.
    pub fn set_instruction_pointer(&mut self, vaddr: usize) {
        self.registers.rip = vaddr;
    }

    /// Set the stack pointer to the given address.
    pub fn set_stack_pointer(&mut self, vaddr: usize) {
        self.registers.rsp = vaddr;
        self.registers.rbp = vaddr;
    }
}
<commit_msg>push_stack (into a process) should require Send<commit_after>/*******************************************************************************
 *
 * kit/kernel/process/x86_64.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 ******************************************************************************/

//! x86-64 architecture-specific process logic and hardware state.

use crate::memory;

use core::ptr;
use core::mem;

/// A complete set of registers
#[repr(C, align(16))]
#[derive(Debug)]
pub struct Registers {
    rax:     usize,       // 0x00
    rcx:     usize,       // 0x08
    rdx:     usize,       // 0x10
    rbx:     usize,       // 0x18
    rsp:     usize,       // 0x20
    rbp:     usize,       // 0x28
    rsi:     usize,       // 0x30
    rdi:     usize,       // 0x38
    r8:      usize,       // 0x40
    r9:      usize,       // 0x48
    r10:     usize,       // 0x50
    r11:     usize,       // 0x58
    r12:     usize,       // 0x60
    r13:     usize,       // 0x68
    r14:     usize,       // 0x70
    r15:     usize,       // 0x78
    rip:     usize,       // 0x80
    eflags:  u32,         // 0x88
    fxsave:  [SSEReg; 32] // 0x90
    // 0x290
}

assert_eq_size!(Registers, [u8; 0x290]);

impl Default for Registers {
    fn default() -> Registers {
        Registers {
            rax: 0, rcx: 0, rdx: 0, rbx: 0,
            rsp: 0, rbp: 0, rsi: 0, rdi: 0,
            r8:  0, r9:  0, r10: 0, r11: 0,
            r12: 0, r13: 0, r14: 0, r15: 0,
            rip: 0,
            eflags: 0,
            fxsave: [SSEReg::default(); 32]
        }
    }
}

#[repr(simd, align(16))]
#[derive(Debug, Default, Clone, Copy)]
pub struct SSEReg(u32, u32, u32, u32);

pub const ARGS_TOP_ADDR:   usize = 0x0000_7fee_ffff_ffff;
pub const STACK_BASE_ADDR: usize = 0x0000_7fff_ffff_f000;
pub const HEAP_BASE_ADDR:  usize = 0x0000_0001_0000_0000;

pub const STACK_SIZE:      usize = 8192;

/// The hardware state of a process. Usually mutated by foreign code.
#[repr(C, align(16))]
#[derive(Debug)]
pub struct HwState {
    kernel: KernelHwState, // offset 0x00
    user: UserHwState,     // offset 0x50
}

impl HwState {
    pub fn new() -> HwState {
        HwState {
            kernel: KernelHwState::new(),
            user: UserHwState::new(),
        }
    }

    pub fn kernel(&self) -> &KernelHwState {
        &self.kernel
    }

    pub fn kernel_mut(&mut self) -> &mut KernelHwState {
        &mut self.kernel
    }

    pub fn user(&self) -> &UserHwState {
        &self.user
    }

    pub fn user_mut(&mut self) -> &mut UserHwState {
        &mut self.user
    }
}

/// The kernel part of the hardware state
#[repr(C, align(16))]
#[derive(Debug)]
pub struct KernelHwState {
    kstack: *mut u8,            // 0x00
    registers: KernelRegisters, // 0x10
}

assert_eq_size!(KernelHwState, [u8; 0x50]);

impl KernelHwState {
    fn new() -> KernelHwState {
        let kstack = memory::allocate_kernel_stack();

        KernelHwState {
            kstack,
            registers: KernelRegisters {
                rsp: kstack as usize,
                rbp: kstack as usize,
                ..KernelRegisters::default()
            }
        }
    }

    /// Set the address to jump to on process switch.
    ///
    /// # Unsafety
    ///
    /// This can result in any code (safe or unsafe) being executed at kernel
    /// level, and dereference of invalid addresses, so it's up to the caller to
    /// ensure the value provided will do something safe.
    pub unsafe fn set_instruction_pointer(&mut self, ip: usize) {
        self.registers.rip = ip;
    }

    /// Push a value onto the stack. The stack pointer advanced by the size of
    /// `T` and then aligned as required for `T`.
    ///
    /// Because the value will be sent to another thread, it must be `Send`.
    ///
    /// # Unsafety
    ///
    /// As this modifies the kernel stack directly, this could cause a violation
    /// of expectations. It's up to the caller to ensure the instruction pointer
    /// is set to a place that can handle the argument passed.
    ///
    /// The kernel stack set must also be mapped to valid, nonoverlapping
    /// memory.
    pub unsafe fn push_stack<T>(&mut self, arg: T)
        where T: Send {

        // Alignment must be power of two. This should be guaranteed, but I
        // didn't see that the Rust docs guarantee it.
        let align = mem::align_of::<T>();
        debug_assert_eq!(align & (align - 1), 0);

        // Subtract size
        self.registers.rsp -= mem::size_of::<T>();

        // Align downward
        self.registers.rsp &= !(align - 1);

        // Put the value in
        *(self.registers.rsp as *mut T) = arg;
    }
}

impl Drop for KernelHwState {
    fn drop(&mut self) {
        // TODO: free the kernel stack
    }
}

/// The registers here are chosen because they are those required to be
/// preserved between calls by the ABI. A process switch just looks like a call.
#[repr(C, align(16))]
#[derive(Debug, Default, Clone)]
struct KernelRegisters {
    rip: usize, // 0x00
    rsp: usize, // 0x08
    rbp: usize, // 0x10
    rbx: usize, // 0x18
    r12: usize, // 0x20
    r13: usize, // 0x28
    r14: usize, // 0x30
    r15: usize, // 0x38
    // 0x40
}

assert_eq_size!(KernelRegisters, [u8; 0x40]);

/// The userland part of the hardware state.
#[repr(C, align(16))]
#[derive(Debug)]
pub struct UserHwState {
    registers: Registers,
}

assert_eq_size!(UserHwState, [u8; 0x290]);

impl UserHwState {
    fn new() -> UserHwState {
        UserHwState {
            registers: Registers::default(),
        }
    }

    /// Set the entry point arguments to `(argc, argv)`.
    ///
    /// Pass `None` to set to `(0, NULL)`.
    pub fn set_args(&mut self, args: Option<(i32, usize)>) {
        if let Some((argc, argv)) = args {
            self.registers.rdi = argc as usize;
            self.registers.rsi = argv;
        } else {
            self.registers.rdi = 0;
            self.registers.rsi = ptr::null::<u8>() as usize;
        }
    }

    /// Set the instruction pointer to the given address.
    pub fn set_instruction_pointer(&mut self, vaddr: usize) {
        self.registers.rip = vaddr;
    }

    /// Set the stack pointer to the given address.
    pub fn set_stack_pointer(&mut self, vaddr: usize) {
        self.registers.rsp = vaddr;
        self.registers.rbp = vaddr;
    }
}
<|endoftext|>


<commit_before>//! Provides special functions related to the [beta](https://en.wikipedia.org/wiki/Beta_function)
//! function

use std::f64;
use error::StatsError;
use function::gamma;
use prec;

/// Computes the natural logarithm
/// of the beta function
/// where `a` is the first beta parameter
/// and `b` is the second beta parameter
/// and `a > 0`, `b > 0`.
///
/// # Panics
///
/// if `a <= 0.0` or `b <= 0.0`
pub fn ln_beta(a: f64, b: f64) -> f64 {
    assert!(a > 0.0, format!("{}", StatsError::ArgMustBePositive("a")));
    assert!(b > 0.0, format!("{}", StatsError::ArgMustBePositive("b")));
    gamma::ln_gamma(a) + gamma::ln_gamma(b) - gamma::ln_gamma(a + b)
}

/// Computes the beta function
/// where `a` is the first beta parameter
/// and `b` is the second beta parameter.
///
///
/// # Panics
///
/// if `a <= 0.0` or `b <= 0.0`
pub fn beta(a: f64, b: f64) -> f64 {
    ln_beta(a, b).exp()
}

/// Computes the lower incomplete (unregularized) beta function
/// `B(a,b,x) = int(t^(a-1)*(1-t)^(b-1),t=0..x)` for `a > 0, b > 0, 1 >= x >= 0`
/// where `a` is the first beta parameter, `b` is the second beta parameter, and
/// `x` is the upper limit of the integral
///
/// # Panics
///
/// If `a < 0.0`, `b < 0.0`, `x < 0.0`, or `x > 1.0`
pub fn beta_inc(a: f64, b: f64, x: f64) -> f64 {
    beta_reg(a, b, x) * beta(a, b)
}

/// Computes the regularized lower incomplete beta function
/// `I_x(a,b) = 1/Beta(a,b) * int(t^(a-1)*(1-t)^(b-1), t=0..x)`
/// `a > 0`, `b > 0`, `1 >= x >= 0` where `a` is the first beta parameter,
/// `b` is the second beta parameter, and `x` is the upper limit of the
/// integral.
///
/// # Panics
///
/// if `a < 0.0`, `b < 0.0`, `x < 0.0`, or `x > 1.0`
pub fn beta_reg(a: f64, b: f64, x: f64) -> f64 {
    assert!(a >= 0.0, format!("{}", StatsError::ArgNotNegative("a")));
    assert!(b >= 0.0, format!("{}", StatsError::ArgNotNegative("b")));
    assert!(x >= 0.0 && x <= 1.0,
            format!("{}", StatsError::ArgIntervalIncl("x", 0.0, 1.0)));

    let bt = match x {
        0.0 | 1.0 => 0.0,
        _ => {
            (gamma::ln_gamma(a + b) - gamma::ln_gamma(a) - gamma::ln_gamma(b) + a * x.ln() +
             b * (1.0 - x).ln())
                .exp()
        }
    };
    let symm_transform = x >= (a + 1.0) / (a + b + 2.0);
    let eps = prec::F64_PREC;
    let fpmin = f64::MIN_POSITIVE / eps;

    let mut a = a;
    let mut b = b;
    let mut x = x;
    if symm_transform {
        let swap = a;
        x = 1.0 - x;
        a = b;
        b = swap;
    }

    let qab = a + b;
    let qap = a + 1.0;
    let qam = a - 1.0;
    let mut c = 1.0;
    let mut d = 1.0 - qab * x / qap;

    if d.abs() < fpmin {
        d = fpmin;
    }
    d = 1.0 / d;
    let mut h = d;

    for m in 1..141 {
        let m = m as f64;
        let m2 = m * 2.0;
        let mut aa = m * (b - m) * x / ((qam + m2) * (a + m2));
        d = 1.0 + aa * d;

        if d.abs() < fpmin {
            d = fpmin;
        }

        c = 1.0 + aa / c;
        if c.abs() < fpmin {
            c = fpmin;
        }

        d = 1.0 / d;
        h = h * d * c;
        aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
        d = 1.0 + aa * d;

        if d.abs() < fpmin {
            d = fpmin;
        }

        c = 1.0 + aa / c;

        if c.abs() < fpmin {
            c = fpmin;
        }

        d = 1.0 / d;
        let del = d * c;
        h *= del;

        if (del - 1.0).abs() <= eps {
            return if symm_transform {
                1.0 - bt * h / a
            } else {
                bt * h / a
            };
        }
    }

    if symm_transform {
        1.0 - bt * h / a
    } else {
        bt * h / a
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    #[test]
    fn test_ln_beta() {
        assert_almost_eq!(super::ln_beta(0.5, 0.5), 1.144729885849400174144, 1e-15);
    }

    #[test]
    fn test_beta() {
        assert_almost_eq!(super::beta(0.5, 0.5), 3.141592653589793238463, 1e-15);
        assert_almost_eq!(super::beta(1.0, 0.5), 2.0, 1e-14);
        assert_almost_eq!(super::beta(2.5, 0.5), 1.17809724509617246442, 1e-15);
        assert_almost_eq!(super::beta(0.5, 1.0), 2.0, 1e-14);
        assert_almost_eq!(super::beta(1.0, 1.0), 1.0, 1e-15);
        assert_almost_eq!(super::beta(2.5, 1.0), 0.4, 1e-14);
        assert_almost_eq!(super::beta(0.5, 2.5), 1.17809724509617246442, 1e-15);
        assert_almost_eq!(super::beta(1.0, 2.5), 0.4, 1e-14);
        assert_almost_eq!(super::beta(2.5, 2.5), 0.073631077818510779026, 1e-15);
        assert_almost_eq!(super::beta(0.5, 5.0), 0.812698412698412698413, 1e-15);
        assert_almost_eq!(super::beta(1.0, 5.0), 0.2, 1e-14);
        assert_almost_eq!(super::beta(2.5, 5.0), 0.017049617049617049617, 1e16);
    }
}
<commit_msg>complete ln_beta tests<commit_after>//! Provides special functions related to the [beta](https://en.wikipedia.org/wiki/Beta_function)
//! function

use std::f64;
use error::StatsError;
use function::gamma;
use prec;

/// Computes the natural logarithm
/// of the beta function
/// where `a` is the first beta parameter
/// and `b` is the second beta parameter
/// and `a > 0`, `b > 0`.
///
/// # Panics
///
/// if `a <= 0.0` or `b <= 0.0`
pub fn ln_beta(a: f64, b: f64) -> f64 {
    assert!(a > 0.0, format!("{}", StatsError::ArgMustBePositive("a")));
    assert!(b > 0.0, format!("{}", StatsError::ArgMustBePositive("b")));
    gamma::ln_gamma(a) + gamma::ln_gamma(b) - gamma::ln_gamma(a + b)
}

/// Computes the beta function
/// where `a` is the first beta parameter
/// and `b` is the second beta parameter.
///
///
/// # Panics
///
/// if `a <= 0.0` or `b <= 0.0`
pub fn beta(a: f64, b: f64) -> f64 {
    ln_beta(a, b).exp()
}

/// Computes the lower incomplete (unregularized) beta function
/// `B(a,b,x) = int(t^(a-1)*(1-t)^(b-1),t=0..x)` for `a > 0, b > 0, 1 >= x >= 0`
/// where `a` is the first beta parameter, `b` is the second beta parameter, and
/// `x` is the upper limit of the integral
///
/// # Panics
///
/// If `a < 0.0`, `b < 0.0`, `x < 0.0`, or `x > 1.0`
pub fn beta_inc(a: f64, b: f64, x: f64) -> f64 {
    beta_reg(a, b, x) * beta(a, b)
}

/// Computes the regularized lower incomplete beta function
/// `I_x(a,b) = 1/Beta(a,b) * int(t^(a-1)*(1-t)^(b-1), t=0..x)`
/// `a > 0`, `b > 0`, `1 >= x >= 0` where `a` is the first beta parameter,
/// `b` is the second beta parameter, and `x` is the upper limit of the
/// integral.
///
/// # Panics
///
/// if `a < 0.0`, `b < 0.0`, `x < 0.0`, or `x > 1.0`
pub fn beta_reg(a: f64, b: f64, x: f64) -> f64 {
    assert!(a >= 0.0, format!("{}", StatsError::ArgNotNegative("a")));
    assert!(b >= 0.0, format!("{}", StatsError::ArgNotNegative("b")));
    assert!(x >= 0.0 && x <= 1.0,
            format!("{}", StatsError::ArgIntervalIncl("x", 0.0, 1.0)));

    let bt = match x {
        0.0 | 1.0 => 0.0,
        _ => {
            (gamma::ln_gamma(a + b) - gamma::ln_gamma(a) - gamma::ln_gamma(b) + a * x.ln() +
             b * (1.0 - x).ln())
                .exp()
        }
    };
    let symm_transform = x >= (a + 1.0) / (a + b + 2.0);
    let eps = prec::F64_PREC;
    let fpmin = f64::MIN_POSITIVE / eps;

    let mut a = a;
    let mut b = b;
    let mut x = x;
    if symm_transform {
        let swap = a;
        x = 1.0 - x;
        a = b;
        b = swap;
    }

    let qab = a + b;
    let qap = a + 1.0;
    let qam = a - 1.0;
    let mut c = 1.0;
    let mut d = 1.0 - qab * x / qap;

    if d.abs() < fpmin {
        d = fpmin;
    }
    d = 1.0 / d;
    let mut h = d;

    for m in 1..141 {
        let m = m as f64;
        let m2 = m * 2.0;
        let mut aa = m * (b - m) * x / ((qam + m2) * (a + m2));
        d = 1.0 + aa * d;

        if d.abs() < fpmin {
            d = fpmin;
        }

        c = 1.0 + aa / c;
        if c.abs() < fpmin {
            c = fpmin;
        }

        d = 1.0 / d;
        h = h * d * c;
        aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2));
        d = 1.0 + aa * d;

        if d.abs() < fpmin {
            d = fpmin;
        }

        c = 1.0 + aa / c;

        if c.abs() < fpmin {
            c = fpmin;
        }

        d = 1.0 / d;
        let del = d * c;
        h *= del;

        if (del - 1.0).abs() <= eps {
            return if symm_transform {
                1.0 - bt * h / a
            } else {
                bt * h / a
            };
        }
    }

    if symm_transform {
        1.0 - bt * h / a
    } else {
        bt * h / a
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    #[test]
    fn test_ln_beta() {
        assert_almost_eq!(super::ln_beta(0.5, 0.5), 1.144729885849400174144, 1e-15);
        assert_almost_eq!(super::ln_beta(1.0, 0.5), 0.6931471805599453094172, 1e-14);
        assert_almost_eq!(super::ln_beta(2.5, 0.5), 0.163900632837673937284, 1e-15);
        assert_almost_eq!(super::ln_beta(0.5, 1.0), 0.6931471805599453094172, 1e-14);
        assert_almost_eq!(super::ln_beta(1.0, 1.0), 0.0, 1e-15);
        assert_almost_eq!(super::ln_beta(2.5, 1.0), -0.9162907318741550651835, 1e-14);
        assert_almost_eq!(super::ln_beta(0.5, 2.5), 0.163900632837673937284, 1e-14);
        assert_almost_eq!(super::ln_beta(1.0, 2.5), -0.9162907318741550651835, 1e-14);
        assert_almost_eq!(super::ln_beta(2.5, 2.5), -2.608688089402107300388, 1e-14);
    }

    #[test]
    fn test_beta() {
        assert_almost_eq!(super::beta(0.5, 0.5), 3.141592653589793238463, 1e-15);
        assert_almost_eq!(super::beta(1.0, 0.5), 2.0, 1e-14);
        assert_almost_eq!(super::beta(2.5, 0.5), 1.17809724509617246442, 1e-15);
        assert_almost_eq!(super::beta(0.5, 1.0), 2.0, 1e-14);
        assert_almost_eq!(super::beta(1.0, 1.0), 1.0, 1e-15);
        assert_almost_eq!(super::beta(2.5, 1.0), 0.4, 1e-14);
        assert_almost_eq!(super::beta(0.5, 2.5), 1.17809724509617246442, 1e-15);
        assert_almost_eq!(super::beta(1.0, 2.5), 0.4, 1e-14);
        assert_almost_eq!(super::beta(2.5, 2.5), 0.073631077818510779026, 1e-15);
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

#[macro_use]
extern crate lazy_static;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;
use std::collections::{HashMap, VecDeque};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct Position {
    x: usize,
    y: usize,
}

impl std::fmt::Display for Position {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "node-y{}-x{}", self.y, self.x)
    }
}

impl Position {
    fn neighbors(&self) -> Vec<Position> {
        let &Position { x, y } = self;
        let mut neighbors = vec![Position { x: x + 1, y: y }, Position { x: x, y: y + 1 }];
        if x != 0 {
            neighbors.push(Position { x: x - 1, y: y });
        }
        if y != 0 {
            neighbors.push(Position { x: x, y: y - 1 });
        }
        neighbors
    }
}

#[derive(Debug, Clone)]
struct NodeInfo {
    size: usize,
    used: usize,
    avail: usize,
}

#[derive(Debug)]
struct NodeListing {
    pos: Position,
    info: NodeInfo,
}

impl std::str::FromStr for NodeListing {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        lazy_static! {
            static ref NODE_RE: Regex =
                Regex::new(
                    r"/dev/grid/node-x(\d+)-y(\d+)\s+(\d+)T\s+(\d+)T\s+(\d+)T\s+\d+%")
                .expect("bad regex NODE_RE");
        }
        if let Some(cap) = NODE_RE.captures(s) {
            Ok(NodeListing {
                pos: Position {
                    x: cap[1].parse().unwrap(),
                    y: cap[2].parse().unwrap(),
                },
                info: NodeInfo {
                    size: cap[3].parse().unwrap(),
                    used: cap[4].parse().unwrap(),
                    avail: cap[5].parse().unwrap(),
                },
            })
        } else {
            Err(format!("Could not parse NodeListing from {}", s))
        }
    }
}

fn valid_pairs(nodes: &HashMap<Position, NodeInfo>) -> Vec<(Position, Position)> {
    let mut pairs = Vec::new();
    for (&pos_a, ref info_a) in nodes.iter() {
        for (&pos_b, ref info_b) in nodes.iter() {
            if info_a.used != 0 && pos_a != pos_b && info_a.used <= info_b.avail {
                pairs.push((pos_a, pos_b));
            }
        }
    }
    pairs
}

fn possible_moves(nodes: &HashMap<Position, NodeInfo>) -> Vec<(Position, Position)> {
    let mut possibilities = Vec::new();
    for (&pos_a, ref info_a) in nodes.iter() {
        if info_a.used == 0 {
            // no point in moving no data
            continue;
        }
        for pos_b in pos_a.neighbors() {
            if let Some(info_b) = nodes.get(&pos_b) {
                if info_a.used <= info_b.avail {
                    possibilities.push((pos_a, pos_b));
                }
            }
        }
    }
    possibilities
}

fn move_data(nodes: &mut HashMap<Position, NodeInfo>, from: Position, to: Position) {
    let from_info = nodes.get(&from)
        .unwrap_or_else(|| panic!("Invalid move: {} does not exist", from))
        .clone();
    if let Some(ref mut to_info) = nodes.get_mut(&to) {
        if from_info.used > to_info.avail {
            panic!("Invalid move: {} (avail: {}) cannot hold {} (used: {})",
                   to,
                   to_info.avail,
                   from,
                   from_info.avail);
        }
        to_info.used += from_info.used;
        to_info.avail -= from_info.used;
    } else {
        panic!("Invalid move: {} does not exist", to);
    }
    let mut from_info_mut = nodes.get_mut(&from).unwrap();
    from_info_mut.avail = from_info.size;
    from_info_mut.used = 0;
}

fn solve(nodes: &HashMap<Position, NodeInfo>) -> Option<Vec<(Position, Position)>> {
    let mut state_queue = VecDeque::new();
    let initial_target_loc = nodes.keys()
        .filter(|pos| pos.y == 0)
        .max_by_key(|pos| pos.x)
        .expect("Invalid target state")
        .clone();
    state_queue.push_back((nodes.clone(), initial_target_loc, Vec::new()));
    while let Some((state, target_loc, moves)) = state_queue.pop_front() {
        // print!("considering target = {} moves = [", target_loc);
        // for &(from, to) in &moves {
        //    print!("{} -> {}, ", from, to);
        // }
        // println!("] ({} moves from here.)", possible_moves(&state).len());
        for (from, to) in possible_moves(&state) {
            let mut new_state = state.clone();
            let mut new_moves = moves.clone();
            new_moves.push((from, to));
            move_data(&mut new_state, from, to);
            let new_target_loc = if from == target_loc { to } else { target_loc };
            if new_target_loc.x == 0 && new_target_loc.y == 0 {
                return Some(new_moves);
            }
            state_queue.push_back((new_state, new_target_loc, new_moves));
        }
    }
    None
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 22")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("nodes")
            .index(1)
            .help("file containing output of nodes `df`. Reads from stdin otherwise"))
        .get_matches();
    let source = matches.value_of_os("nodes");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let nodes: HashMap<Position, NodeInfo> = input.lines()
        .map(|line| line.trim().parse::<NodeListing>())
        .filter_map(|r| r.ok())
        .map(|listing| (listing.pos, listing.info))
        .collect();
    println!("number of valid node pairs: {}", valid_pairs(&nodes).len());
    if let Some(solution) = solve(&nodes) {
        println!("Solution:");
        for mov in &solution {
            println!("{} -> {}", mov.0, mov.1);
        }
        println!("Total moves taken: {}", solution.len())
    }
}

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

    #[test]
    fn example() {
        let nodes = ["/dev/grid/node-x0-y0   10T    8T     2T   80%",
                     "/dev/grid/node-x0-y1   11T    6T     5T   54%",
                     "/dev/grid/node-x0-y2   32T   28T     4T   87%",
                     "/dev/grid/node-x1-y0    9T    7T     2T   77%",
                     "/dev/grid/node-x1-y1    8T    0T     8T    0%",
                     "/dev/grid/node-x1-y2   11T    7T     4T   63%",
                     "/dev/grid/node-x2-y0   10T    6T     4T   60%",
                     "/dev/grid/node-x2-y1    9T    8T     1T   88%",
                     "/dev/grid/node-x2-y2    9T    6T     3T   66%"]
            .into_iter()
            .map(|s| s.parse::<NodeListing>().unwrap())
            .map(|listing| (listing.pos, listing.info))
            .collect();
        assert_eq!(solve(&nodes).unwrap().len(), 7);
    }
}
<commit_msg>Day 22 part 2<commit_after>extern crate clap;
extern crate regex;

#[macro_use]
extern crate lazy_static;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;
use std::collections::{HashMap, HashSet, VecDeque};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct Position {
    x: usize,
    y: usize,
}

impl std::fmt::Display for Position {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "node-x{}-y{}", self.x, self.y)
    }
}

impl Position {
    fn neighbors(&self) -> Vec<Position> {
        let &Position { x, y } = self;
        let mut neighbors = vec![Position { x: x + 1, y: y }, Position { x: x, y: y + 1 }];
        if x != 0 {
            neighbors.push(Position { x: x - 1, y: y });
        }
        if y != 0 {
            neighbors.push(Position { x: x, y: y - 1 });
        }
        neighbors
    }
}

#[derive(Debug, Clone)]
struct NodeInfo {
    size: usize,
    used: usize,
    avail: usize,
}

#[derive(Debug)]
struct NodeListing {
    pos: Position,
    info: NodeInfo,
}

impl std::str::FromStr for NodeListing {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        lazy_static! {
            static ref NODE_RE: Regex =
                Regex::new(
                    r"/dev/grid/node-x(\d+)-y(\d+)\s+(\d+)T\s+(\d+)T\s+(\d+)T\s+\d+%")
                .expect("bad regex NODE_RE");
        }
        if let Some(cap) = NODE_RE.captures(s) {
            Ok(NodeListing {
                pos: Position {
                    x: cap[1].parse().unwrap(),
                    y: cap[2].parse().unwrap(),
                },
                info: NodeInfo {
                    size: cap[3].parse().unwrap(),
                    used: cap[4].parse().unwrap(),
                    avail: cap[5].parse().unwrap(),
                },
            })
        } else {
            Err(format!("Could not parse NodeListing from {}", s))
        }
    }
}

fn valid_pairs(nodes: &HashMap<Position, NodeInfo>) -> Vec<(Position, Position)> {
    let mut pairs = Vec::new();
    for (&pos_a, ref info_a) in nodes.iter() {
        for (&pos_b, ref info_b) in nodes.iter() {
            if info_a.used != 0 && pos_a != pos_b && info_a.used <= info_b.avail {
                pairs.push((pos_a, pos_b));
            }
        }
    }
    pairs
}

fn possible_moves(nodes: &HashMap<Position, NodeInfo>, hole: Position) -> Vec<Position> {
    let mut possibilities = Vec::with_capacity(4);
    let avail = nodes[&hole].avail;
    for pos in hole.neighbors() {
        if let Some(from_info) = nodes.get(&pos) {
            if from_info.used <= avail {
                possibilities.push(pos);
            }
        }
    }
    possibilities
}

fn move_data(nodes: &mut HashMap<Position, NodeInfo>, from: Position, to: Position) {
    let from_info = nodes.get(&from)
        .unwrap_or_else(|| panic!("Invalid move: {} does not exist", from))
        .clone();
    if let Some(ref mut to_info) = nodes.get_mut(&to) {
        if from_info.used > to_info.avail {
            panic!("Invalid move: {} (avail: {}) cannot hold {} (used: {})",
                   to,
                   to_info.avail,
                   from,
                   from_info.avail);
        }
        to_info.used += from_info.used;
        to_info.avail -= from_info.used;
    } else {
        panic!("Invalid move: {} does not exist", to);
    }
    let mut from_info_mut = nodes.get_mut(&from).unwrap();
    from_info_mut.avail = from_info.size;
    from_info_mut.used = 0;
}

fn make_moves(mut nodes: &mut HashMap<Position, NodeInfo>,
              initial_hole: Position,
              moves: &[Position])
              -> Position {
    let mut hole = initial_hole;
    for mov in moves.iter() {
        move_data(&mut nodes, *mov, hole);
        hole = *mov;
    }
    hole
}

fn solve(nodes: &HashMap<Position, NodeInfo>) -> Option<Vec<Position>> {
    let mut state_queue = VecDeque::new();
    let initial_target_loc = nodes.keys()
        .filter(|pos| pos.y == 0)
        .max_by_key(|pos| pos.x)
        .expect("Invalid target state")
        .clone();
    let mut initial_holes: Vec<_> = nodes.iter()
        .filter(|&(_, info)| info.used == 0)
        .map(|(pos, _)| *pos)
        .collect();
    if initial_holes.len() != 1 {
        panic!("sorry, consult a better path-finding algorithm =p");
    }
    let initial_hole = initial_holes.pop().unwrap();
    let mut visited = HashSet::new();
    visited.insert((initial_hole, initial_target_loc));
    state_queue.push_back((initial_target_loc, Vec::new()));
    while let Some((target_loc, moves)) = state_queue.pop_front() {
        let mut state = nodes.clone();
        let old_hole = make_moves(&mut state, initial_hole, &moves);
        for from in possible_moves(&state, old_hole) {
            let mut new_state = state.clone();
            move_data(&mut new_state, from, old_hole);
            let mut new_moves = moves.clone();
            new_moves.push(from);
            let new_target_loc = if from == target_loc {
                old_hole
            } else {
                target_loc
            };
            if new_target_loc.x == 0 && new_target_loc.y == 0 {
                return Some(new_moves);
            }
            if !visited.contains(&(from, new_target_loc)) {
                visited.insert((from, new_target_loc));
                state_queue.push_back((new_target_loc, new_moves));
            }
        }
    }
    None
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 22")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("nodes")
            .index(1)
            .help("file containing output of nodes `df`. Reads from stdin otherwise"))
        .get_matches();
    let source = matches.value_of_os("nodes");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let nodes: HashMap<Position, NodeInfo> = input.lines()
        .map(|line| line.trim().parse::<NodeListing>())
        .filter_map(|r| r.ok())
        .map(|listing| (listing.pos, listing.info))
        .collect();
    println!("number of valid node pairs: {}", valid_pairs(&nodes).len());
    if let Some(solution) = solve(&nodes) {
        let mut initial_holes: Vec<_> = nodes.iter()
            .filter(|&(_, info)| info.used == 0)
            .map(|(pos, _)| *pos)
            .collect();
        if initial_holes.len() != 1 {
            panic!("sorry, consult a better path-finding algorithm =p");
        }
        let initial_hole = initial_holes.pop().unwrap();
        println!("Solution:");
        println!("{}", initial_hole);
        for mov in &solution {
            println!("-> {}", mov);
        }
        println!("Total moves taken: {}", solution.len())
    }
}

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

    #[test]
    fn example() {
        let nodes = ["/dev/grid/node-x0-y0   10T    8T     2T   80%",
                     "/dev/grid/node-x0-y1   11T    6T     5T   54%",
                     "/dev/grid/node-x0-y2   32T   28T     4T   87%",
                     "/dev/grid/node-x1-y0    9T    7T     2T   77%",
                     "/dev/grid/node-x1-y1    8T    0T     8T    0%",
                     "/dev/grid/node-x1-y2   11T    7T     4T   63%",
                     "/dev/grid/node-x2-y0   10T    6T     4T   60%",
                     "/dev/grid/node-x2-y1    9T    8T     1T   88%",
                     "/dev/grid/node-x2-y2    9T    6T     3T   66%"]
            .into_iter()
            .map(|s| s.parse::<NodeListing>().unwrap())
            .map(|listing| (listing.pos, listing.info))
            .collect();
        assert_eq!(solve(&nodes).unwrap().len(), 7);
    }
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use gl_context::*;
use libc::types::common::c95;
use queue::Queue;
use shader::*;
use std::cmp;
use std::mem;
use std::ptr;
use std::raw;
use std::rc::Rc;
use vertex;

// TODO: Don't 1-1 vertex array objects with vertex buffers

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case_functions)]
fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| unsafe { gl::GetAttribLocation(shader_program, ptr) })
}

/// Ensures a slice has a given alignment, and converts it to a raw pointer.
unsafe fn aligned_slice_to_ptr<T, U>(vs: &[T], alignment: uint) -> *const U {
  let vs_as_slice : raw::Slice<T> = mem::transmute(vs);
  assert!(
    (vs_as_slice.data as uint & (alignment - 1) == 0),
    "0x{:x} not {}-aligned",
    vs_as_slice.data as uint,
    alignment
  );
  assert!(vs_as_slice.data != ptr::null());
  vs_as_slice.data as *const U
}

/// A fixed-capacity array of GLfloats passed to OpenGL.
pub struct GLfloatBuffer {
  pub vertex_array: u32,
  pub vertex_buffer: u32,
  pub length: uint,
  pub capacity: uint,
  pub shader: Rc<Shader>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// size of vertex attribs, in GLfloats.
  pub attrib_span: uint,
}

pub enum DrawMode {
  Lines,
  Triangles,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match self {
      &Lines     => gl::LINES,
      &Triangles => gl::TRIANGLES,
    }
  }
}

impl GLfloatBuffer {
  #[inline]
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub unsafe fn new(
      _gl: &GLContext,
      shader_program: Rc<Shader>,
      attribs: &[vertex::AttribData],
      capacity: uint,
      mode: DrawMode) -> GLfloatBuffer {
    let mut vertex_array = 0;
    let mut vertex_buffer = 0;

    // TODO(cgaebel): Error checking?

    unsafe {
      gl::GenVertexArrays(1, &mut vertex_array);
      gl::GenBuffers(1, &mut vertex_buffer);
    }

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x}", err),
    }

    gl::BindVertexArray(vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x}", err),
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size;
      }
      attrib_span * mem::size_of::<GLfloat>()
    };
    for attrib in attribs.iter() {
      let shader_attrib = glGetAttribLocation((*shader_program).id, attrib.name) as GLuint;
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);

      gl::EnableVertexAttribArray(shader_attrib);
      unsafe {
        gl::VertexAttribPointer(
          shader_attrib,
          attrib.size as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          attrib_span as i32,
          ptr::null().offset(offset),
        );
      }
      offset += (attrib.size * mem::size_of::<GLfloat>()) as int;
    }

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x}", err),
    }

    unsafe {
      gl::BufferData(
        gl::ARRAY_BUFFER,
        (capacity * mem::size_of::<GLfloat>()) as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );

      match gl::GetError() {
        gl::NO_ERROR => {},
        gl::OUT_OF_MEMORY => fail!("Out of VRAM"),
        err => fail!("OpenGL error 0x{:x}", err),
      }
    }

    GLfloatBuffer {
      vertex_array:  vertex_array,
      vertex_buffer: vertex_buffer,
      length: 0,
      capacity: capacity,
      shader: shader_program,
      mode: mode.to_enum(),
      attrib_span: attrib_span / mem::size_of::<GLfloat>(),
    }
  }

  pub fn len(&self) -> uint {
    self.length
  }

  pub fn capacity(&self) -> uint {
    self.capacity
  }

  /// Analog of `std::vec::Vec::swap_remove`, but for GLfloatBuffer data.
  pub fn swap_remove(&mut self, _gl: &GLContext, i: uint, count: uint) {
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLfloatBuffer::swap_remove would cause copy in overlapping regions"
      );

      let va = self.vertex_array;
      let vb = self.vertex_buffer;

      gl::BindVertexArray(va);
      gl::BindBuffer(gl::ARRAY_BUFFER, vb);

      let byte_size = mem::size_of::<GLfloat>() as i64;
      gl::CopyBufferSubData(
        gl::ARRAY_BUFFER,
        gl::ARRAY_BUFFER,
        self.length as i64 * byte_size,
        i as i64 * byte_size,
        count as i64 * byte_size
      );
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &GLContext, vs: *const GLfloat, count: uint) {
    assert!(
      self.length + count <= self.capacity,
      "GLfloatBuffer::push {} into a {}/{} full GLfloatBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn update(&self, gl: &GLContext, idx: uint, vs: *const GLfloat, count: uint) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  fn update_inner(&self, _gl: &GLContext, idx: uint, vs: *const GLfloat, count: uint) {
    assert!(idx + count <= self.capacity);

    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    let byte_size = mem::size_of::<GLfloat>();
    unsafe {
      gl::BufferSubData(
          gl::ARRAY_BUFFER,
          (byte_size * idx) as i64,
          (byte_size * count) as i64,
          mem::transmute(vs)
      );
    }

    gl::Flush();
    gl::Finish();

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x} in GLfloatBuffer::update", err),
    }
  }

  #[inline]
  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, gl: &GLContext, start: uint, len: uint) {
    assert!(start + len <= self.len());

    gl.use_shader(self.shader.deref(), |_gl| {
      gl::BindVertexArray(self.vertex_array);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

      gl::DrawArrays(self.mode, start as i32, (len / self.attrib_span) as i32);
    });
  }
}

#[unsafe_destructor]
impl Drop for GLfloatBuffer {
  #[inline]
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer);
      gl::DeleteVertexArrays(1, &self.vertex_array);
    }
  }
}

/// A `GLfloatBuffer` that pushes slices of data at a time.
/// These slices are expected to be a fixed size (or multiples of that size).
/// Indexing operations and lengths are in terms of contiguous blocks of that
/// size (i.e. refering to index 2 when `slice_span` is 3 means referring to a
/// contiguous block of size 3 starting at index 6 in the underlying GLfloatBuffer.
pub struct GLSliceBuffer<T> {
  pub gl_buffer: GLfloatBuffer,
  /// Each index in the GLfloatBuffer is the index of a contiguous block of
  /// `slice_span` elements.
  pub slice_span: uint,

  /// in-memory buffer before sending to OpenGL.
  pub buffer: Queue<T>,
}

impl<T: Clone> GLSliceBuffer<T> {
  fn glfloat_ratio() -> uint {
    assert!(mem::size_of::<T>() % mem::size_of::<GLfloat>() == 0);
    mem::size_of::<T>() / mem::size_of::<GLfloat>()
  }

  pub unsafe fn new(
    gl: &GLContext,
    shader_program: Rc<Shader>,
    attribs: &[vertex::AttribData],
    slice_span: uint,
    capacity: uint,
    mode: DrawMode
  ) -> GLSliceBuffer<T> {
    let capacity = capacity * slice_span;
    let gl_buffer =
      GLfloatBuffer::new(
        gl,
        shader_program,
        attribs,
        capacity * GLSliceBuffer::<T>::glfloat_ratio(),
        mode
      );
    GLSliceBuffer {
      gl_buffer: gl_buffer,
      slice_span: slice_span,
      buffer: Queue::new(capacity),
    }
  }

  pub fn len(&self) -> uint {
    self.gl_buffer.len() / GLSliceBuffer::<T>::glfloat_ratio() + self.buffer.len()
  }

  pub fn capacity(&self) -> uint {
    self.gl_buffer.capacity() / GLSliceBuffer::<T>::glfloat_ratio()
  }

  pub fn swap_remove(&mut self, gl: &GLContext, i: uint) {
    let i = i * self.slice_span;
    assert!(i < self.len());
    assert!(self.gl_buffer.len() % GLSliceBuffer::<T>::glfloat_ratio() == 0);
    let gl_len = self.gl_buffer.len() / GLSliceBuffer::<T>::glfloat_ratio();
    if i < gl_len {
      let i = i * GLSliceBuffer::<T>::glfloat_ratio();
      self.gl_buffer.swap_remove(gl, i, self.slice_span * GLSliceBuffer::<T>::glfloat_ratio());
    } else {
      self.buffer.swap_remove(i - gl_len, self.slice_span);
    }
  }

  /// Add more data into this buffer; the data are not pushed to OpenGL until
  /// flush() is called!
  pub fn push(&mut self, vs: &[T]) {
    assert!(vs.len() % self.slice_span == 0);
    assert!(self.len() + vs.len() <= self.capacity(),
      "GLSliceBuffer::push {} into a {}/{} full GLSliceBuffer",
      vs.len(),
      self.len(),
      self.capacity()
    );

    let prev_len = self.len();

    self.buffer.push_all(vs);

    assert!(self.len() == prev_len + vs.len());
  }

  pub fn flush(&mut self, gl: &GLContext, max: Option<uint>) {
    if self.buffer.is_empty() {
      return;
    }

    assert!(self.buffer.len() % self.slice_span == 0);
    assert!(self.len() <= self.capacity());

    let prev_len = self.len();

    let count = match max {
      None => self.buffer.len(),
      Some(x) => cmp::min(x * self.slice_span, self.buffer.len()),
    };

    unsafe {
      let (l, h) = self.buffer.slices(0, count);
      let s = mem::size_of::<GLfloat>();
      self.gl_buffer.push(
        gl,
        aligned_slice_to_ptr(l, s),
        l.len() * GLSliceBuffer::<T>::glfloat_ratio()
      );
      self.gl_buffer.push(
        gl,
        aligned_slice_to_ptr(h, s),
        h.len() * GLSliceBuffer::<T>::glfloat_ratio()
      );
    }

    self.buffer.pop(count);

    assert!(self.len() == prev_len);
  }

  pub fn update(&self, gl: &GLContext, idx: uint, vs: &[T]) {
    assert!(vs.len() % self.slice_span == 0);
    let s = mem::size_of::<GLfloat>();
    unsafe {
      self.gl_buffer.update(
        gl,
        idx * self.slice_span * GLSliceBuffer::<T>::glfloat_ratio(),
        aligned_slice_to_ptr(vs, s),
        vs.len() * GLSliceBuffer::<T>::glfloat_ratio()
      );
    }
  }

  pub fn draw(&self, gl: &GLContext) {
    self.gl_buffer.draw(gl);
  }

  pub fn draw_slice(&self, gl: &GLContext, start: uint, len: uint) {
    let s = self.slice_span * GLSliceBuffer::<T>::glfloat_ratio();
    self.gl_buffer.draw_slice(gl, start * s, len * s);
  }
}
<commit_msg>fix previous commit<commit_after>use gl;
use gl::types::*;
use gl_context::*;
use libc::types::common::c95;
use queue::Queue;
use shader::*;
use std::cmp;
use std::mem;
use std::ptr;
use std::raw;
use std::rc::Rc;
use vertex;

// TODO: Don't 1-1 vertex array objects with vertex buffers

/// Gets the id number for a given input of the shader program.
#[allow(non_snake_case_functions)]
fn glGetAttribLocation(shader_program: GLuint, name: &str) -> GLint {
  name.with_c_str(|ptr| unsafe { gl::GetAttribLocation(shader_program, ptr) })
}

/// Ensures a slice has a given alignment, and converts it to a raw pointer.
unsafe fn aligned_slice_to_ptr<T, U>(vs: &[T], alignment: uint) -> *const U {
  let vs_as_slice : raw::Slice<T> = mem::transmute(vs);
  assert!(
    (vs_as_slice.data as uint & (alignment - 1) == 0),
    "0x{:x} not {}-aligned",
    vs_as_slice.data as uint,
    alignment
  );
  assert!(vs_as_slice.data != ptr::null());
  vs_as_slice.data as *const U
}

/// A fixed-capacity array of GLfloats passed to OpenGL.
pub struct GLfloatBuffer {
  pub vertex_array: u32,
  pub vertex_buffer: u32,
  pub length: uint,
  pub capacity: uint,
  pub shader: Rc<Shader>,
  /// How to draw this buffer. Ex: gl::LINES, gl::TRIANGLES, etc.
  pub mode: GLenum,
  /// size of vertex attribs, in GLfloats.
  pub attrib_span: uint,
}

pub enum DrawMode {
  Lines,
  Triangles,
}

impl DrawMode {
  fn to_enum(&self) -> GLenum {
    match self {
      &Lines     => gl::LINES,
      &Triangles => gl::TRIANGLES,
    }
  }
}

impl GLfloatBuffer {
  #[inline]
  /// Creates a new array of objects on the GPU.
  /// capacity is provided in units of size slice_span.
  pub unsafe fn new(
      _gl: &GLContext,
      shader_program: Rc<Shader>,
      attribs: &[vertex::AttribData],
      capacity: uint,
      mode: DrawMode) -> GLfloatBuffer {
    let mut vertex_array = 0;
    let mut vertex_buffer = 0;

    // TODO(cgaebel): Error checking?

    unsafe {
      gl::GenVertexArrays(1, &mut vertex_array);
      gl::GenBuffers(1, &mut vertex_buffer);
    }

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x}", err),
    }

    gl::BindVertexArray(vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, vertex_buffer);

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x}", err),
    }

    let mut offset = 0;
    let attrib_span = {
      let mut attrib_span = 0;
      for attrib in attribs.iter() {
        attrib_span += attrib.size;
      }
      attrib_span * mem::size_of::<GLfloat>()
    };
    for attrib in attribs.iter() {
      let shader_attrib = glGetAttribLocation((*shader_program).id, attrib.name) as GLuint;
      assert!(shader_attrib != -1, "shader attribute \"{}\" not found", attrib.name);

      gl::EnableVertexAttribArray(shader_attrib);
      unsafe {
        gl::VertexAttribPointer(
          shader_attrib,
          attrib.size as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          attrib_span as i32,
          ptr::null().offset(offset),
        );
      }
      offset += (attrib.size * mem::size_of::<GLfloat>()) as int;
    }

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x}", err),
    }

    unsafe {
      gl::BufferData(
        gl::ARRAY_BUFFER,
        (capacity * mem::size_of::<GLfloat>()) as GLsizeiptr,
        ptr::null(),
        gl::DYNAMIC_DRAW,
      );

      match gl::GetError() {
        gl::NO_ERROR => {},
        gl::OUT_OF_MEMORY => fail!("Out of VRAM"),
        err => fail!("OpenGL error 0x{:x}", err),
      }
    }

    GLfloatBuffer {
      vertex_array:  vertex_array,
      vertex_buffer: vertex_buffer,
      length: 0,
      capacity: capacity,
      shader: shader_program,
      mode: mode.to_enum(),
      attrib_span: attrib_span / mem::size_of::<GLfloat>(),
    }
  }

  pub fn len(&self) -> uint {
    self.length
  }

  pub fn capacity(&self) -> uint {
    self.capacity
  }

  /// Analog of `std::vec::Vec::swap_remove`, but for GLfloatBuffer data.
  pub fn swap_remove(&mut self, _gl: &GLContext, i: uint, count: uint) {
    self.length -= count;
    assert!(i <= self.length);

    // In the `i == self.length` case, we don't bother with the swap;
    // decreasing `self.length` is enough.

    if i < self.length {
      assert!(
        i <= self.length - count,
        "GLfloatBuffer::swap_remove would cause copy in overlapping regions"
      );

      let va = self.vertex_array;
      let vb = self.vertex_buffer;

      gl::BindVertexArray(va);
      gl::BindBuffer(gl::ARRAY_BUFFER, vb);

      let byte_size = mem::size_of::<GLfloat>() as i64;
      gl::CopyBufferSubData(
        gl::ARRAY_BUFFER,
        gl::ARRAY_BUFFER,
        self.length as i64 * byte_size,
        i as i64 * byte_size,
        count as i64 * byte_size
      );
    }
  }

  /// Add more data into this buffer.
  pub unsafe fn push(&mut self, gl: &GLContext, vs: *const GLfloat, count: uint) {
    assert!(
      self.length + count <= self.capacity,
      "GLfloatBuffer::push {} into a {}/{} full GLfloatBuffer",
      count,
      self.length,
      self.capacity
    );

    self.update_inner(gl, self.length, vs, count);
    self.length += count;
  }

  pub fn update(&self, gl: &GLContext, idx: uint, vs: *const GLfloat, count: uint) {
    assert!(idx + count <= self.length);
    self.update_inner(gl, idx, vs, count);
  }

  fn update_inner(&self, _gl: &GLContext, idx: uint, vs: *const GLfloat, count: uint) {
    assert!(idx + count <= self.capacity);

    gl::BindVertexArray(self.vertex_array);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

    let byte_size = mem::size_of::<GLfloat>();
    unsafe {
      gl::BufferSubData(
          gl::ARRAY_BUFFER,
          (byte_size * idx) as i64,
          (byte_size * count) as i64,
          mem::transmute(vs)
      );
    }

    gl::Flush();
    gl::Finish();

    match gl::GetError() {
      gl::NO_ERROR => {},
      err => fail!("OpenGL error 0x{:x} in GLfloatBuffer::update", err),
    }
  }

  #[inline]
  /// Draws all the queued triangles to the screen.
  pub fn draw(&self, gl: &GLContext) {
    self.draw_slice(gl, 0, self.length);
  }

  /// Draw some subset of the triangle array.
  pub fn draw_slice(&self, gl: &GLContext, start: uint, len: uint) {
    assert!(start + len <= self.len());

    gl.use_shader(self.shader.deref(), |_gl| {
      gl::BindVertexArray(self.vertex_array);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer);

      gl::DrawArrays(self.mode, (start / self.attrib_span) as i32, (len / self.attrib_span) as i32);
    });
  }
}

#[unsafe_destructor]
impl Drop for GLfloatBuffer {
  #[inline]
  fn drop(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer);
      gl::DeleteVertexArrays(1, &self.vertex_array);
    }
  }
}

/// A `GLfloatBuffer` that pushes slices of data at a time.
/// These slices are expected to be a fixed size (or multiples of that size).
/// Indexing operations and lengths are in terms of contiguous blocks of that
/// size (i.e. refering to index 2 when `slice_span` is 3 means referring to a
/// contiguous block of size 3 starting at index 6 in the underlying GLfloatBuffer.
pub struct GLSliceBuffer<T> {
  pub gl_buffer: GLfloatBuffer,
  /// Each index in the GLfloatBuffer is the index of a contiguous block of
  /// `slice_span` elements.
  pub slice_span: uint,

  /// in-memory buffer before sending to OpenGL.
  pub buffer: Queue<T>,
}

impl<T: Clone> GLSliceBuffer<T> {
  fn glfloat_ratio() -> uint {
    assert!(mem::size_of::<T>() % mem::size_of::<GLfloat>() == 0);
    mem::size_of::<T>() / mem::size_of::<GLfloat>()
  }

  pub unsafe fn new(
    gl: &GLContext,
    shader_program: Rc<Shader>,
    attribs: &[vertex::AttribData],
    slice_span: uint,
    capacity: uint,
    mode: DrawMode
  ) -> GLSliceBuffer<T> {
    let capacity = capacity * slice_span;
    let gl_buffer =
      GLfloatBuffer::new(
        gl,
        shader_program,
        attribs,
        capacity * GLSliceBuffer::<T>::glfloat_ratio(),
        mode
      );
    GLSliceBuffer {
      gl_buffer: gl_buffer,
      slice_span: slice_span,
      buffer: Queue::new(capacity),
    }
  }

  pub fn len(&self) -> uint {
    self.gl_buffer.len() / GLSliceBuffer::<T>::glfloat_ratio() + self.buffer.len()
  }

  pub fn capacity(&self) -> uint {
    self.gl_buffer.capacity() / GLSliceBuffer::<T>::glfloat_ratio()
  }

  pub fn swap_remove(&mut self, gl: &GLContext, i: uint) {
    let i = i * self.slice_span;
    assert!(i < self.len());
    assert!(self.gl_buffer.len() % GLSliceBuffer::<T>::glfloat_ratio() == 0);
    let gl_len = self.gl_buffer.len() / GLSliceBuffer::<T>::glfloat_ratio();
    if i < gl_len {
      let i = i * GLSliceBuffer::<T>::glfloat_ratio();
      self.gl_buffer.swap_remove(gl, i, self.slice_span * GLSliceBuffer::<T>::glfloat_ratio());
    } else {
      self.buffer.swap_remove(i - gl_len, self.slice_span);
    }
  }

  /// Add more data into this buffer; the data are not pushed to OpenGL until
  /// flush() is called!
  pub fn push(&mut self, vs: &[T]) {
    assert!(vs.len() % self.slice_span == 0);
    assert!(self.len() + vs.len() <= self.capacity(),
      "GLSliceBuffer::push {} into a {}/{} full GLSliceBuffer",
      vs.len(),
      self.len(),
      self.capacity()
    );

    let prev_len = self.len();

    self.buffer.push_all(vs);

    assert!(self.len() == prev_len + vs.len());
  }

  pub fn flush(&mut self, gl: &GLContext, max: Option<uint>) {
    if self.buffer.is_empty() {
      return;
    }

    assert!(self.buffer.len() % self.slice_span == 0);
    assert!(self.len() <= self.capacity());

    let prev_len = self.len();

    let count = match max {
      None => self.buffer.len(),
      Some(x) => cmp::min(x * self.slice_span, self.buffer.len()),
    };

    unsafe {
      let (l, h) = self.buffer.slices(0, count);
      let s = mem::size_of::<GLfloat>();
      self.gl_buffer.push(
        gl,
        aligned_slice_to_ptr(l, s),
        l.len() * GLSliceBuffer::<T>::glfloat_ratio()
      );
      self.gl_buffer.push(
        gl,
        aligned_slice_to_ptr(h, s),
        h.len() * GLSliceBuffer::<T>::glfloat_ratio()
      );
    }

    self.buffer.pop(count);

    assert!(self.len() == prev_len);
  }

  pub fn update(&self, gl: &GLContext, idx: uint, vs: &[T]) {
    assert!(vs.len() % self.slice_span == 0);
    let s = mem::size_of::<GLfloat>();
    unsafe {
      self.gl_buffer.update(
        gl,
        idx * self.slice_span * GLSliceBuffer::<T>::glfloat_ratio(),
        aligned_slice_to_ptr(vs, s),
        vs.len() * GLSliceBuffer::<T>::glfloat_ratio()
      );
    }
  }

  pub fn draw(&self, gl: &GLContext) {
    self.gl_buffer.draw(gl);
  }

  pub fn draw_slice(&self, gl: &GLContext, start: uint, len: uint) {
    let s = self.slice_span * GLSliceBuffer::<T>::glfloat_ratio();
    self.gl_buffer.draw_slice(gl, start * s, len * s);
  }
}
<|endoftext|>


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

//! Compute API (v2 with microversions) implementation.
//!
//! Currently supported functionality:
//!
//! * [server management](struct.ServerManager.html) (incomplete)
//!
//! # Examples
//!
//! ```rust,no_run
//! use openstack;
//!
//! let auth = openstack::auth::Identity::from_env()
//!     .expect("Unable to authenticate");
//! let session = openstack::Session::new(auth);
//! let servers = openstack::compute::v2::servers(&session);
//!
//! let server = servers.get("8a1c355b-2e1e-440a-8aa8-f272df72bc32")
//!     .expect("Unable to get a server");
//! ```
//!
//! Compute API supports version negotiation:
//!
//! ```rust,no_run
//! use openstack;
//!
//! let auth = openstack::auth::Identity::from_env()
//!     .expect("Unable to authenticate");
//! let mut session = openstack::Session::new(auth);
//! let version = session.negotiate_api_version::<openstack::compute::V2>(
//!     openstack::ApiVersionRequest::Exact(openstack::ApiVersion(2, 10))
//! ).expect("API version 2.10 is not supported");
//!
//! let servers = openstack::compute::v2::servers(&session);
//! ```

mod base;
mod servermanager;
mod protocol;

pub use self::base::V2;
pub use self::protocol::{AddressType, ServerAddress, ServerSortKey,
                         ServerStatus};
pub use self::servermanager::{servers, Server, ServerList, ServerManager,
                              ServerQuery, ServerSummary};
<commit_msg>fix(compute): expose FlavorRef and ImageRef as public<commit_after>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Compute API (v2 with microversions) implementation.
//!
//! Currently supported functionality:
//!
//! * [server management](struct.ServerManager.html) (incomplete)
//!
//! # Examples
//!
//! ```rust,no_run
//! use openstack;
//!
//! let auth = openstack::auth::Identity::from_env()
//!     .expect("Unable to authenticate");
//! let session = openstack::Session::new(auth);
//! let servers = openstack::compute::v2::servers(&session);
//!
//! let server = servers.get("8a1c355b-2e1e-440a-8aa8-f272df72bc32")
//!     .expect("Unable to get a server");
//! ```
//!
//! Compute API supports version negotiation:
//!
//! ```rust,no_run
//! use openstack;
//!
//! let auth = openstack::auth::Identity::from_env()
//!     .expect("Unable to authenticate");
//! let mut session = openstack::Session::new(auth);
//! let version = session.negotiate_api_version::<openstack::compute::V2>(
//!     openstack::ApiVersionRequest::Exact(openstack::ApiVersion(2, 10))
//! ).expect("API version 2.10 is not supported");
//!
//! let servers = openstack::compute::v2::servers(&session);
//! ```

mod base;
mod servermanager;
mod protocol;

pub use self::base::V2;
pub use self::protocol::{AddressType, ServerAddress, ServerSortKey,
                         ServerStatus};
pub use self::servermanager::{servers, Server, ServerList, ServerManager,
                              ServerQuery, ServerSummary, FlavorRef, ImageRef};
<|endoftext|>


<commit_before>// Copyright (c) 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A cryptographic hash generator dependent upon Windows's `CryptoAPI`.
//!
//! Originally based on:
//! https://github.com/rust-lang/cargo/blob/0.10.0/src/cargo/util/sha256.rs
//! which is copyright (c) 2014 The Rust Project Developers under the MIT license.

use super::Algorithm;
use std::io;
use std::ptr;
use winapi::shared::minwindef::DWORD;
use winapi::um::wincrypt::{
    CALG_MD5, CALG_SHA1, CALG_SHA_256, CALG_SHA_512, CryptAcquireContextW, CryptCreateHash,
    CryptDestroyHash, CryptGetHashParam, CryptHashData, CryptReleaseContext, CRYPT_SILENT,
    CRYPT_VERIFYCONTEXT, HCRYPTHASH, HCRYPTPROV, HP_HASHVAL, PROV_RSA_AES,
};

macro_rules! call {
    ($e:expr) => {{
        if $e == 0 {
            panic!("failed {}: {}", stringify!($e), io::Error::last_os_error())
        }
    }};
}

macro_rules! finish_algorithm {
    ($func_name: ident, $size: ident) => {
        fn $func_name(&mut self) -> Vec<u8> {
            let mut len = $size as u32;
            let mut hash = [0u8; $size];
            call!(unsafe {
                CryptGetHashParam(self.hcrypthash, HP_HASHVAL, hash.as_mut_ptr(), &mut len, 0)
            });
            assert_eq!(len as usize, hash.len());
            hash.to_vec()
        }
    }
}

const MD5_LENGTH: usize = 16;
const SHA1_LENGTH: usize = 20;
const SHA256_LENGTH: usize = 32;
const SHA512_LENGTH: usize = 64;

/// Generator of digests using a cryptographic hash function.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, Hasher};
/// use std::io::Write;
///
/// let mut hasher = Hasher::new(&Algorithm::SHA256);
/// hasher.write_all(b"crypto");
/// hasher.write_all(b"-");
/// hasher.write_all(b"hash");
/// let result = hasher.finish();
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub struct Hasher {
    algorithm: Algorithm,
    hcryptprov: HCRYPTPROV,
    hcrypthash: HCRYPTHASH,
}

impl Hasher {
    /// Create a new `Hasher` for the given `Algorithm`.
    pub fn new(algorithm: &Algorithm) -> Hasher {
        let mut hcp = 0;
        call!(unsafe {
            CryptAcquireContextW(
                &mut hcp,
                ptr::null(),
                ptr::null(),
                PROV_RSA_AES,
                CRYPT_VERIFYCONTEXT | CRYPT_SILENT,
            )
        });

        let hash_type = match algorithm {
            Algorithm::MD5 => CALG_MD5,
            Algorithm::SHA1 => CALG_SHA1,
            Algorithm::SHA256 => CALG_SHA_256,
            Algorithm::SHA512 => CALG_SHA_512,
        };

        let mut ret = Hasher {
            algorithm: algorithm,
            hcryptprov: hcp,
            hcrypthash: 0,
        };

        call!(unsafe { CryptCreateHash(ret.hcryptprov, hash_type, 0, 0, &mut ret.hcrypthash) });
        ret
    }

    /// Generate a digest from the data written to the `Hasher`.
    pub fn finish(&mut self) -> Vec<u8> {
        match self.algorithm {
            Algorithm::MD5 => self.finish_md5(),
            Algorithm::SHA1 => self.finish_sha1(),
            Algorithm::SHA256 => self.finish_sha256(),
            Algorithm::SHA512 => self.finish_sha512(),
        }
    }

    finish_algorithm!(finish_md5, MD5_LENGTH);
    finish_algorithm!(finish_sha1, SHA1_LENGTH);
    finish_algorithm!(finish_sha256, SHA256_LENGTH);
    finish_algorithm!(finish_sha512, SHA512_LENGTH);
}

impl io::Write for Hasher {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        call!(unsafe {
            CryptHashData(
                self.hcrypthash,
                buf.as_ptr() as *mut _,
                buf.len() as DWORD,
                0,
            )
        });
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for Hasher {
    fn drop(&mut self) {
        if self.hcrypthash != 0 {
            call!(unsafe { CryptDestroyHash(self.hcrypthash) });
        }
        call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) });
    }
}
<commit_msg>Rustfmt<commit_after>// Copyright (c) 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A cryptographic hash generator dependent upon Windows's `CryptoAPI`.
//!
//! Originally based on:
//! https://github.com/rust-lang/cargo/blob/0.10.0/src/cargo/util/sha256.rs
//! which is copyright (c) 2014 The Rust Project Developers under the MIT license.

use super::Algorithm;
use std::io;
use std::ptr;
use winapi::shared::minwindef::DWORD;
use winapi::um::wincrypt::{
    CryptAcquireContextW, CryptCreateHash, CryptDestroyHash, CryptGetHashParam, CryptHashData,
    CryptReleaseContext, CALG_MD5, CALG_SHA1, CALG_SHA_256, CALG_SHA_512, CRYPT_SILENT,
    CRYPT_VERIFYCONTEXT, HCRYPTHASH, HCRYPTPROV, HP_HASHVAL, PROV_RSA_AES,
};

macro_rules! call {
    ($e:expr) => {{
        if $e == 0 {
            panic!("failed {}: {}", stringify!($e), io::Error::last_os_error())
        }
    }};
}

macro_rules! finish_algorithm {
    ($func_name: ident, $size: ident) => {
        fn $func_name(&mut self) -> Vec<u8> {
            let mut len = $size as u32;
            let mut hash = [0u8; $size];
            call!(unsafe {
                CryptGetHashParam(self.hcrypthash, HP_HASHVAL, hash.as_mut_ptr(), &mut len, 0)
            });
            assert_eq!(len as usize, hash.len());
            hash.to_vec()
        }
    }
}

const MD5_LENGTH: usize = 16;
const SHA1_LENGTH: usize = 20;
const SHA256_LENGTH: usize = 32;
const SHA512_LENGTH: usize = 64;

/// Generator of digests using a cryptographic hash function.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, Hasher};
/// use std::io::Write;
///
/// let mut hasher = Hasher::new(&Algorithm::SHA256);
/// hasher.write_all(b"crypto");
/// hasher.write_all(b"-");
/// hasher.write_all(b"hash");
/// let result = hasher.finish();
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub struct Hasher {
    algorithm: Algorithm,
    hcryptprov: HCRYPTPROV,
    hcrypthash: HCRYPTHASH,
}

impl Hasher {
    /// Create a new `Hasher` for the given `Algorithm`.
    pub fn new(algorithm: &Algorithm) -> Hasher {
        let mut hcp = 0;
        call!(unsafe {
            CryptAcquireContextW(
                &mut hcp,
                ptr::null(),
                ptr::null(),
                PROV_RSA_AES,
                CRYPT_VERIFYCONTEXT | CRYPT_SILENT,
            )
        });

        let hash_type = match algorithm {
            Algorithm::MD5 => CALG_MD5,
            Algorithm::SHA1 => CALG_SHA1,
            Algorithm::SHA256 => CALG_SHA_256,
            Algorithm::SHA512 => CALG_SHA_512,
        };

        let mut ret = Hasher {
            algorithm: algorithm,
            hcryptprov: hcp,
            hcrypthash: 0,
        };

        call!(unsafe { CryptCreateHash(ret.hcryptprov, hash_type, 0, 0, &mut ret.hcrypthash) });
        ret
    }

    /// Generate a digest from the data written to the `Hasher`.
    pub fn finish(&mut self) -> Vec<u8> {
        match self.algorithm {
            Algorithm::MD5 => self.finish_md5(),
            Algorithm::SHA1 => self.finish_sha1(),
            Algorithm::SHA256 => self.finish_sha256(),
            Algorithm::SHA512 => self.finish_sha512(),
        }
    }

    finish_algorithm!(finish_md5, MD5_LENGTH);
    finish_algorithm!(finish_sha1, SHA1_LENGTH);
    finish_algorithm!(finish_sha256, SHA256_LENGTH);
    finish_algorithm!(finish_sha512, SHA512_LENGTH);
}

impl io::Write for Hasher {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        call!(unsafe {
            CryptHashData(
                self.hcrypthash,
                buf.as_ptr() as *mut _,
                buf.len() as DWORD,
                0,
            )
        });
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for Hasher {
    fn drop(&mut self) {
        if self.hcrypthash != 0 {
            call!(unsafe { CryptDestroyHash(self.hcrypthash) });
        }
        call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) });
    }
}
<|endoftext|>


<commit_before>use futures::stable::block_on_stable;
use futures::executor::{block_on, ThreadPool};
use futures::prelude::*;

#[async]
fn foo() -> Result<i32, i32> {
    Ok(1)
}

#[async]
fn bar(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async]
fn baz(x: i32) -> Result<i32, i32> {
    await!(bar(&x))
}

#[async_move]
fn qux(x: i32) -> Result<i32, i32> {
    await!(baz(x).pin())
}

// This test is to check that the internal __await macro generated in each
// function does not leak across function boundaries. If it did then calling
// the #[async] version of __await in the #[async_move] function should cause
// a 'borrow may still be in use when generator yields' error, while calling
// the #[async_move] version in the #[async] function should fail because `bar`
// does not implement `Future`.
#[async_move]
fn qux2(x: i32) -> Result<i32, i32> {
    #[async]
    fn baz2(x: i32) -> Result<i32, i32> {
        await!(bar(&x))
    }
    await!(baz2(x).pin())
}

#[async(pinned)]
fn boxed(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned)]
fn boxed_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn boxed_send(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned_send)]
fn boxed_send_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn spawnable() -> Result<(), Never> {
    Ok(())
}

#[async_stream(item = u64)]
fn _stream1() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async]
pub fn uses_async_for() -> Result<Vec<u64>, i32> {
    let mut v = vec![];
    #[async]
    for i in _stream1() {
        v.push(i);
    }
    Ok(v)
}

#[test]
fn main() {
    assert_eq!(block_on_stable(foo()), Ok(1));
    assert_eq!(block_on_stable(bar(&1)), Ok(1));
    assert_eq!(block_on_stable(baz(17)), Ok(17));
    assert_eq!(block_on_stable(qux(17)), Ok(17));
    assert_eq!(block_on_stable(qux2(17)), Ok(17));
    assert_eq!(block_on(boxed(17)), Ok(17));
    assert_eq!(block_on(boxed_send(17)), Ok(17));
    assert_eq!(block_on_stable(uses_async_for()), Ok(vec![0, 1]));
}

#[test]
fn run_pinned_future_in_thread_pool() {
    let mut pool = ThreadPool::new();
    pool.spawn_pinned(spawnable()).unwrap();
}
<commit_msg>Add pinned async stream test<commit_after>use futures::stable::block_on_stable;
use futures::executor::{block_on, ThreadPool};
use futures::prelude::*;

#[async]
fn foo() -> Result<i32, i32> {
    Ok(1)
}

#[async]
fn bar(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async]
fn baz(x: i32) -> Result<i32, i32> {
    await!(bar(&x))
}

#[async_move]
fn qux(x: i32) -> Result<i32, i32> {
    await!(baz(x).pin())
}

// This test is to check that the internal __await macro generated in each
// function does not leak across function boundaries. If it did then calling
// the #[async] version of __await in the #[async_move] function should cause
// a 'borrow may still be in use when generator yields' error, while calling
// the #[async_move] version in the #[async] function should fail because `bar`
// does not implement `Future`.
#[async_move]
fn qux2(x: i32) -> Result<i32, i32> {
    #[async]
    fn baz2(x: i32) -> Result<i32, i32> {
        await!(bar(&x))
    }
    await!(baz2(x).pin())
}

#[async(pinned)]
fn boxed(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned)]
fn boxed_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn boxed_send(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned_send)]
fn boxed_send_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn spawnable() -> Result<(), Never> {
    Ok(())
}

#[async_stream(item = u64)]
fn _stream1() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async_stream(pinned, item = u64)]
fn _stream_boxed() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async]
pub fn uses_async_for() -> Result<Vec<u64>, i32> {
    let mut v = vec![];
    #[async]
    for i in _stream1() {
        v.push(i);
    }
    Ok(v)
}

#[test]
fn main() {
    assert_eq!(block_on_stable(foo()), Ok(1));
    assert_eq!(block_on_stable(bar(&1)), Ok(1));
    assert_eq!(block_on_stable(baz(17)), Ok(17));
    assert_eq!(block_on_stable(qux(17)), Ok(17));
    assert_eq!(block_on_stable(qux2(17)), Ok(17));
    assert_eq!(block_on(boxed(17)), Ok(17));
    assert_eq!(block_on(boxed_send(17)), Ok(17));
    assert_eq!(block_on_stable(uses_async_for()), Ok(vec![0, 1]));
}

#[test]
fn run_pinned_future_in_thread_pool() {
    let mut pool = ThreadPool::new();
    pool.spawn_pinned(spawnable()).unwrap();
}
<|endoftext|>