<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use super::*;
use data_model::{DataInit, Le32};
use kvm::Datamatch;
use pci::{
    PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciDevice, PciDeviceError,
    PciHeaderType, PciInterruptPin, PciSubclass,
};
use resources::SystemAllocator;
use sys_util::{EventFd, GuestMemory, Result};

use self::virtio_pci_common_config::VirtioPciCommonConfig;

enum PciCapabilityType {
    CommonConfig = 1,
    NotifyConfig = 2,
    IsrConfig = 3,
    DeviceConfig = 4,
    PciConfig = 5,
}

#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Copy)]
struct VirtioPciCap {
    cap_len: u8,      // Generic PCI field: capability length
    cfg_type: u8,     // Identifies the structure.
    bar: u8,          // Where to find it.
    padding: [u8; 3], // Pad to full dword.
    offset: Le32,     // Offset within bar.
    length: Le32,     // Length of the structure, in bytes.
}
// It is safe to implement DataInit; all members are simple numbers and any value is valid.
unsafe impl DataInit for VirtioPciCap {}

impl PciCapability for VirtioPciCap {
    fn bytes(&self) -> &[u8] {
        self.as_slice()
    }

    fn id(&self) -> PciCapabilityID {
        PciCapabilityID::VendorSpecific
    }
}

const VIRTIO_PCI_CAPABILITY_BYTES: u8 = 16;

impl VirtioPciCap {
    pub fn new(cfg_type: PciCapabilityType, bar: u8, offset: u32, length: u32) -> Self {
        VirtioPciCap {
            cap_len: VIRTIO_PCI_CAPABILITY_BYTES,
            cfg_type: cfg_type as u8,
            bar,
            padding: [0; 3],
            offset: Le32::from(offset),
            length: Le32::from(length),
        }
    }
}

#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Copy)]
struct VirtioPciNotifyCap {
    cap: VirtioPciCap,
    notify_off_multiplier: Le32,
}
// It is safe to implement DataInit; all members are simple numbers and any value is valid.
unsafe impl DataInit for VirtioPciNotifyCap {}

impl PciCapability for VirtioPciNotifyCap {
    fn bytes(&self) -> &[u8] {
        self.as_slice()
    }

    fn id(&self) -> PciCapabilityID {
        PciCapabilityID::VendorSpecific
    }
}

impl VirtioPciNotifyCap {
    pub fn new(
        cfg_type: PciCapabilityType,
        bar: u8,
        offset: u32,
        length: u32,
        multiplier: Le32,
    ) -> Self {
        VirtioPciNotifyCap {
            cap: VirtioPciCap {
                cap_len: std::mem::size_of::<VirtioPciNotifyCap>() as u8,
                cfg_type: cfg_type as u8,
                bar,
                padding: [0; 3],
                offset: Le32::from(offset),
                length: Le32::from(length),
            },
            notify_off_multiplier: multiplier,
        }
    }
}

/// Subclasses for virtio.
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum PciVirtioSubclass {
    NonTransitionalBase = 0xff,
}

impl PciSubclass for PciVirtioSubclass {
    fn get_register_value(&self) -> u8 {
        *self as u8
    }
}

// Allocate one bar for the structs pointed to by the capability structures.
const COMMON_CONFIG_BAR_OFFSET: u64 = 0x0000;
const COMMON_CONFIG_SIZE: u64 = 56;
const ISR_CONFIG_BAR_OFFSET: u64 = 0x1000;
const ISR_CONFIG_SIZE: u64 = 1;
const DEVICE_CONFIG_BAR_OFFSET: u64 = 0x2000;
const DEVICE_CONFIG_SIZE: u64 = 0x1000;
const NOTIFICATION_BAR_OFFSET: u64 = 0x3000;
const NOTIFICATION_SIZE: u64 = 0x1000;
const CAPABILITY_BAR_SIZE: u64 = 0x4000;

const NOTIFY_OFF_MULTIPLIER: u32 = 4; // A dword per notification address.

const VIRTIO_PCI_VENDOR_ID: u16 = 0x1af4;
const VIRTIO_PCI_DEVICE_ID_BASE: u16 = 0x1040; // Add to device type to get device ID.

/// Implements the
/// [PCI](http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-650001)
/// transport for virtio devices.
pub struct VirtioPciDevice {
    config_regs: PciConfiguration,

    device: Box<VirtioDevice>,
    device_activated: bool,

    interrupt_status: Arc<AtomicUsize>,
    interrupt_evt: Option<EventFd>,
    queues: Vec<Queue>,
    queue_evts: Vec<EventFd>,
    mem: Option<GuestMemory>,
    settings_bar: u8,

    common_config: VirtioPciCommonConfig,
}

impl VirtioPciDevice {
    /// Constructs a new PCI transport for the given virtio device.
    pub fn new(mem: GuestMemory, device: Box<VirtioDevice>) -> Result<Self> {
        let mut queue_evts = Vec::new();
        for _ in device.queue_max_sizes().iter() {
            queue_evts.push(EventFd::new()?)
        }
        let queues = device
            .queue_max_sizes()
            .iter()
            .map(|&s| Queue::new(s))
            .collect();

        let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + device.device_type() as u16;

        let config_regs = PciConfiguration::new(
            VIRTIO_PCI_VENDOR_ID,
            pci_device_id,
            PciClassCode::Other,
            &PciVirtioSubclass::NonTransitionalBase,
            None,
            PciHeaderType::Device,
            VIRTIO_PCI_VENDOR_ID,
            pci_device_id,
        );

        Ok(VirtioPciDevice {
            config_regs,
            device,
            device_activated: false,
            interrupt_status: Arc::new(AtomicUsize::new(0)),
            interrupt_evt: None,
            queues,
            queue_evts,
            mem: Some(mem),
            settings_bar: 0,
            common_config: VirtioPciCommonConfig {
                driver_status: 0,
                config_generation: 0,
                device_feature_select: 0,
                driver_feature_select: 0,
                queue_select: 0,
            },
        })
    }

    /// Gets the list of queue events that must be triggered whenever the VM writes to
    /// `virtio::NOTIFY_REG_OFFSET` past the MMIO base. Each event must be triggered when the
    /// value being written equals the index of the event in this list.
    pub fn queue_evts(&self) -> &[EventFd] {
        self.queue_evts.as_slice()
    }

    /// Gets the event this device uses to interrupt the VM when the used queue is changed.
    pub fn interrupt_evt(&self) -> Option<&EventFd> {
        self.interrupt_evt.as_ref()
    }

    fn is_driver_ready(&self) -> bool {
        let ready_bits =
            (DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_DRIVER_OK | DEVICE_FEATURES_OK) as u8;
        self.common_config.driver_status == ready_bits
            && self.common_config.driver_status & DEVICE_FAILED as u8 == 0
    }

    fn are_queues_valid(&self) -> bool {
        if let Some(mem) = self.mem.as_ref() {
            self.queues.iter().all(|q| q.is_valid(mem))
        } else {
            false
        }
    }

    fn add_pci_capabilities(&mut self, settings_bar: u8) {
        // Add pointers to the different configuration structures from the PCI capabilities.
        let common_cap = VirtioPciCap::new(
            PciCapabilityType::CommonConfig,
            settings_bar,
            COMMON_CONFIG_BAR_OFFSET as u32,
            COMMON_CONFIG_SIZE as u32,
        );
        self.config_regs.add_capability(&common_cap);

        let isr_cap = VirtioPciCap::new(
            PciCapabilityType::IsrConfig,
            settings_bar,
            ISR_CONFIG_BAR_OFFSET as u32,
            ISR_CONFIG_SIZE as u32,
        );
        self.config_regs.add_capability(&isr_cap);

        // TODO(dgreid) - set based on device's configuration size?
        let device_cap = VirtioPciCap::new(
            PciCapabilityType::DeviceConfig,
            settings_bar,
            DEVICE_CONFIG_BAR_OFFSET as u32,
            DEVICE_CONFIG_SIZE as u32,
        );
        self.config_regs.add_capability(&device_cap);

        let notify_cap = VirtioPciNotifyCap::new(
            PciCapabilityType::NotifyConfig,
            settings_bar,
            NOTIFICATION_BAR_OFFSET as u32,
            NOTIFICATION_SIZE as u32,
            Le32::from(NOTIFY_OFF_MULTIPLIER),
        );
        self.config_regs.add_capability(&notify_cap);

        //TODO(dgreid) - How will the configuration_cap work?
        let configuration_cap = VirtioPciCap::new(PciCapabilityType::PciConfig, 0, 0, 0);
        self.config_regs.add_capability(&configuration_cap);

        self.settings_bar = settings_bar;
    }
}

impl PciDevice for VirtioPciDevice {
    fn keep_fds(&self) -> Vec<RawFd> {
        let mut fds = self.device.keep_fds();
        if let Some(ref interrupt_evt) = self.interrupt_evt {
            fds.push(interrupt_evt.as_raw_fd());
        }
        fds
    }

    fn assign_irq(&mut self, irq_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin) {
        self.config_regs.set_irq(irq_num as u8, irq_pin);
        self.interrupt_evt = Some(irq_evt);
    }

    fn allocate_io_bars(
        &mut self,
        resources: &mut SystemAllocator,
    ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
        // Allocate one bar for the structures pointed to by the capability structures.
        let mut ranges = Vec::new();
        let settings_config_addr = resources
            .allocate_mmio_addresses(CAPABILITY_BAR_SIZE)
            .ok_or(PciDeviceError::IoAllocationFailed(CAPABILITY_BAR_SIZE))?;
        let settings_bar = self
            .config_regs
            .add_memory_region(settings_config_addr, CAPABILITY_BAR_SIZE)
            .ok_or(PciDeviceError::IoRegistrationFailed(settings_config_addr))?
            as u8;
        ranges.push((settings_config_addr, CAPABILITY_BAR_SIZE));

        // Once the BARs are allocated, the capabilities can be added to the PCI configuration.
        self.add_pci_capabilities(settings_bar);

        Ok(ranges)
    }

    fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
        let notify_base = bar0 + NOTIFICATION_BAR_OFFSET;
        self.queue_evts()
            .iter()
            .enumerate()
            .map(|(i, event)| {
                (
                    event,
                    notify_base + i as u64 * NOTIFY_OFF_MULTIPLIER as u64,
                    Datamatch::U16(Some(i as u16)),
                )
            }).collect()
    }

    fn config_registers(&self) -> &PciConfiguration {
        &self.config_regs
    }

    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
        &mut self.config_regs
    }

    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
        // The driver is only allowed to do aligned, properly sized access.
        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
        let offset = addr - bar0;
        match offset {
            o if COMMON_CONFIG_BAR_OFFSET <= o
                && o < COMMON_CONFIG_BAR_OFFSET + COMMON_CONFIG_SIZE =>
            {
                self.common_config.read(
                    o - COMMON_CONFIG_BAR_OFFSET,
                    data,
                    &mut self.queues,
                    &mut self.device,
                )
            }
            o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
                if let Some(v) = data.get_mut(0) {
                    *v = self.interrupt_status.load(Ordering::SeqCst) as u8;
                }
            }
            o if DEVICE_CONFIG_BAR_OFFSET <= o
                && o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
            {
                self.device.read_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
            }
            o if NOTIFICATION_BAR_OFFSET <= o
                && o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
            {
                // Handled with ioeventfds.
            }
            _ => (),
        }
    }

    fn write_bar(&mut self, addr: u64, data: &[u8]) {
        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
        let offset = addr - bar0;
        match offset {
            o if COMMON_CONFIG_BAR_OFFSET <= o
                && o < COMMON_CONFIG_BAR_OFFSET + COMMON_CONFIG_SIZE =>
            {
                self.common_config.write(
                    o - COMMON_CONFIG_BAR_OFFSET,
                    data,
                    &mut self.queues,
                    &mut self.device,
                )
            }
            o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
                if let Some(v) = data.get(0) {
                    self.interrupt_status
                        .fetch_and(!(*v as usize), Ordering::SeqCst);
                }
            }
            o if DEVICE_CONFIG_BAR_OFFSET <= o
                && o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
            {
                self.device.write_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
            }
            o if NOTIFICATION_BAR_OFFSET <= o
                && o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
            {
                // Handled with ioeventfds.
            }
            _ => (),
        };

        if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() {
            if let Some(interrupt_evt) = self.interrupt_evt.take() {
                if let Some(mem) = self.mem.take() {
                    self.device.activate(
                        mem,
                        interrupt_evt,
                        self.interrupt_status.clone(),
                        self.queues.clone(),
                        self.queue_evts.split_off(0),
                    );
                    self.device_activated = true;
                }
            }
        }
    }
}
<commit_msg>devices: virtio: pci: reset ISR status on read<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use super::*;
use data_model::{DataInit, Le32};
use kvm::Datamatch;
use pci::{
    PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciDevice, PciDeviceError,
    PciHeaderType, PciInterruptPin, PciSubclass,
};
use resources::SystemAllocator;
use sys_util::{EventFd, GuestMemory, Result};

use self::virtio_pci_common_config::VirtioPciCommonConfig;

enum PciCapabilityType {
    CommonConfig = 1,
    NotifyConfig = 2,
    IsrConfig = 3,
    DeviceConfig = 4,
    PciConfig = 5,
}

#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Copy)]
struct VirtioPciCap {
    cap_len: u8,      // Generic PCI field: capability length
    cfg_type: u8,     // Identifies the structure.
    bar: u8,          // Where to find it.
    padding: [u8; 3], // Pad to full dword.
    offset: Le32,     // Offset within bar.
    length: Le32,     // Length of the structure, in bytes.
}
// It is safe to implement DataInit; all members are simple numbers and any value is valid.
unsafe impl DataInit for VirtioPciCap {}

impl PciCapability for VirtioPciCap {
    fn bytes(&self) -> &[u8] {
        self.as_slice()
    }

    fn id(&self) -> PciCapabilityID {
        PciCapabilityID::VendorSpecific
    }
}

const VIRTIO_PCI_CAPABILITY_BYTES: u8 = 16;

impl VirtioPciCap {
    pub fn new(cfg_type: PciCapabilityType, bar: u8, offset: u32, length: u32) -> Self {
        VirtioPciCap {
            cap_len: VIRTIO_PCI_CAPABILITY_BYTES,
            cfg_type: cfg_type as u8,
            bar,
            padding: [0; 3],
            offset: Le32::from(offset),
            length: Le32::from(length),
        }
    }
}

#[allow(dead_code)]
#[repr(packed)]
#[derive(Clone, Copy)]
struct VirtioPciNotifyCap {
    cap: VirtioPciCap,
    notify_off_multiplier: Le32,
}
// It is safe to implement DataInit; all members are simple numbers and any value is valid.
unsafe impl DataInit for VirtioPciNotifyCap {}

impl PciCapability for VirtioPciNotifyCap {
    fn bytes(&self) -> &[u8] {
        self.as_slice()
    }

    fn id(&self) -> PciCapabilityID {
        PciCapabilityID::VendorSpecific
    }
}

impl VirtioPciNotifyCap {
    pub fn new(
        cfg_type: PciCapabilityType,
        bar: u8,
        offset: u32,
        length: u32,
        multiplier: Le32,
    ) -> Self {
        VirtioPciNotifyCap {
            cap: VirtioPciCap {
                cap_len: std::mem::size_of::<VirtioPciNotifyCap>() as u8,
                cfg_type: cfg_type as u8,
                bar,
                padding: [0; 3],
                offset: Le32::from(offset),
                length: Le32::from(length),
            },
            notify_off_multiplier: multiplier,
        }
    }
}

/// Subclasses for virtio.
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum PciVirtioSubclass {
    NonTransitionalBase = 0xff,
}

impl PciSubclass for PciVirtioSubclass {
    fn get_register_value(&self) -> u8 {
        *self as u8
    }
}

// Allocate one bar for the structs pointed to by the capability structures.
const COMMON_CONFIG_BAR_OFFSET: u64 = 0x0000;
const COMMON_CONFIG_SIZE: u64 = 56;
const ISR_CONFIG_BAR_OFFSET: u64 = 0x1000;
const ISR_CONFIG_SIZE: u64 = 1;
const DEVICE_CONFIG_BAR_OFFSET: u64 = 0x2000;
const DEVICE_CONFIG_SIZE: u64 = 0x1000;
const NOTIFICATION_BAR_OFFSET: u64 = 0x3000;
const NOTIFICATION_SIZE: u64 = 0x1000;
const CAPABILITY_BAR_SIZE: u64 = 0x4000;

const NOTIFY_OFF_MULTIPLIER: u32 = 4; // A dword per notification address.

const VIRTIO_PCI_VENDOR_ID: u16 = 0x1af4;
const VIRTIO_PCI_DEVICE_ID_BASE: u16 = 0x1040; // Add to device type to get device ID.

/// Implements the
/// [PCI](http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html#x1-650001)
/// transport for virtio devices.
pub struct VirtioPciDevice {
    config_regs: PciConfiguration,

    device: Box<VirtioDevice>,
    device_activated: bool,

    interrupt_status: Arc<AtomicUsize>,
    interrupt_evt: Option<EventFd>,
    queues: Vec<Queue>,
    queue_evts: Vec<EventFd>,
    mem: Option<GuestMemory>,
    settings_bar: u8,

    common_config: VirtioPciCommonConfig,
}

impl VirtioPciDevice {
    /// Constructs a new PCI transport for the given virtio device.
    pub fn new(mem: GuestMemory, device: Box<VirtioDevice>) -> Result<Self> {
        let mut queue_evts = Vec::new();
        for _ in device.queue_max_sizes().iter() {
            queue_evts.push(EventFd::new()?)
        }
        let queues = device
            .queue_max_sizes()
            .iter()
            .map(|&s| Queue::new(s))
            .collect();

        let pci_device_id = VIRTIO_PCI_DEVICE_ID_BASE + device.device_type() as u16;

        let config_regs = PciConfiguration::new(
            VIRTIO_PCI_VENDOR_ID,
            pci_device_id,
            PciClassCode::Other,
            &PciVirtioSubclass::NonTransitionalBase,
            None,
            PciHeaderType::Device,
            VIRTIO_PCI_VENDOR_ID,
            pci_device_id,
        );

        Ok(VirtioPciDevice {
            config_regs,
            device,
            device_activated: false,
            interrupt_status: Arc::new(AtomicUsize::new(0)),
            interrupt_evt: None,
            queues,
            queue_evts,
            mem: Some(mem),
            settings_bar: 0,
            common_config: VirtioPciCommonConfig {
                driver_status: 0,
                config_generation: 0,
                device_feature_select: 0,
                driver_feature_select: 0,
                queue_select: 0,
            },
        })
    }

    /// Gets the list of queue events that must be triggered whenever the VM writes to
    /// `virtio::NOTIFY_REG_OFFSET` past the MMIO base. Each event must be triggered when the
    /// value being written equals the index of the event in this list.
    pub fn queue_evts(&self) -> &[EventFd] {
        self.queue_evts.as_slice()
    }

    /// Gets the event this device uses to interrupt the VM when the used queue is changed.
    pub fn interrupt_evt(&self) -> Option<&EventFd> {
        self.interrupt_evt.as_ref()
    }

    fn is_driver_ready(&self) -> bool {
        let ready_bits =
            (DEVICE_ACKNOWLEDGE | DEVICE_DRIVER | DEVICE_DRIVER_OK | DEVICE_FEATURES_OK) as u8;
        self.common_config.driver_status == ready_bits
            && self.common_config.driver_status & DEVICE_FAILED as u8 == 0
    }

    fn are_queues_valid(&self) -> bool {
        if let Some(mem) = self.mem.as_ref() {
            self.queues.iter().all(|q| q.is_valid(mem))
        } else {
            false
        }
    }

    fn add_pci_capabilities(&mut self, settings_bar: u8) {
        // Add pointers to the different configuration structures from the PCI capabilities.
        let common_cap = VirtioPciCap::new(
            PciCapabilityType::CommonConfig,
            settings_bar,
            COMMON_CONFIG_BAR_OFFSET as u32,
            COMMON_CONFIG_SIZE as u32,
        );
        self.config_regs.add_capability(&common_cap);

        let isr_cap = VirtioPciCap::new(
            PciCapabilityType::IsrConfig,
            settings_bar,
            ISR_CONFIG_BAR_OFFSET as u32,
            ISR_CONFIG_SIZE as u32,
        );
        self.config_regs.add_capability(&isr_cap);

        // TODO(dgreid) - set based on device's configuration size?
        let device_cap = VirtioPciCap::new(
            PciCapabilityType::DeviceConfig,
            settings_bar,
            DEVICE_CONFIG_BAR_OFFSET as u32,
            DEVICE_CONFIG_SIZE as u32,
        );
        self.config_regs.add_capability(&device_cap);

        let notify_cap = VirtioPciNotifyCap::new(
            PciCapabilityType::NotifyConfig,
            settings_bar,
            NOTIFICATION_BAR_OFFSET as u32,
            NOTIFICATION_SIZE as u32,
            Le32::from(NOTIFY_OFF_MULTIPLIER),
        );
        self.config_regs.add_capability(&notify_cap);

        //TODO(dgreid) - How will the configuration_cap work?
        let configuration_cap = VirtioPciCap::new(PciCapabilityType::PciConfig, 0, 0, 0);
        self.config_regs.add_capability(&configuration_cap);

        self.settings_bar = settings_bar;
    }
}

impl PciDevice for VirtioPciDevice {
    fn keep_fds(&self) -> Vec<RawFd> {
        let mut fds = self.device.keep_fds();
        if let Some(ref interrupt_evt) = self.interrupt_evt {
            fds.push(interrupt_evt.as_raw_fd());
        }
        fds
    }

    fn assign_irq(&mut self, irq_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin) {
        self.config_regs.set_irq(irq_num as u8, irq_pin);
        self.interrupt_evt = Some(irq_evt);
    }

    fn allocate_io_bars(
        &mut self,
        resources: &mut SystemAllocator,
    ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> {
        // Allocate one bar for the structures pointed to by the capability structures.
        let mut ranges = Vec::new();
        let settings_config_addr = resources
            .allocate_mmio_addresses(CAPABILITY_BAR_SIZE)
            .ok_or(PciDeviceError::IoAllocationFailed(CAPABILITY_BAR_SIZE))?;
        let settings_bar = self
            .config_regs
            .add_memory_region(settings_config_addr, CAPABILITY_BAR_SIZE)
            .ok_or(PciDeviceError::IoRegistrationFailed(settings_config_addr))?
            as u8;
        ranges.push((settings_config_addr, CAPABILITY_BAR_SIZE));

        // Once the BARs are allocated, the capabilities can be added to the PCI configuration.
        self.add_pci_capabilities(settings_bar);

        Ok(ranges)
    }

    fn ioeventfds(&self) -> Vec<(&EventFd, u64, Datamatch)> {
        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
        let notify_base = bar0 + NOTIFICATION_BAR_OFFSET;
        self.queue_evts()
            .iter()
            .enumerate()
            .map(|(i, event)| {
                (
                    event,
                    notify_base + i as u64 * NOTIFY_OFF_MULTIPLIER as u64,
                    Datamatch::U16(Some(i as u16)),
                )
            }).collect()
    }

    fn config_registers(&self) -> &PciConfiguration {
        &self.config_regs
    }

    fn config_registers_mut(&mut self) -> &mut PciConfiguration {
        &mut self.config_regs
    }

    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
        // The driver is only allowed to do aligned, properly sized access.
        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
        let offset = addr - bar0;
        match offset {
            o if COMMON_CONFIG_BAR_OFFSET <= o
                && o < COMMON_CONFIG_BAR_OFFSET + COMMON_CONFIG_SIZE =>
            {
                self.common_config.read(
                    o - COMMON_CONFIG_BAR_OFFSET,
                    data,
                    &mut self.queues,
                    &mut self.device,
                )
            }
            o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
                if let Some(v) = data.get_mut(0) {
                    // Reading this register resets it to 0.
                    *v = self.interrupt_status.swap(0, Ordering::SeqCst) as u8;
                }
            }
            o if DEVICE_CONFIG_BAR_OFFSET <= o
                && o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
            {
                self.device.read_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
            }
            o if NOTIFICATION_BAR_OFFSET <= o
                && o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
            {
                // Handled with ioeventfds.
            }
            _ => (),
        }
    }

    fn write_bar(&mut self, addr: u64, data: &[u8]) {
        let bar0 = self.config_regs.get_bar_addr(self.settings_bar as usize) as u64;
        let offset = addr - bar0;
        match offset {
            o if COMMON_CONFIG_BAR_OFFSET <= o
                && o < COMMON_CONFIG_BAR_OFFSET + COMMON_CONFIG_SIZE =>
            {
                self.common_config.write(
                    o - COMMON_CONFIG_BAR_OFFSET,
                    data,
                    &mut self.queues,
                    &mut self.device,
                )
            }
            o if ISR_CONFIG_BAR_OFFSET <= o && o < ISR_CONFIG_BAR_OFFSET + ISR_CONFIG_SIZE => {
                if let Some(v) = data.get(0) {
                    self.interrupt_status
                        .fetch_and(!(*v as usize), Ordering::SeqCst);
                }
            }
            o if DEVICE_CONFIG_BAR_OFFSET <= o
                && o < DEVICE_CONFIG_BAR_OFFSET + DEVICE_CONFIG_SIZE =>
            {
                self.device.write_config(o - DEVICE_CONFIG_BAR_OFFSET, data);
            }
            o if NOTIFICATION_BAR_OFFSET <= o
                && o < NOTIFICATION_BAR_OFFSET + NOTIFICATION_SIZE =>
            {
                // Handled with ioeventfds.
            }
            _ => (),
        };

        if !self.device_activated && self.is_driver_ready() && self.are_queues_valid() {
            if let Some(interrupt_evt) = self.interrupt_evt.take() {
                if let Some(mem) = self.mem.take() {
                    self.device.activate(
                        mem,
                        interrupt_evt,
                        self.interrupt_status.clone(),
                        self.queues.clone(),
                        self.queue_evts.split_off(0),
                    );
                    self.device_activated = true;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use tensorflow_sys as ffi;

/// Test that the library is linked properly
#[test]
fn linkage() {
    unsafe {
        let buffer = ffi::TF_NewBuffer();
        assert!(!buffer.is_null());
        ffi::TF_DeleteBuffer(buffer);
    }
}

/// Test that the eager API works.
#[cfg(feature = "eager")]
#[test]
fn tfe_tensor_handle() {
    let data = vec![0.0f32; 100];
    let shape = [1, 10, 10];
    let num_elements = shape.iter().fold(1, |t, x| t * x) as usize;

    unsafe {
        let tf_tensor = ffi::TF_AllocateTensor(
            ffi::TF_FLOAT,
            shape.as_ptr(),
            shape.len() as i32,
            num_elements * std::mem::size_of::<f32>(),
        );
        std::ptr::copy_nonoverlapping(
            data.as_ptr(),
            ffi::TF_TensorData(tf_tensor) as *mut f32,
            ffi::TF_TensorByteSize(tf_tensor) / std::mem::size_of::<f32>(),
        );
        let status = ffi::TF_NewStatus();
        let tfe_handle = ffi::TFE_NewTensorHandle(tf_tensor, status);

        ffi::TF_DeleteStatus(status);
        ffi::TFE_DeleteTensorHandle(tfe_handle);
        ffi::TF_DeleteTensor(tf_tensor);
    }
}
<commit_msg>[tensorflow-sys] use product instead of fold<commit_after>use tensorflow_sys as ffi;

/// Test that the library is linked properly
#[test]
fn linkage() {
    unsafe {
        let buffer = ffi::TF_NewBuffer();
        assert!(!buffer.is_null());
        ffi::TF_DeleteBuffer(buffer);
    }
}

/// Test that the eager API works.
#[cfg(feature = "eager")]
#[test]
fn tfe_tensor_handle() {
    let data = vec![0.0f32; 100];
    let shape = [1, 10, 10];
    let num_elements = shape.iter().product::<i64>() as usize;

    unsafe {
        let tf_tensor = ffi::TF_AllocateTensor(
            ffi::TF_FLOAT,
            shape.as_ptr(),
            shape.len() as i32,
            num_elements * std::mem::size_of::<f32>(),
        );
        std::ptr::copy_nonoverlapping(
            data.as_ptr(),
            ffi::TF_TensorData(tf_tensor) as *mut f32,
            ffi::TF_TensorByteSize(tf_tensor) / std::mem::size_of::<f32>(),
        );
        let status = ffi::TF_NewStatus();
        let tfe_handle = ffi::TFE_NewTensorHandle(tf_tensor, status);

        ffi::TF_DeleteStatus(status);
        ffi::TFE_DeleteTensorHandle(tfe_handle);
        ffi::TF_DeleteTensor(tf_tensor);
    }
}
<|endoftext|>


<commit_before>//extern crate rustc_serialize;
//extern crate hyper;
//#[macro_use] extern crate lazy_static;

//mod util;

mod examples {
    mod hello_world;

}

#[test]
fn test_works() {}<commit_msg>Added files via upload<commit_after>//extern crate rustc_serialize;
//extern crate hyper;
//#[macro_use] extern crate lazy_static;

mod util;

mod examples {
    mod hello_w;
    mod hello_world;

}

#[test]
fn test_works() {}<|endoftext|>


<commit_before>// Copyright 2016 Mozilla
//
// 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.

extern crate datomish;

#[test]
fn can_import_sqlite() {
    // From https://github.com/jgallagher/rusqlite#rusqlite.
    #[derive(Debug)]
    struct Person {
        id: i32,
        name: String,
        data: Option<Vec<u8>>
    }

    let conn = datomish::get_connection();

    conn.execute("CREATE TABLE person (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  data            BLOB
                  )", &[]).unwrap();
    let me = Person {
        id: 1,
        name: "Steven".to_string(),
        data: None
    };
    conn.execute("INSERT INTO person (name, data)
                  VALUES (?1, ?2)",
                 &[&me.name, &me.data]).unwrap();

    let mut stmt = conn.prepare("SELECT id, name, data FROM person").unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        Person {
            id: row.get(0),
            name: row.get(1),
            data: row.get(2)
        }
    }).unwrap();

    for person in person_iter {
        let p = person.unwrap();
        assert_eq!(me.id, p.id);
        assert_eq!(me.data, p.data);
        assert_eq!(me.data, p.data);
    }
}
<commit_msg>Rename to Project Mentat (tests).<commit_after>// Copyright 2016 Mozilla
//
// 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.

extern crate mentat;

#[test]
fn can_import_sqlite() {
    // From https://github.com/jgallagher/rusqlite#rusqlite.
    #[derive(Debug)]
    struct Person {
        id: i32,
        name: String,
        data: Option<Vec<u8>>
    }

    let conn = mentat::get_connection();

    conn.execute("CREATE TABLE person (
                  id              INTEGER PRIMARY KEY,
                  name            TEXT NOT NULL,
                  data            BLOB
                  )", &[]).unwrap();
    let me = Person {
        id: 1,
        name: "Steven".to_string(),
        data: None
    };
    conn.execute("INSERT INTO person (name, data)
                  VALUES (?1, ?2)",
                 &[&me.name, &me.data]).unwrap();

    let mut stmt = conn.prepare("SELECT id, name, data FROM person").unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        Person {
            id: row.get(0),
            name: row.get(1),
            data: row.get(2)
        }
    }).unwrap();

    for person in person_iter {
        let p = person.unwrap();
        assert_eq!(me.id, p.id);
        assert_eq!(me.data, p.data);
        assert_eq!(me.data, p.data);
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixture parser.<commit_after>use std::io::{self, Read, BufReader, BufRead};
use std::env;
use std::fs::{self, DirEntry, File};
use std::path::Path;

#[test]
fn fixtures() {
    visit_fixtures(&env::current_dir().unwrap().join("tests").join("fixtures"), &|entry| {
        println!("fixture {:?}", entry.path());

        let f = File::open(entry.path()).expect("error opening fixture file");
        let fixture = match Fixture::new(f) {
            Err(e) => panic!("invalid test {:?}", e),
            Ok(f) => f,
        };

        println!("{:#?}", fixture);
    }).unwrap();
    assert!(false);
}

// one possible implementation of fs::walk_dir only visiting files
fn visit_fixtures(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(visit_fixtures(&entry.path(), cb));
            } else {
                if let Some(Some("test")) = entry.path().extension().map(|v| v.to_str()) {
                    cb(&entry);
                }
            }
        }
    }
    Ok(())
}

#[derive(Debug)]
enum FixtureError {
    ExpectedBlockStart,
    IoError,
}

#[derive(Debug)]
enum TemplateName {
    Main,
    Other(String),
}

#[derive(Debug)]
enum ReadState {
    Message(String),
    Template((TemplateName, String)),
    Data(String),
    Config(String),
    Expect(String)
}

#[derive(Debug)]
struct Fixture {
    message: Option<String>,
    template: Option<String>,
    templates: Vec<(String, String)>,
    data: Option<String>,
    config: Option<String>,
    expect: Option<String>,
}

const TEMPLATE_NAME_START: &'static str = "--TEMPLATE(";
const TEMPLATE_NAME_END: &'static str = ")--";

fn check_for_new_state(line: &str) -> Option<ReadState> {
    match &line[..] {
        "--TEST--" => Some(ReadState::Message(String::new())),
        "--DATA--" => Some(ReadState::Data(String::new())),
        "--CONFIG--" => Some(ReadState::Config(String::new())),
        "--EXPECT--" => Some(ReadState::Expect(String::new())),
        other => if other.starts_with("--TEMPLATE(") {
            let name = other[TEMPLATE_NAME_START.len()..other.len()-TEMPLATE_NAME_END.len()].to_string();
            Some(ReadState::Template((TemplateName::Other(name), String::new())))
        } else if other.starts_with("--TEMPLATE--") {
            Some(ReadState::Template((TemplateName::Main, String::new())))
        } else {
            None
        },
    }
}

impl Fixture {
    pub fn new<R: Read>(input: R) -> Result<Fixture, FixtureError> {
        let mut state = None;
        let mut fixture = Fixture {
            message: None,
            template: None,
            templates: Vec::new(),
            data: None,
            config: None,
            expect: None,
        };

        for maybe_line in BufReader::new(input).lines() {
            let line = match maybe_line {
                Ok(l) => l,
                Err(_) => return Err(FixtureError::IoError),
            };

            state = match state {
                None => {
                    Some(try!(check_for_new_state(&line).ok_or(FixtureError::ExpectedBlockStart)))
                },
                Some(mut old) => match check_for_new_state(&line) {
                    Some(new_state) => {
                        fixture.collect(old);
                        Some(new_state)
                    },
                    None => {
                        match old {
                            ReadState::Message(ref mut m) => { if m.len() > 0 { m.push_str("\n"); } m.push_str(&line); },
                            ReadState::Template((_, ref mut m)) => { if m.len() > 0 { m.push_str("\n"); }  m.push_str(&line); },
                            ReadState::Data(ref mut m) => { if m.len() > 0 { m.push_str("\n"); }  m.push_str(&line); },
                            ReadState::Config(ref mut m) => { if m.len() > 0 { m.push_str("\n"); }  m.push_str(&line); },
                            ReadState::Expect(ref mut m) => { if m.len() > 0 { m.push_str("\n"); }  m.push_str(&line); },
                        };
                        Some(old)
                    }
                },
            }
        }

        if let Some(leftover_state) = state {
            fixture.collect(leftover_state);
        }

        Ok(fixture)
    }

    fn collect(&mut self, state: ReadState) {
        match state {
            ReadState::Message(m) => self.message = Some(m),
            ReadState::Template((TemplateName::Main, m)) => self.template = Some(m),
            ReadState::Template((TemplateName::Other(name), m)) => {
                self.templates.push((name, m));
            },
            ReadState::Data(m) => self.data = Some(m),
            ReadState::Config(m) => self.config = Some(m),
            ReadState::Expect(m) => self.expect = Some(m),
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_int, c_ulong, c_char};
use std::ptr;
use std::path::Path;
use std::ffi::{CString};
use std::os::unix::ffi::OsStrExt;

//path to cstr
fn p2cstr<P: AsRef<Path>>(p: P) -> CString {
    CString::new(p.as_ref().as_os_str().as_bytes()).expect("string contains NULLs")
}

// CString Option to pointer
fn cstr2p(o: Option<CString>) -> *const c_char {
    o.map_or(ptr::null(), |x| x.as_ptr())
}

pub fn chdir<P: AsRef<Path>>(path: P) {
    let path = CString::new(p2cstr(path)).unwrap();
    assert_eq!(unsafe { libc::chdir(path.as_ptr()) }, 0);
}

mod ffi{
    use libc::{c_int, c_char};
    extern {
        pub fn pivot_root(new_root: *const c_char, put_old: *const c_char) -> c_int;
    }
}
pub fn pivot_root<P: AsRef<Path>>(new_root: P, put_old: P) {
    let new_root = p2cstr(new_root).as_ptr();
    let put_old = p2cstr(put_old).as_ptr();
    let r = unsafe { ffi::pivot_root(new_root, put_old) };
    assert_eq!(r, 0);
}

pub fn mount<P: AsRef<Path>>(source: Option<P>, target: Option<P>, filesystemtype: Option<&str>, mountflags: c_ulong) -> () {
    let source = source.map(p2cstr);
    let target = target.map(p2cstr);
    let fstype = match filesystemtype {
            None => ptr::null(),
            Some(fst) => CString::new(fst).expect("fstypes has NULLs").as_ptr(),
        };
    let r = unsafe { libc::mount(cstr2p(source), cstr2p(target), fstype, mountflags, ptr::null()) };
    assert_eq!(r, 0);
}

pub fn umount2<P: AsRef<Path>>(target: P, flags: c_int) {
    let target = p2cstr(target);
    assert_eq!( unsafe { libc::umount2(target.as_ptr(), flags) }, 0);
}

pub fn execv(path: &str, argv: Vec<&str>){
    let prog = CString::new(path).unwrap();
    //have a copy in mem we can point to. No map!
    let mut argv_strs = Vec::with_capacity(argv.len());
    for s in argv {
        argv_strs.push(CString::new(s).unwrap());
    }
    let mut argv_ptrs = Vec::with_capacity(argv_strs.len() + 1);
    for s in argv_strs {
        argv_ptrs.push(s.as_ptr());
    }
    argv_ptrs.push(ptr::null());
    unsafe { libc::execv(prog.as_ptr(), argv_ptrs.as_ptr()) };
    panic!("exec failed!");
}
<commit_msg>fixing memory errors<commit_after>extern crate libc;

use libc::{c_int, c_ulong, c_char};
use std::ptr;
use std::path::Path;
use std::ffi::{CString};
use std::os::unix::ffi::OsStrExt;

// Careful with all libc functions which want a string. Make sure the CString exists on the local
// stack.
// Bad: p2cstr(foo).as_ptr()
// Good: let string_on_stack = p2cstr(foo); string_on_stack.as_ptr()

//path to cstr
fn p2cstr<P: AsRef<Path>>(p: P) -> CString {
    CString::new(p.as_ref().as_os_str().as_bytes()).expect("string contains NULLs")
}

// CString Option to pointer
fn cstr2p(o: Option<&CString>) -> *const c_char {
    o.map_or(ptr::null(), |x| x.as_ptr())
}

pub fn chdir<P: AsRef<Path>>(path: P) {
    let path = CString::new(p2cstr(path)).unwrap();
    println!("chdir {:?}", path);
    assert_eq!(unsafe { libc::chdir(path.as_ptr()) }, 0);
}

mod ffi{
    use libc::{c_int, c_char};
    extern {
        pub fn pivot_root(new_root: *const c_char, put_old: *const c_char) -> c_int;
    }
}
pub fn pivot_root<P: AsRef<Path>>(new_root: P, put_old: P) {
    let new_root = p2cstr(new_root);
    let put_old = p2cstr(put_old);
    println!("pivot_root {:?} {:?}", new_root, put_old);
    let r = unsafe { ffi::pivot_root(new_root.as_ptr(), put_old.as_ptr()) };
    assert_eq!(r, 0);
}

pub fn mount<P: AsRef<Path>>(source: Option<P>, target: Option<P>, filesystemtype: Option<&str>, mountflags: c_ulong) -> () {
    let source = source.map(p2cstr);
    let target = target.map(p2cstr);
    let fstype = filesystemtype.map( |fst| CString::new(fst).expect("fstypes has NULLs") );
    println!("mount {:?} {:?} {:?} {} NULL", source, target, fstype, mountflags);
    let r = unsafe { libc::mount(cstr2p(source.as_ref()), cstr2p(target.as_ref()), cstr2p(fstype.as_ref()), mountflags, ptr::null()) };
    assert_eq!(r, 0);
}

pub fn umount2<P: AsRef<Path>>(target: P, flags: c_int) {
    let target = p2cstr(target);
    println!("umount2 {:?}", target);
    assert_eq!( unsafe { libc::umount2(target.as_ptr(), flags) }, 0);
}

pub fn execv(path: &str, argv: Vec<&str>){
    let prog = CString::new(path).unwrap();
    //have a copy in mem we can point to. No map!
    let mut argv_strs = Vec::with_capacity(argv.len());
    for s in argv {
        argv_strs.push(CString::new(s).unwrap());
    }
    println!("execv {:?} {:?}", prog, argv_strs);
    let mut argv_ptrs = Vec::with_capacity(argv_strs.len() + 1);
    for s in argv_strs {
        argv_ptrs.push(s.as_ptr());
    }
    argv_ptrs.push(ptr::null());
    unsafe { libc::execv(prog.as_ptr(), argv_ptrs.as_ptr()) };
    panic!("exec failed!");
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops::Index;

use num::Num;

// A 2D array
pub struct Array<T: Num> {
    shape: Vec<usize>,
    dim_steps: Vec<usize>, // the ‘volume’ of 1 unit in each dimension.
    buffer: Vec<T>,
}

impl<T: Num> Array<T> {
    pub fn new(shape: Vec<usize>, initial: T) -> Array<T> {
        let buf_size = shape.iter().fold(1, |a, b| a*b);
        let dim_steps = compute_dim_steps(&shape);
        Array {
            shape: shape,
            dim_steps: dim_steps,
            buffer: vec![initial; buf_size],
        }
    }

    pub fn from_vec(shape: Vec<usize>, vec: Vec<T>) -> Array<T> {
        let dim_steps = compute_dim_steps(&shape);
        Array {
            shape: shape,
            dim_steps: dim_steps,
            buffer: vec,
        }
    }

    pub fn get<'a, 'b, I: IntoIterator<Item=&'b usize>>(&'a self, coords: I) -> &'a T {
        let index: usize = coords.into_iter().zip(self.dim_steps.iter())
                                 .map(|(c, s)| (*c)*(*s))
                                 .sum();
        println!("index: {}", index);
        &self.buffer[index]
    }

    pub fn get_mut<'a, 'b, I: IntoIterator<Item=&'b usize>>(&'a mut self, coords: I) -> &'a mut T {
        let index: usize = coords.into_iter().zip(self.dim_steps.iter())
                                 .map(|(c, s)| (*c)*(*s))
                                 .sum();
        &mut self.buffer[index]
    }

    pub fn shape(&self) -> &[usize] {
        &self.shape
    }

    pub fn buffer(&self) -> &Vec<T> {
        &self.buffer
    }
}

impl<'a, 'b, T: Num, I: IntoIterator<Item=&'b usize>> Index<I> for Array<T> {
    type Output = T;

    fn index<'r>(&'r self, index: I) -> &'r T {
        self.get(index)
    }
}

impl<T: Num> fmt::Debug for Array<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[\n"));
        for row in 0..self.shape[0] {
            try!(write!(f, "[{}", self.get(&[row, 0])));
            for col in 1..self.shape[1] {
                try!(write!(f, "\t{}", self.get(&[row, col])));
            }
            try!(write!(f, "]\n"));
        }
        try!(write!(f, "]\n"));
        Ok(())
    }
}

fn compute_dim_steps(shape: &[usize]) -> Vec<usize> {
    let mut dim_steps = vec![0; shape.len()];
    dim_steps[shape.len()-1] = 1;
    for i in 1..shape.len() {
        let cur_index = shape.len()-i-1;
        dim_steps[cur_index] = shape[cur_index+1]*dim_steps[cur_index+1];
    }
    println!("{:?}", dim_steps);
    dim_steps
}
<commit_msg>took out debug prints<commit_after>use std::fmt;
use std::ops::Index;

use num::Num;

// A 2D array
pub struct Array<T: Num> {
    shape: Vec<usize>,
    dim_steps: Vec<usize>, // the ‘volume’ of 1 unit in each dimension.
    buffer: Vec<T>,
}

impl<T: Num> Array<T> {
    pub fn new(shape: Vec<usize>, initial: T) -> Array<T> {
        let buf_size = shape.iter().fold(1, |a, b| a*b);
        let dim_steps = compute_dim_steps(&shape);
        Array {
            shape: shape,
            dim_steps: dim_steps,
            buffer: vec![initial; buf_size],
        }
    }

    pub fn from_vec(shape: Vec<usize>, vec: Vec<T>) -> Array<T> {
        let dim_steps = compute_dim_steps(&shape);
        Array {
            shape: shape,
            dim_steps: dim_steps,
            buffer: vec,
        }
    }

    pub fn get<'a, 'b, I: IntoIterator<Item=&'b usize>>(&'a self, coords: I) -> &'a T {
        let index: usize = coords.into_iter().zip(self.dim_steps.iter())
                                 .map(|(c, s)| (*c)*(*s))
                                 .sum();
        &self.buffer[index]
    }

    pub fn get_mut<'a, 'b, I: IntoIterator<Item=&'b usize>>(&'a mut self, coords: I) -> &'a mut T {
        let index: usize = coords.into_iter().zip(self.dim_steps.iter())
                                 .map(|(c, s)| (*c)*(*s))
                                 .sum();
        &mut self.buffer[index]
    }

    pub fn shape(&self) -> &[usize] {
        &self.shape
    }

    pub fn buffer(&self) -> &Vec<T> {
        &self.buffer
    }
}

impl<'a, 'b, T: Num, I: IntoIterator<Item=&'b usize>> Index<I> for Array<T> {
    type Output = T;

    fn index<'r>(&'r self, index: I) -> &'r T {
        self.get(index)
    }
}

impl<T: Num> fmt::Debug for Array<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "[\n"));
        for row in 0..self.shape[0] {
            try!(write!(f, "[{}", self.get(&[row, 0])));
            for col in 1..self.shape[1] {
                try!(write!(f, "\t{}", self.get(&[row, col])));
            }
            try!(write!(f, "]\n"));
        }
        try!(write!(f, "]\n"));
        Ok(())
    }
}

fn compute_dim_steps(shape: &[usize]) -> Vec<usize> {
    let mut dim_steps = vec![0; shape.len()];
    dim_steps[shape.len()-1] = 1;
    for i in 1..shape.len() {
        let cur_index = shape.len()-i-1;
        dim_steps[cur_index] = shape[cur_index+1]*dim_steps[cur_index+1];
    }
    dim_steps
}
<|endoftext|>


<commit_before>//! A collection of ascii representation (u8) utility functions

use std::str::{self, FromStr};

pub trait Ascii: Clone {
  fn is_alpha(self) -> bool;
  fn is_digit(self) -> bool;
  fn is_hex_digit(self) -> bool;
  fn is_space(self) -> bool;
}

impl Ascii for u8 {
  /// Returns true if this `u8` is an alphabetic code point, and false if not.
  #[inline]
  fn is_alpha(self) -> bool {
    match self {
      b'a'...b'z' | b'A'...b'Z' => true,
      _ => false
    }
  }

  /// Checks if a `char` is a digit in a radix of ten.
  #[inline]
  fn is_digit(self) -> bool {
    b'0' <= self && self <= b'9'
  }

  /// Checks if a `char` is a digit in a radix of hexadecimal.
  #[inline]
  fn is_hex_digit(self) -> bool {
    match self {
      b'0'...b'9' | b'a'...b'f' | b'A'...b'F' => true,
      _ => false
    }
  }

  #[inline]
  fn is_space(self) -> bool {
    match self {
      b' ' | b'\t' | b'\n' | b'\r' => true,
      _ => false
    }
  }
}

/// Convert a string to a i64 value and
/// return a remaning part which is not valid in decimal
pub fn strtoi<'a>(s: &'a str, start_idx: usize) -> (i32, Option<&'a str>) {
  let (val, remain) = strtol(s, start_idx);
  if val != ((val as i32) as i64) {
    panic!(format!("integer overflow in strtoi: {}", s));
  }
  return (val as i32, remain);
}

/// Convert a string to a i64 value and
/// return a remaning part which is not valid in decimal
pub fn strtol<'a>(s: &'a str, start_idx: usize) -> (i64, Option<&'a str>) {
  debug_assert!(s.len() > start_idx, format!(
    "the length of input string must be greater than start_idx, \
    but length = {} and start_idx = {}", s.len(), start_idx));

  let bytes = &(s.as_bytes()[start_idx..]);
  let last_digit_idx = match bytes.iter().position(|&c| !c.is_digit()) {
    Some(idx) => idx,
    None => bytes.len()
  };

  let val = i64::from_str(unsafe {
      str::from_utf8_unchecked(&bytes[..last_digit_idx])
    }).ok().unwrap();

  let remain = if s.len() == last_digit_idx {
    None
  } else {
    Some(unsafe {str::from_utf8_unchecked(&bytes[last_digit_idx..])})
  };

  (val, remain)
}

#[cfg(test)]
mod tests {
  use super::{strtoi, strtol};

  #[test]
  fn test_strtol() {
    let (val, remain) = strtol("12345", 0);
    assert_eq!(12345i64, val);
    assert!(remain.is_none());

    let (val, remain) = strtol("12345l", 0);
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!("l", remain.unwrap());

    let (val, remain) = strtol("12345lll", 0);
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!("lll", remain.unwrap());
  }

  #[test]
  #[should_panic]
  fn test_strtoi_overflow() {
    strtoi("123456789012345lll", 0);
  }
}<commit_msg>Refactor strtoi and strtol to take &[u8]<commit_after>//! A collection of ascii representation (u8) utility functions

use std::str::{self, FromStr};

pub trait Ascii: Clone {
  fn is_alpha(self) -> bool;
  fn is_digit(self) -> bool;
  fn is_hex_digit(self) -> bool;
  fn is_space(self) -> bool;
}

impl Ascii for u8 {
  /// Returns true if this `u8` is an alphabetic code point, and false if not.
  #[inline]
  fn is_alpha(self) -> bool {
    match self {
      b'a'...b'z' | b'A'...b'Z' => true,
      _ => false
    }
  }

  /// Checks if a `char` is a digit in a radix of ten.
  #[inline]
  fn is_digit(self) -> bool {
    b'0' <= self && self <= b'9'
  }

  /// Checks if a `char` is a digit in a radix of hexadecimal.
  #[inline]
  fn is_hex_digit(self) -> bool {
    match self {
      b'0'...b'9' | b'a'...b'f' | b'A'...b'F' => true,
      _ => false
    }
  }

  #[inline]
  fn is_space(self) -> bool {
    match self {
      b' ' | b'\t' | b'\n' | b'\r' => true,
      _ => false
    }
  }
}

/// Convert a string to a i64 value and
/// return a remaning part which is not valid in decimal
pub fn strtoi<'a>(s: &'a [u8], start_idx: usize) -> (i32, Option<&'a [u8]>) {
  let (val, remain) = strtol(s, start_idx);
  if val != ((val as i32) as i64) {
    panic!(format!("integer overflow in strtoi: {}",
      unsafe { str::from_utf8_unchecked(s) }));
  }
  return (val as i32, remain);
}

/// Convert a string to a i64 value and
/// return a remaning part which is not valid in decimal
pub fn strtol<'a>(s: &'a [u8], start_idx: usize) -> (i64, Option<&'a [u8]>) {
  debug_assert!(s.len() > start_idx, format!(
    "the length of input string must be greater than start_idx, \
    but length = {} and start_idx = {}", s.len(), start_idx));

  let bytes = &s[start_idx..];
  let last_digit_idx = match bytes.iter().position(|&c| !c.is_digit()) {
    Some(idx) => idx,
    None => bytes.len()
  };

  let val = i64::from_str(unsafe {
      str::from_utf8_unchecked(&bytes[..last_digit_idx])
    }).ok().unwrap();

  let remain = if s.len() == last_digit_idx {
    None
  } else {
    Some(&bytes[last_digit_idx..])
  };

  (val, remain)
}

#[cfg(test)]
mod tests {
  use super::{strtoi, strtol};

  #[test]
  fn test_strtol() {
    let (val, remain) = strtol(b"12345", 0);
    assert_eq!(12345i64, val);
    assert!(remain.is_none());

    let (val, remain) = strtol(b"12345l", 0);
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!(b"l", remain.unwrap());

    let (val, remain) = strtol(b"12345lll", 0);
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!(b"lll", remain.unwrap());
  }

  #[test]
  #[should_panic]
  fn test_strtoi_overflow() {
    strtoi(b"123456789012345lll", 0);
  }
}<|endoftext|>


<commit_before>#![feature(test)]
#![allow(non_snake_case, unused_variables)]

extern crate test;
extern crate seq_io;
extern crate fastq;
extern crate bio;
#[macro_use]
extern crate lazy_static;

use std::io::Cursor;
use std::iter::repeat;
use test::Bencher;

/// generates 'nrecords' FASTQ records with given properties
fn gen_fastq(nrecords: usize, id_len: usize, desc_len: usize,
             seq_len: usize, sep_ids: bool, cr: bool) -> Vec<u8> {

    let newline = if cr { b"\r\n".to_vec() } else { b"\n".to_vec() };
    let mut rec: Vec<u8> = vec![];
    rec.push(b'@');
    let id: Vec<_> = repeat(b'i').take(id_len).collect();
    rec.extend(&id);
    rec.push(b' ');
    rec.extend(repeat(b'd').take(desc_len));
    rec.extend(&newline);
    rec.extend(repeat(b'A').take(seq_len));
    rec.extend(&newline);
    rec.push(b'+');
    if sep_ids {
        rec.extend(Some(b' ').into_iter().chain(id.into_iter()));
    }
    rec.extend(&newline);
    rec.extend(repeat(66).take(seq_len));
    rec.extend(&newline);

    (0..nrecords).flat_map(|_| rec.clone()).collect()
}

/// generates 'nrecords' FASTQ records with fixed ID / description lengths (20 and 50), but configurable otherwise
fn with_seqlen(nrecords: usize, seq_len: usize, sep_ids: bool, cr: bool) -> Vec<u8> {
    gen_fastq(nrecords, 20, 50, seq_len, sep_ids, cr)
}

/// number of records for all benchmarks
const N: usize = 100_000;

/// data to be used with parallel readers (require 'static)
lazy_static! {
    static ref L500: Vec<u8> = { with_seqlen(N, 500, false, false) };
}

macro_rules! bench {
    ($name:ident, $seqlen:expr, $lbreak:expr, $cursor:ident, $code:block) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let data = with_seqlen(N, $seqlen, $lbreak, false);
            b.bytes = data.len() as u64;
            b.iter(|| {
                let $cursor = Cursor::new(&data);
                $code
            });
        }
     };
}

macro_rules! bench_static500 {
    ($name:ident, $cursor:ident, $code:block) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let data: &'static Vec<u8> = &L500 as &Vec<u8>;
            b.bytes = data.len() as u64;
            b.iter(move || {
                let $cursor = Cursor::new(data);
                $code
            });
        }
     };
}

macro_rules! fastq {
    ($name:ident, $seqlen:expr, $lbreak:expr, $rec:ident, $code:block) => {
        bench!($name, $seqlen, $lbreak, cursor, {
            let mut reader = seq_io::fastq::Reader::new(cursor);
            while let Some($rec) = reader.next() {
                let $rec = $rec.unwrap();
                $code
            }
        });
     };
}

macro_rules! fastq_rs {
    ($name:ident, $seqlen:expr, $lbreak:expr, $rec:ident, $code:block) => {
        bench!($name, $seqlen, $lbreak, cursor, {
            let reader = fastq::Parser::new(cursor);
            reader.each(|$rec| {
                $code
                true
            }).unwrap();
        });
     };
}

macro_rules! bio {
    ($name:ident, $seqlen:expr, $lbreak:expr, $rec:ident, $code:block) => {
        bench!($name, $seqlen, $lbreak, cursor, {
            let reader = bio::io::fastq::Reader::new(cursor);
            for r in reader.records() {
                let $rec = r.unwrap();
                $code
            }
        });
     };
}

fastq!(fastq_iter_200____seqio, 200, false, r, {});
fastq!(fastq_iter_500____seqio, 500, false, r, {});
fastq!(fastq_iter_1000____seqio, 1000, false, r, {});

fastq_rs!(fastq_iter_200____fastqrs, 200, false, r, {});
fastq_rs!(fastq_iter_500____fastqrs, 500, false, r, {});
fastq_rs!(fastq_iter_1000____fastqrs, 1000, false, r, {});

bio!(fastq_iter_200__owned__bio,  200,  false, r, {});
bio!(fastq_iter_500__owned__bio,  500,  false, r, {});
bio!(fastq_iter_1000__owned__bio, 1000, false, r, {});

// bench!(fastq_iter_500__buf5k__seqio, 500, false, cursor, {
//     let mut reader = seq_io::fastq::Reader::with_capacity(cursor, 5*1024);
//     while let Some(rec) = reader.next() {
//         rec.unwrap();
//     }
// });
//
// bench!(fastq_iter_500__buf5k__fastqrs, 500, false, cursor, {
//     let reader = fastq::Parser::with_capacity(cursor, 5*1024);
//     reader.each(|_| {true}).unwrap();
// });

fastq!(fastq_iter_500__owned__seqio,  500,  false, r, {
    let _ = r.to_owned_record();
});

fastq_rs!(fastq_iter_500__owned__fastqrs,  500,  false, r, {
    let _ = r.to_owned_record();
});

// parallel processing (just iterate)

bench!(fastq_iter_500_recset__parallel_seqio, 500, false, cursor, {
    let reader = seq_io::fastq::Reader::new(cursor);
    seq_io::parallel::read_parallel(reader, 2, 2, |rset| {
        for _ in &*rset {}
    }, |rsets| {
        while let Some(result) = rsets.next() {
            let (rset, _) = result.unwrap();
            for _ in &*rset {}
        }
    });
});

bench!(fastq_iter_500_records__parallel_seqio, 500, false, cursor, {
    let reader = seq_io::fastq::Reader::new(cursor);
    seq_io::parallel::parallel_fastq::<_, (), _, _>(reader, 2, 2, |_, _| {}, |_, _| {true}).unwrap();
});

// bench_static500!(fastq_iter_500_static__parallel_seqio, cursor, {
//     let reader = seq_io::fastq::Reader::new(cursor);
//     seq_io::parallel::read_parallel(reader, 2, 2, |rset| { for _ in &*rset {} }, |rsets| {
//         while let Some(result) = rsets.next() {
//             let (rset, _) = result.unwrap();
//             for _ in &*rset {}
//         }
//     });
// });

// input needs static lifetime, but impact of using lazy_static is neglectable
bench_static500!(fastq_iter_500_recset__parallel_fastqrs, cursor, {
    let parser = fastq::Parser::new(cursor);
    let res: Vec<_> = parser.parallel_each(2, |rsets| {
        for rset in rsets {
            for _ in rset.iter() {}
        }
    }).unwrap();
});

// iterate over record sets without parallelism

bench!(fastq_iter_500_recset___seqio, 500, false, cursor, {
    let mut reader = seq_io::fastq::Reader::new(cursor);
    let mut rset = seq_io::fastq::RecordSet::default();
    while let Some(result) = reader.read_record_set(&mut rset) {
        result.unwrap();
        for _ in &rset {}
    }
});
<commit_msg>Fix benches<commit_after>#![feature(test)]
#![allow(non_snake_case, unused_variables)]

extern crate test;
extern crate seq_io;
extern crate fastq;
extern crate bio;
#[macro_use]
extern crate lazy_static;

use std::io::Cursor;
use std::iter::repeat;
use test::Bencher;

/// generates 'nrecords' FASTQ records with given properties
fn gen_fastq(nrecords: usize, id_len: usize, desc_len: usize,
             seq_len: usize, sep_ids: bool, cr: bool) -> Vec<u8> {

    let newline = if cr { b"\r\n".to_vec() } else { b"\n".to_vec() };
    let mut rec: Vec<u8> = vec![];
    rec.push(b'@');
    let id: Vec<_> = repeat(b'i').take(id_len).collect();
    rec.extend(&id);
    rec.push(b' ');
    rec.extend(repeat(b'd').take(desc_len));
    rec.extend(&newline);
    rec.extend(repeat(b'A').take(seq_len));
    rec.extend(&newline);
    rec.push(b'+');
    if sep_ids {
        rec.extend(Some(b' ').into_iter().chain(id.into_iter()));
    }
    rec.extend(&newline);
    rec.extend(repeat(66).take(seq_len));
    rec.extend(&newline);

    (0..nrecords).flat_map(|_| rec.clone()).collect()
}

/// generates 'nrecords' FASTQ records with fixed ID / description lengths (20 and 50), but configurable otherwise
fn with_seqlen(nrecords: usize, seq_len: usize, sep_ids: bool, cr: bool) -> Vec<u8> {
    gen_fastq(nrecords, 20, 50, seq_len, sep_ids, cr)
}

/// number of records for all benchmarks
const N: usize = 100_000;

/// data to be used with parallel readers (require 'static)
lazy_static! {
    static ref L500: Vec<u8> = { with_seqlen(N, 500, false, false) };
}

macro_rules! bench {
    ($name:ident, $seqlen:expr, $lbreak:expr, $cursor:ident, $code:block) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let data = with_seqlen(N, $seqlen, $lbreak, false);
            b.bytes = data.len() as u64;
            b.iter(|| {
                let $cursor = Cursor::new(&data);
                $code
            });
        }
     };
}

macro_rules! bench_static500 {
    ($name:ident, $cursor:ident, $code:block) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let data: &'static Vec<u8> = &L500 as &Vec<u8>;
            b.bytes = data.len() as u64;
            b.iter(move || {
                let $cursor = Cursor::new(data);
                $code
            });
        }
     };
}

macro_rules! fastq {
    ($name:ident, $seqlen:expr, $lbreak:expr, $rec:ident, $code:block) => {
        bench!($name, $seqlen, $lbreak, cursor, {
            let mut reader = seq_io::fastq::Reader::new(cursor);
            while let Some($rec) = reader.next() {
                let $rec = $rec.unwrap();
                $code
            }
        });
     };
}

macro_rules! fastq_rs {
    ($name:ident, $seqlen:expr, $lbreak:expr, $rec:ident, $code:block) => {
        bench!($name, $seqlen, $lbreak, cursor, {
            let reader = fastq::Parser::new(cursor);
            reader.each(|$rec| {
                $code
                true
            }).unwrap();
        });
     };
}

macro_rules! bio {
    ($name:ident, $seqlen:expr, $lbreak:expr, $rec:ident, $code:block) => {
        bench!($name, $seqlen, $lbreak, cursor, {
            let reader = bio::io::fastq::Reader::new(cursor);
            for r in reader.records() {
                let $rec = r.unwrap();
                $code
            }
        });
     };
}

fastq!(fastq_iter_200____seqio, 200, false, r, {});
fastq!(fastq_iter_500____seqio, 500, false, r, {});
fastq!(fastq_iter_1000____seqio, 1000, false, r, {});

fastq_rs!(fastq_iter_200____fastqrs, 200, false, r, {});
fastq_rs!(fastq_iter_500____fastqrs, 500, false, r, {});
fastq_rs!(fastq_iter_1000____fastqrs, 1000, false, r, {});

bio!(fastq_iter_200__owned__bio,  200,  false, r, {});
bio!(fastq_iter_500__owned__bio,  500,  false, r, {});
bio!(fastq_iter_1000__owned__bio, 1000, false, r, {});

// bench!(fastq_iter_500__buf5k__seqio, 500, false, cursor, {
//     let mut reader = seq_io::fastq::Reader::with_capacity(cursor, 5*1024);
//     while let Some(rec) = reader.next() {
//         rec.unwrap();
//     }
// });
//
// bench!(fastq_iter_500__buf5k__fastqrs, 500, false, cursor, {
//     let reader = fastq::Parser::with_capacity(cursor, 5*1024);
//     reader.each(|_| {true}).unwrap();
// });

fastq!(fastq_iter_500__owned__seqio,  500,  false, r, {
    let _ = r.to_owned_record();
});

fastq_rs!(fastq_iter_500__owned__fastqrs,  500,  false, r, {
    let _ = r.to_owned_record();
});

// parallel processing (just iterate)

bench!(fastq_iter_500_recset__parallel_seqio, 500, false, cursor, {
    let reader = seq_io::fastq::Reader::new(cursor);
    seq_io::parallel::read_parallel(reader, 2, 2, |rset| {
        for _ in &*rset {}
    }, |rsets| {
        while let Some(result) = rsets.next() {
            let (rset, _) = result.unwrap();
            for _ in &*rset {}
        }
    });
});

bench!(fastq_iter_500_records__parallel_seqio, 500, false, cursor, {
    let reader = seq_io::fastq::Reader::new(cursor);
    seq_io::parallel::parallel_fastq::<_, (), _, _, ()>(reader, 2, 2, |_, _| {}, |_, _| {None}).unwrap();
});

// bench_static500!(fastq_iter_500_static__parallel_seqio, cursor, {
//     let reader = seq_io::fastq::Reader::new(cursor);
//     seq_io::parallel::read_parallel(reader, 2, 2, |rset| { for _ in &*rset {} }, |rsets| {
//         while let Some(result) = rsets.next() {
//             let (rset, _) = result.unwrap();
//             for _ in &*rset {}
//         }
//     });
// });

// input needs static lifetime, but impact of using lazy_static is neglectable
bench_static500!(fastq_iter_500_recset__parallel_fastqrs, cursor, {
    let parser = fastq::Parser::new(cursor);
    let res: Vec<_> = parser.parallel_each(2, |rsets| {
        for rset in rsets {
            for _ in rset.iter() {}
        }
    }).unwrap();
});

// iterate over record sets without parallelism

bench!(fastq_iter_500_recset___seqio, 500, false, cursor, {
    let mut reader = seq_io::fastq::Reader::new(cursor);
    let mut rset = seq_io::fastq::RecordSet::default();
    while let Some(result) = reader.read_record_set(&mut rset) {
        result.unwrap();
        for _ in &rset {}
    }
});
<|endoftext|>


<commit_before>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use std::os::raw::c_void;
use {CreationError, WindowEvent as Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::{Touch, TouchPhase};

use std::collections::VecDeque;

use CursorState;
use WindowAttributes;
use FullScreenState;

gen_api_transition!();

pub struct Window {
    native_window: *const c_void,
    event_rx: Receiver<android_glue::Event>,
}

#[derive(Clone)]
pub struct MonitorId;

mod ffi;

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    let mut rb = VecDeque::new();
    rb.push_back(MonitorId);
    rb
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    MonitorId
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self.window.event_rx.try_recv() {
            Ok(android_glue::Event::EventMotion(motion)) => {
                Some(Event::Touch(Touch {
                    phase: match motion.action {
                        android_glue::MotionAction::Down => TouchPhase::Started,
                        android_glue::MotionAction::Move => TouchPhase::Moved,
                        android_glue::MotionAction::Up => TouchPhase::Ended,
                        android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
                    },
                    location: (motion.x as f64, motion.y as f64),
                    id: motion.pointer_id as u64,
                    device_id: DEVICE_ID,
                }))
            },
            Ok(android_glue::Event::InitWindow) => {
                // The activity went to foreground.
                Some(Event::Suspended(false))
            },
            Ok(android_glue::Event::TermWindow) => {
                // The activity went to background.
                Some(Event::Suspended(true))
            },
            Ok(android_glue::Event::WindowResized) |
            Ok(android_glue::Event::ConfigChanged) => {
                // Activity Orientation changed or resized.
                self.window.get_inner_size().map(|s| Event::Resized(s.0, s.1))
            },
            Ok(android_glue::Event::WindowRedrawNeeded) => {
                // The activity needs to be redrawn.
                Some(Event::Refresh)
            }
            _ => {
                None
            }
        }
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    #[inline]
    fn next(&mut self) -> Option<Event> {
        loop {
            // calling poll_events()
            if let Some(ev) = self.window.poll_events().next() {
                return Some(ev);
            }

            // TODO: Implement a proper way of sleeping on the event queue
            // timer::sleep(Duration::milliseconds(16));
        }
    }
}

impl Window {
    pub fn new(win_attribs: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window, CreationError>
    {
        use std::{mem, ptr};

        // not implemented
        assert!(win_attribs.min_dimensions.is_none());
        assert!(win_attribs.max_dimensions.is_none());

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let (tx, rx) = channel();
        android_glue::add_sender(tx);
        android_glue::set_multitouch(win_attribs.multitouch);

        Ok(Window {
            native_window: native_window as *const _,
            event_rx: rx,
        })
    }

    #[inline]
    pub fn get_native_window(&self) -> *const c_void {
        self.native_window
    }

    #[inline]
    pub fn is_closed(&self) -> bool {
        false
    }

    #[inline]
    pub fn set_title(&self, _: &str) {
    }

    #[inline]
    pub fn show(&self) {
    }

    #[inline]
    pub fn hide(&self) {
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window as *const _) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window as *const _) } as u32
            ))
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    #[inline]
    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!();
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        unimplemented!()
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    #[inline]
    pub fn set_cursor(&self, _: MouseCursor) {
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        Ok(())
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        unimplemented!();
    }

    #[inline]
    pub fn set_maximized(&self, maximized: bool) {
    }

    #[inline]
    pub fn set_fullscreen(&self, state: FullScreenState) {
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        android_glue::wake_event_loop();
    }
}

// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
<commit_msg>Update Android code with EventsLoop (#272)<commit_after>#![cfg(target_os = "android")]

extern crate android_glue;

use libc;
use std::sync::mpsc::{Receiver, channel};
use std::os::raw::c_void;
use {CreationError, Event, WindowEvent, MouseCursor};
use CreationError::OsError;
use WindowId as RootWindowId;
use events::{Touch, TouchPhase};

use std::collections::VecDeque;

use CursorState;
use WindowAttributes;
use FullScreenState;

pub struct EventsLoop {
    event_rx: Receiver<android_glue::Event>,
}

pub struct EventsLoopProxy;

impl EventsLoop {
    pub fn new() -> EventsLoop {
        let (tx, rx) = channel();
        android_glue::add_sender(tx);
        EventsLoop {
            event_rx: rx,
        }
    }

    #[inline]
    pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
        let mut rb = VecDeque::new();
        rb.push_back(MonitorId);
        rb
    }

    #[inline]
    pub fn get_primary_monitor(&self) -> MonitorId {
        MonitorId
    }

    pub fn poll_events<F>(&mut self, mut callback: F)
        where F: FnMut(::Event)
    {
        let event = match self.event_rx.try_recv() {
            Ok(android_glue::Event::EventMotion(motion)) => {
                Some(WindowEvent::Touch(Touch {
                    phase: match motion.action {
                        android_glue::MotionAction::Down => TouchPhase::Started,
                        android_glue::MotionAction::Move => TouchPhase::Moved,
                        android_glue::MotionAction::Up => TouchPhase::Ended,
                        android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
                    },
                    location: (motion.x as f64, motion.y as f64),
                    id: motion.pointer_id as u64,
                    device_id: DEVICE_ID,
                }))
            },
            Ok(android_glue::Event::InitWindow) => {
                // The activity went to foreground.
                Some(WindowEvent::Suspended(false))
            },
            Ok(android_glue::Event::TermWindow) => {
                // The activity went to background.
                Some(WindowEvent::Suspended(true))
            },
            Ok(android_glue::Event::WindowResized) |
            Ok(android_glue::Event::ConfigChanged) => {
                // Activity Orientation changed or resized.
                let native_window = unsafe { android_glue::get_native_window() };
                if native_window.is_null() {
                    None
                } else {
                    let w = unsafe { ffi::ANativeWindow_getWidth(native_window as *const _) } as u32;
                    let h = unsafe { ffi::ANativeWindow_getHeight(native_window as *const _) } as u32;
                    Some(WindowEvent::Resized(w, h))
                }
            },
            Ok(android_glue::Event::WindowRedrawNeeded) => {
                // The activity needs to be redrawn.
                Some(WindowEvent::Refresh)
            }
            _ => {
                None
            }
        };

        if let Some(event) = event {
            callback(Event::WindowEvent {
                window_id: RootWindowId(WindowId),
                event: event
            });
        }
    }

    pub fn run_forever<F>(&mut self, mut callback: F)
        where F: FnMut(::Event) -> ::ControlFlow,
    {
        // Yeah that's a very bad implementation.
        loop {
            let mut control_flow = ::ControlFlow::Continue;
            self.poll_events(|e| {
                if let ::ControlFlow::Break = callback(e) {
                    control_flow = ::ControlFlow::Break;
                }
            });
            if let ::ControlFlow::Break = control_flow {
                break;
            }
            ::std::thread::sleep(::std::time::Duration::from_millis(5));
        }
    }

    pub fn create_proxy(&self) -> EventsLoopProxy {
        EventsLoopProxy
    }
}

impl EventsLoopProxy {
    pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
        android_glue::wake_event_loop();
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;

pub struct Window2 {
    native_window: *const c_void,
}

#[derive(Clone)]
pub struct MonitorId;

mod ffi;

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes;
#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

impl Window2 {
    pub fn new(_: &EventsLoop, win_attribs: &WindowAttributes,
               _: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window2, CreationError>
    {
        // not implemented
        assert!(win_attribs.min_dimensions.is_none());
        assert!(win_attribs.max_dimensions.is_none());

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        android_glue::set_multitouch(win_attribs.multitouch);

        Ok(Window2 {
            native_window: native_window as *const _,
        })
    }

    #[inline]
    pub fn get_native_window(&self) -> *const c_void {
        self.native_window
    }

    #[inline]
    pub fn set_title(&self, _: &str) {
    }

    #[inline]
    pub fn show(&self) {
    }

    #[inline]
    pub fn hide(&self) {
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        if self.native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(self.native_window as *const _) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(self.native_window as *const _) } as u32
            ))
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    #[inline]
    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        unimplemented!();
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        unimplemented!()
    }

    #[inline]
    pub fn set_cursor(&self, _: MouseCursor) {
    }

    #[inline]
    pub fn set_cursor_state(&self, _state: CursorState) -> Result<(), String> {
        Ok(())
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        Ok(())
    }

    #[inline]
    pub fn set_maximized(&self, _maximized: bool) {
    }

    #[inline]
    pub fn set_fullscreen(&self, _state: FullScreenState) {
    }

    pub fn id(&self) -> WindowId {
        WindowId
    }
}

unsafe impl Send for Window2 {}
unsafe impl Sync for Window2 {}

// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
<|endoftext|>