<commit_before>use crate::codec::*;
use crate::endpoint::Endpoint;
use crate::error::ZmqResult;
use crate::message::*;
use crate::transport::AcceptStopHandle;
use crate::util::PeerIdentity;
use crate::{async_rt, CaptureSocket, SocketOptions};
use crate::{
    MultiPeerBackend, Socket, SocketBackend, SocketEvent, SocketSend, SocketType, ZmqError,
};

use async_trait::async_trait;
use dashmap::DashMap;
use futures::channel::{mpsc, oneshot};
use futures::FutureExt;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::io::ErrorKind;
use std::pin::Pin;
use std::sync::Arc;

pub(crate) struct Subscriber {
    pub(crate) subscriptions: Vec<Vec<u8>>,
    pub(crate) send_queue: Pin<Box<ZmqFramedWrite>>,
    _subscription_coro_stop: oneshot::Sender<()>,
}

pub(crate) struct PubSocketBackend {
    subscribers: DashMap<PeerIdentity, Subscriber>,
    socket_monitor: Mutex<Option<mpsc::Sender<SocketEvent>>>,
    socket_options: SocketOptions,
}

impl PubSocketBackend {
    fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        let message = match message {
            Message::Message(m) => m,
            _ => return,
        };
        assert_eq!(message.len(), 1);
        let data: Vec<u8> = message.into_vec().pop().unwrap().to_vec();
        if data.is_empty() {
            return;
        }
        match data[0] {
            1 => {
                // Subscribe
                self.subscribers
                    .get_mut(peer_id)
                    .unwrap()
                    .subscriptions
                    .push(Vec::from(&data[1..]));
            }
            0 => {
                // Unsubscribe
                let mut del_index = None;
                let sub = Vec::from(&data[1..]);
                for (idx, subscription) in self
                    .subscribers
                    .get(peer_id)
                    .unwrap()
                    .subscriptions
                    .iter()
                    .enumerate()
                {
                    if &sub == subscription {
                        del_index = Some(idx);
                        break;
                    }
                }
                if let Some(index) = del_index {
                    self.subscribers
                        .get_mut(peer_id)
                        .unwrap()
                        .subscriptions
                        .remove(index);
                }
            }
            _ => (),
        }
    }
}

impl SocketBackend for PubSocketBackend {
    fn socket_type(&self) -> SocketType {
        SocketType::PUB
    }

    fn socket_options(&self) -> &SocketOptions {
        &self.socket_options
    }

    fn shutdown(&self) {
        self.subscribers.clear();
    }

    fn monitor(&self) -> &Mutex<Option<mpsc::Sender<SocketEvent>>> {
        &self.socket_monitor
    }
}

impl MultiPeerBackend for PubSocketBackend {
    fn peer_connected(self: Arc<Self>, peer_id: &PeerIdentity, io: FramedIo) {
        let (mut recv_queue, send_queue) = io.into_parts();
        // TODO provide handling for recv_queue
        let (sender, stop_receiver) = oneshot::channel();
        self.subscribers.insert(
            peer_id.clone(),
            Subscriber {
                subscriptions: vec![],
                send_queue: Box::pin(send_queue),
                _subscription_coro_stop: sender,
            },
        );
        let backend = self;
        let peer_id = peer_id.clone();
        async_rt::task::spawn(async move {
            use futures::StreamExt;
            let mut stop_receiver = stop_receiver.fuse();
            loop {
                futures::select! {
                     _ = stop_receiver => {
                         break;
                     },
                     message = recv_queue.next().fuse() => {
                        match message {
                            Some(Ok(m)) => backend.message_received(&peer_id, m),
                            Some(Err(e)) => {
                                dbg!(e);
                                backend.peer_disconnected(&peer_id);
                                break;
                            }
                            None => {
                                backend.peer_disconnected(&peer_id);
                                break
                            }
                        }

                     }
                }
            }
        });
    }

    fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        log::info!("Client disconnected {:?}", peer_id);
        self.subscribers.remove(peer_id);
    }
}

pub struct PubSocket {
    pub(crate) backend: Arc<PubSocketBackend>,
    binds: HashMap<Endpoint, AcceptStopHandle>,
}

impl Drop for PubSocket {
    fn drop(&mut self) {
        self.backend.shutdown();
    }
}

#[async_trait]
impl SocketSend for PubSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        let mut dead_peers = Vec::new();
        for mut subscriber in self.backend.subscribers.iter_mut() {
            for sub_filter in &subscriber.subscriptions {
                if sub_filter.len() <= message.get(0).unwrap().len()
                    && sub_filter.as_slice() == &message.get(0).unwrap()[0..sub_filter.len()]
                {
                    let res = subscriber
                        .send_queue
                        .as_mut()
                        .try_send(Message::Message(message.clone()));
                    match res {
                        Ok(()) => {}
                        Err(ZmqError::Codec(CodecError::Io(e))) => {
                            if e.kind() == ErrorKind::BrokenPipe {
                                dead_peers.push(subscriber.key().clone());
                            } else {
                                dbg!(e);
                            }
                        }
                        Err(e) => {
                            dbg!(e);
                            todo!()
                        }
                    }
                    break;
                }
            }
        }
        for peer in dead_peers {
            self.backend.peer_disconnected(&peer);
        }
        Ok(())
    }
}

impl CaptureSocket for PubSocket {}

#[async_trait]
impl Socket for PubSocket {
    fn with_options(options: SocketOptions) -> Self {
        Self {
            backend: Arc::new(PubSocketBackend {
                subscribers: DashMap::new(),
                socket_monitor: Mutex::new(None),
                socket_options: options,
            }),
            binds: HashMap::new(),
        }
    }

    fn backend(&self) -> Arc<dyn MultiPeerBackend> {
        self.backend.clone()
    }

    fn binds(&mut self) -> &mut HashMap<Endpoint, AcceptStopHandle> {
        &mut self.binds
    }

    fn monitor(&mut self) -> mpsc::Receiver<SocketEvent> {
        let (sender, receiver) = mpsc::channel(1024);
        self.backend.socket_monitor.lock().replace(sender);
        receiver
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util::tests::{
        test_bind_to_any_port_helper, test_bind_to_unspecified_interface_helper,
    };
    use crate::ZmqResult;
    use std::net::IpAddr;

    #[async_rt::test]
    async fn test_bind_to_any_port() -> ZmqResult<()> {
        let s = PubSocket::new();
        test_bind_to_any_port_helper(s).await
    }

    #[async_rt::test]
    async fn test_bind_to_any_ipv4_interface() -> ZmqResult<()> {
        let any_ipv4: IpAddr = "0.0.0.0".parse().unwrap();
        let s = PubSocket::new();
        test_bind_to_unspecified_interface_helper(any_ipv4, s, 4000).await
    }

    #[async_rt::test]
    async fn test_bind_to_any_ipv6_interface() -> ZmqResult<()> {
        let any_ipv6: IpAddr = "::".parse().unwrap();
        let s = PubSocket::new();
        test_bind_to_unspecified_interface_helper(any_ipv6, s, 4010).await
    }
}
<commit_msg>Silently ignore send error if a subscriber queue is full<commit_after>use crate::codec::*;
use crate::endpoint::Endpoint;
use crate::error::ZmqResult;
use crate::message::*;
use crate::transport::AcceptStopHandle;
use crate::util::PeerIdentity;
use crate::{async_rt, CaptureSocket, SocketOptions};
use crate::{
    MultiPeerBackend, Socket, SocketBackend, SocketEvent, SocketSend, SocketType, ZmqError,
};

use async_trait::async_trait;
use dashmap::DashMap;
use futures::channel::{mpsc, oneshot};
use futures::FutureExt;
use parking_lot::Mutex;
use std::collections::HashMap;
use std::io::ErrorKind;
use std::pin::Pin;
use std::sync::Arc;

pub(crate) struct Subscriber {
    pub(crate) subscriptions: Vec<Vec<u8>>,
    pub(crate) send_queue: Pin<Box<ZmqFramedWrite>>,
    _subscription_coro_stop: oneshot::Sender<()>,
}

pub(crate) struct PubSocketBackend {
    subscribers: DashMap<PeerIdentity, Subscriber>,
    socket_monitor: Mutex<Option<mpsc::Sender<SocketEvent>>>,
    socket_options: SocketOptions,
}

impl PubSocketBackend {
    fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        let message = match message {
            Message::Message(m) => m,
            _ => return,
        };
        assert_eq!(message.len(), 1);
        let data: Vec<u8> = message.into_vec().pop().unwrap().to_vec();
        if data.is_empty() {
            return;
        }
        match data[0] {
            1 => {
                // Subscribe
                self.subscribers
                    .get_mut(peer_id)
                    .unwrap()
                    .subscriptions
                    .push(Vec::from(&data[1..]));
            }
            0 => {
                // Unsubscribe
                let mut del_index = None;
                let sub = Vec::from(&data[1..]);
                for (idx, subscription) in self
                    .subscribers
                    .get(peer_id)
                    .unwrap()
                    .subscriptions
                    .iter()
                    .enumerate()
                {
                    if &sub == subscription {
                        del_index = Some(idx);
                        break;
                    }
                }
                if let Some(index) = del_index {
                    self.subscribers
                        .get_mut(peer_id)
                        .unwrap()
                        .subscriptions
                        .remove(index);
                }
            }
            _ => (),
        }
    }
}

impl SocketBackend for PubSocketBackend {
    fn socket_type(&self) -> SocketType {
        SocketType::PUB
    }

    fn socket_options(&self) -> &SocketOptions {
        &self.socket_options
    }

    fn shutdown(&self) {
        self.subscribers.clear();
    }

    fn monitor(&self) -> &Mutex<Option<mpsc::Sender<SocketEvent>>> {
        &self.socket_monitor
    }
}

impl MultiPeerBackend for PubSocketBackend {
    fn peer_connected(self: Arc<Self>, peer_id: &PeerIdentity, io: FramedIo) {
        let (mut recv_queue, send_queue) = io.into_parts();
        // TODO provide handling for recv_queue
        let (sender, stop_receiver) = oneshot::channel();
        self.subscribers.insert(
            peer_id.clone(),
            Subscriber {
                subscriptions: vec![],
                send_queue: Box::pin(send_queue),
                _subscription_coro_stop: sender,
            },
        );
        let backend = self;
        let peer_id = peer_id.clone();
        async_rt::task::spawn(async move {
            use futures::StreamExt;
            let mut stop_receiver = stop_receiver.fuse();
            loop {
                futures::select! {
                     _ = stop_receiver => {
                         break;
                     },
                     message = recv_queue.next().fuse() => {
                        match message {
                            Some(Ok(m)) => backend.message_received(&peer_id, m),
                            Some(Err(e)) => {
                                dbg!(e);
                                backend.peer_disconnected(&peer_id);
                                break;
                            }
                            None => {
                                backend.peer_disconnected(&peer_id);
                                break
                            }
                        }

                     }
                }
            }
        });
    }

    fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        log::info!("Client disconnected {:?}", peer_id);
        self.subscribers.remove(peer_id);
    }
}

pub struct PubSocket {
    pub(crate) backend: Arc<PubSocketBackend>,
    binds: HashMap<Endpoint, AcceptStopHandle>,
}

impl Drop for PubSocket {
    fn drop(&mut self) {
        self.backend.shutdown();
    }
}

#[async_trait]
impl SocketSend for PubSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        let mut dead_peers = Vec::new();
        for mut subscriber in self.backend.subscribers.iter_mut() {
            for sub_filter in &subscriber.subscriptions {
                if sub_filter.len() <= message.get(0).unwrap().len()
                    && sub_filter.as_slice() == &message.get(0).unwrap()[0..sub_filter.len()]
                {
                    let res = subscriber
                        .send_queue
                        .as_mut()
                        .try_send(Message::Message(message.clone()));
                    match res {
                        Ok(()) => {}
                        Err(ZmqError::Codec(CodecError::Io(e))) => {
                            if e.kind() == ErrorKind::BrokenPipe {
                                dead_peers.push(subscriber.key().clone());
                            } else {
                                dbg!(e);
                            }
                        }
                        Err(ZmqError::BufferFull(_)) => {
                            // ignore silently. https://rfc.zeromq.org/spec/29/ says:
                            // For processing outgoing messages:
                            //   SHALL silently drop the message if the queue for a subscriber is full.
                        }
                        Err(e) => {
                            dbg!(e);
                            todo!()
                        }
                    }
                    break;
                }
            }
        }
        for peer in dead_peers {
            self.backend.peer_disconnected(&peer);
        }
        Ok(())
    }
}

impl CaptureSocket for PubSocket {}

#[async_trait]
impl Socket for PubSocket {
    fn with_options(options: SocketOptions) -> Self {
        Self {
            backend: Arc::new(PubSocketBackend {
                subscribers: DashMap::new(),
                socket_monitor: Mutex::new(None),
                socket_options: options,
            }),
            binds: HashMap::new(),
        }
    }

    fn backend(&self) -> Arc<dyn MultiPeerBackend> {
        self.backend.clone()
    }

    fn binds(&mut self) -> &mut HashMap<Endpoint, AcceptStopHandle> {
        &mut self.binds
    }

    fn monitor(&mut self) -> mpsc::Receiver<SocketEvent> {
        let (sender, receiver) = mpsc::channel(1024);
        self.backend.socket_monitor.lock().replace(sender);
        receiver
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util::tests::{
        test_bind_to_any_port_helper, test_bind_to_unspecified_interface_helper,
    };
    use crate::ZmqResult;
    use std::net::IpAddr;

    #[async_rt::test]
    async fn test_bind_to_any_port() -> ZmqResult<()> {
        let s = PubSocket::new();
        test_bind_to_any_port_helper(s).await
    }

    #[async_rt::test]
    async fn test_bind_to_any_ipv4_interface() -> ZmqResult<()> {
        let any_ipv4: IpAddr = "0.0.0.0".parse().unwrap();
        let s = PubSocket::new();
        test_bind_to_unspecified_interface_helper(any_ipv4, s, 4000).await
    }

    #[async_rt::test]
    async fn test_bind_to_any_ipv6_interface() -> ZmqResult<()> {
        let any_ipv6: IpAddr = "::".parse().unwrap();
        let s = PubSocket::new();
        test_bind_to_unspecified_interface_helper(any_ipv6, s, 4010).await
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// 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.

//! Interface for the SPI peripherals.
//!
//! RPPAL provides access to the available SPI peripherals by using the `/dev/spidevB.C`
//! devices, where B points to an SPI bus (0, 1, 2), and C to a Chip Enable pin (0, 1, 2).
//!
//! The Raspberry Pi's GPIO header exposes several SPI buses. SPI0 is available
//! on all Raspberry Pi models. SPI1 is available on models with a 40-pin
//! header. SPI2 is only available on the Compute and Compute 3.
//!
//! SPI0 is disabled by default. You can enable it by running
//! `sudo raspi-config`, or by manually adding `dtparam=spi=on` to
//! `/boot/config.txt`. The associated pins are listed below.
//!
//! * MISO: BCM GPIO 9 (physical pin 21)
//! * MOSI: BCM GPIO 10 (physical pin 19)
//! * SCLK: BCM GPIO 11 (physical pin 23)
//! * SS: CE0: BCM GPIO 8 (physical pin 24), CE1: BCM GPIO 7 (physical pin 26)
//!
//! SPI1 is an auxiliary peripheral that's referred to as mini SPI. According
//! to the documentation, using higher clock speeds on SPI1 requires additional
//! CPU time compared to SPI0, caused by shallow FIFOs and no DMA support. SPI1
//! can be enabled by adding `dtoverlay=spi1-3cs` to `/boot/config.txt`. Replace
//! `3cs` with either `2cs` or `1cs` if you only require 2 or 1 Slave Select pins.
//! The associated pins are listed below.
//!
//! * MISO: BCM GPIO 19 (physical pin 35)
//! * MOSI: BCM GPIO 20 (physical pin 38)
//! * SCLK: BCM GPIO 21 (physical pin 40)
//! * SS: CE0: BCM GPIO 18 (physical pin 12), CE1: BCM GPIO 17 (physical pin 11), CE2: BCM GPIO 16 (physical pin 36)
//!
//! SPI2 shares the same characteristics as SPI1. It can be enabled by adding
//! `dtoverlay=spi2-3cs` to `/boot/config.txt`. Replace `3cs` with either `2cs` or
//! `1cs` if you only require 2 or 1 Slave Select pins. The associated pins are
//! listed below.
//!
//! * MISO: BCM GPIO 40
//! * MOSI: BCM GPIO 41
//! * SCLK: BCM GPIO 42
//! * SS: CE0: BCM GPIO 43, CE1: BCM GPIO 44, CE2: BCM GPIO 45
//!
//! The GPIO pin numbers mentioned above are part of the default configuration. Some of
//! their functionality can be moved to different pins. Read `/boot/overlays/README`
//! for more information.

use std::fs::{File, OpenOptions};
use std::io;
use std::result;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when accessing the SPI peripherals.
    pub enum Error {
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `spi::Error`s.
pub type Result<T> = result::Result<T, Error>;

mod ioctl {}

/// SPI buses.
///
/// The Raspberry Pi supports up to three SPI buses, depending on the model and
/// your `/boot/config.txt` configuration. More information can be found [here].
///
/// [here]: index.html
pub enum Bus {
    Spi0 = 0,
    Spi1 = 1,
    Spi2 = 2,
}

/// Chip Enable (Slave Select) pins.
///
/// The Chip Enable pin is used to signal which device should
/// pay attention to the SPI bus. Chip Enable is more commonly
/// known as Slave Select or Chip Select.
///
/// The number of available Chip Enable pins for the selected SPI
/// bus depends on your `/boot/config.txt` configuration. More
/// information can be found [here].
///
/// [here]: index.html
pub enum ChipEnable {
    Ce0 = 0,
    Ce1 = 1,
    Ce2 = 2,
}

/// SPI modes.
///
/// Select the appropriate SPI mode for your device. Each mode
/// configures the clock polarity (CPOL) and clock phase (CPHA)
/// as shown below:
///
/// * Mode0: CPOL 0, CPHA 0
/// * Mode1: CPOL 0, CPHA 1
/// * Mode2: CPOL 1, CPHA 0
/// * Mode3: CPOL 1, CPHA 1
///
/// More information on clock polarity and phase can be found on [Wikipedia].
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase
pub enum Mode {
    Mode0 = 0, // CPOL 0, CPHA 0
    Mode1 = 1, // CPOL 0, CPHA 1
    Mode2 = 2, // CPOL 1, CPHA 0
    Mode3 = 3, // CPOL 1, CPHA 1
}

/// Provides access to the Raspberry Pi's SPI peripherals.
pub struct Spi {
    spidev: File,
}

impl Spi {
    pub fn new(bus: Bus, chip_enable: ChipEnable, mode: Mode, speed: u32) -> Result<Spi> {
        let spidev = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/spidev{}.{}", bus as u8, chip_enable as u8))?;

        Ok(Spi { spidev })
    }

    pub fn read(&self, mut buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn write(&self, buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn transfer(&self, mut read_buffer: &[u8], write_buffer: &[u8]) -> Result<()> {
        Ok(())
    }
}
<commit_msg>Add ioctl system calls<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// 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.

//! Interface for the SPI peripherals.
//!
//! RPPAL provides access to the available SPI peripherals by using the `/dev/spidevB.C`
//! devices, where B points to an SPI bus (0, 1, 2), and C to a Chip Enable pin (0, 1, 2).
//!
//! The Raspberry Pi's GPIO header exposes several SPI buses. SPI0 is available
//! on all Raspberry Pi models. SPI1 is available on models with a 40-pin
//! header. SPI2 is only available on the Compute and Compute 3.
//!
//! SPI0 is disabled by default. You can enable it by running
//! `sudo raspi-config`, or by manually adding `dtparam=spi=on` to
//! `/boot/config.txt`. The associated pins are listed below.
//!
//! * MISO: BCM GPIO 9 (physical pin 21)
//! * MOSI: BCM GPIO 10 (physical pin 19)
//! * SCLK: BCM GPIO 11 (physical pin 23)
//! * SS: CE0: BCM GPIO 8 (physical pin 24), CE1: BCM GPIO 7 (physical pin 26)
//!
//! SPI1 is an auxiliary peripheral that's referred to as mini SPI. According
//! to the documentation, using higher clock speeds on SPI1 requires additional
//! CPU time compared to SPI0, caused by shallow FIFOs and no DMA support. SPI1
//! can be enabled by adding `dtoverlay=spi1-3cs` to `/boot/config.txt`. Replace
//! `3cs` with either `2cs` or `1cs` if you only require 2 or 1 Slave Select pins.
//! The associated pins are listed below.
//!
//! * MISO: BCM GPIO 19 (physical pin 35)
//! * MOSI: BCM GPIO 20 (physical pin 38)
//! * SCLK: BCM GPIO 21 (physical pin 40)
//! * SS: CE0: BCM GPIO 18 (physical pin 12), CE1: BCM GPIO 17 (physical pin 11), CE2: BCM GPIO 16 (physical pin 36)
//!
//! SPI2 shares the same characteristics as SPI1. It can be enabled by adding
//! `dtoverlay=spi2-3cs` to `/boot/config.txt`. Replace `3cs` with either `2cs` or
//! `1cs` if you only require 2 or 1 Slave Select pins. The associated pins are
//! listed below.
//!
//! * MISO: BCM GPIO 40
//! * MOSI: BCM GPIO 41
//! * SCLK: BCM GPIO 42
//! * SS: CE0: BCM GPIO 43, CE1: BCM GPIO 44, CE2: BCM GPIO 45
//!
//! The GPIO pin numbers mentioned above are part of the default configuration. Some of
//! their functionality can be moved to different pins. Read `/boot/overlays/README`
//! for more information.

use std::fs::{File, OpenOptions};
use std::io;
use std::result;

quick_error! {
    #[derive(Debug)]
/// Errors that can occur when accessing the SPI peripherals.
    pub enum Error {
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
    }
}

/// Result type returned from methods that can have `spi::Error`s.
pub type Result<T> = result::Result<T, Error>;

mod ioctl {
    const SPI_IOC_MAGIC: u8 = b'k';

    const SPI_IOC_TYPE_MODE: u8 = 1;
    const SPI_IOC_TYPE_LSB_FIRST: u8 = 2;
    const SPI_IOC_TYPE_BITS_PER_WORD: u8 = 3;
    const SPI_IOC_TYPE_MAX_SPEED_HZ: u8 = 4;
    const SPI_IOC_TYPE_MESSAGE: u8 = 0;

    #[repr(C)]
    pub struct SpiIocTransfer {
        tx_buf: u64,
        rx_buf: u64,
        len: u32,
        speed_hz: u32,
        delay_usecs: u16,
        bits_per_word: u8,
        cs_change: u8,
        tx_nbits: u8,
        rx_nbits: u8,
        pad: u16,
    }

    ioctl!(write_int spi_write_mode with SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE);
    ioctl!(write_int spi_write_lsb_first with SPI_IOC_MAGIC, SPI_IOC_TYPE_LSB_FIRST);
    ioctl!(write_int spi_write_bits_per_word with SPI_IOC_MAGIC, SPI_IOC_TYPE_BITS_PER_WORD);
    ioctl!(write_int spi_write_max_speed_hz with SPI_IOC_MAGIC, SPI_IOC_TYPE_MAX_SPEED_HZ);
    ioctl!(write_buf spi_transfer with SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE; SpiIocTransfer);
}

/// SPI buses.
///
/// The Raspberry Pi supports up to three SPI buses, depending on the model and
/// your `/boot/config.txt` configuration. More information can be found [here].
///
/// [here]: index.html
pub enum Bus {
    Spi0 = 0,
    Spi1 = 1,
    Spi2 = 2,
}

/// Chip Enable (Slave Select) pins.
///
/// The Chip Enable pin is used to signal which device should
/// pay attention to the SPI bus. Chip Enable is more commonly
/// known as Slave Select or Chip Select.
///
/// The number of available Chip Enable pins for the selected SPI
/// bus depends on your `/boot/config.txt` configuration. More
/// information can be found [here].
///
/// [here]: index.html
pub enum ChipEnable {
    Ce0 = 0,
    Ce1 = 1,
    Ce2 = 2,
}

/// SPI modes.
///
/// Select the appropriate SPI mode for your device. Each mode
/// configures the clock polarity (CPOL) and clock phase (CPHA)
/// as shown below:
///
/// * Mode0: CPOL 0, CPHA 0
/// * Mode1: CPOL 0, CPHA 1
/// * Mode2: CPOL 1, CPHA 0
/// * Mode3: CPOL 1, CPHA 1
///
/// More information on clock polarity and phase can be found on [Wikipedia].
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase
pub enum Mode {
    Mode0 = 0, // CPOL 0, CPHA 0
    Mode1 = 1, // CPOL 0, CPHA 1
    Mode2 = 2, // CPOL 1, CPHA 0
    Mode3 = 3, // CPOL 1, CPHA 1
}

pub enum BitOrder {
    LsbFirst,
    MsbFirst,
}

/// Provides access to the Raspberry Pi's SPI peripherals.
pub struct Spi {
    spidev: File,
}

impl Spi {
    pub fn new(
        bus: Bus,
        chip_enable: ChipEnable,
        clock_speed: u32,
        mode: Mode,
        bit_order: BitOrder,
    ) -> Result<Spi> {
        // We don't ask for bits per word, because the driver only supports
        // 8 bits (or 9 bits in LoSSI mode). Changing the SS polarity from
        // active-low to active-high isn't supported either.
        // Based on https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
        // and https://www.kernel.org/doc/Documentation/spi/spidev.

        let spidev = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/spidev{}.{}", bus as u8, chip_enable as u8))?;

        Ok(Spi { spidev })
    }

    pub fn read(&self, mut buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn write(&self, buffer: &[u8]) -> Result<()> {
        Ok(())
    }

    pub fn transfer(&self, mut read_buffer: &[u8], write_buffer: &[u8]) -> Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::collections::HashMap;

use futures::{future, Async, Future, Poll, Sink, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};

use termion::event::{Event, Key, MouseButton, MouseEvent};
use tokio_core::reactor::Handle;
use xrl::{Client, ClientResult, Frontend, FrontendBuilder, ScrollTo, ServerResult, Style, Update};

use errors::*;
use terminal::{Terminal, TerminalEvent};
use view::View;

pub struct Tui {
    pub pending_open_requests: Vec<ClientResult<(String, View)>>,
    pub delayed_events: Vec<CoreEvent>,
    pub views: HashMap<String, View>,
    pub current_view: String,
    pub events: UnboundedReceiver<CoreEvent>,
    pub handle: Handle,
    pub client: Client,
    pub term: Terminal,
    pub term_size: (u16, u16),
    pub shutdown: bool,
    pub styles: HashMap<u64, Style>,
}

impl Tui {
    pub fn new(
        handle: Handle,
        client: Client,
        events: UnboundedReceiver<CoreEvent>,
    ) -> Result<Self> {
        let mut styles = HashMap::new();
        styles.insert(0, Default::default());

        Ok(Tui {
            events: events,
            delayed_events: Vec::new(),
            pending_open_requests: Vec::new(),
            handle: handle,
            term: Terminal::new()?,
            term_size: (0, 0),
            views: HashMap::new(),
            styles: styles,
            current_view: "".into(),
            client: client,
            shutdown: false,
        })
    }

    pub fn handle_core_event(&mut self, event: CoreEvent) {
        match event {
            CoreEvent::Update(update) => self.handle_update(update),
            CoreEvent::SetStyle(style) => self.handle_def_style(style),
            CoreEvent::ScrollTo(scroll_to) => self.handle_scroll_to(scroll_to),
        }
    }

    pub fn handle_update(&mut self, update: Update) {
        let Tui {
            ref mut views,
            ref mut delayed_events,
            ..
        } = *self;
        match views.get_mut(&update.view_id) {
            Some(view) => view.update_cache(update),
            None => delayed_events.push(CoreEvent::Update(update)),
        }
    }

    pub fn handle_scroll_to(&mut self, scroll_to: ScrollTo) {
        let Tui {
            ref mut views,
            ref mut delayed_events,
            ..
        } = *self;
        match views.get_mut(&scroll_to.view_id) {
            Some(view) => view.set_cursor(scroll_to.line, scroll_to.column),
            None => delayed_events.push(CoreEvent::ScrollTo(scroll_to)),
        }
    }

    pub fn handle_def_style(&mut self, style: Style) {
        self.styles.insert(style.id, style);
    }

    pub fn handle_resize(&mut self, size: (u16, u16)) {
        let Tui {
            ref mut views,
            ref current_view,
            ref mut client,
            ref mut handle,
            ..
        } = *self;
        info!("setting new terminal size");
        self.term_size = size;
        match views.get_mut(current_view) {
            Some(view) => {
                view.resize(size.1);
                let region = view.scroll_region();
                let future = client
                    .scroll(current_view, region.0, region.1)
                    .map_err(|_| ());
                handle.spawn(future);
            }
            None => warn!("view {} not found", current_view),
        }
    }

    pub fn insert(&mut self, character: char) {
        let future = self.client
            .char(&self.current_view, character)
            .map_err(|_| ());
        self.handle.spawn(future);
    }

    fn down(&mut self) {
        let future = self.client.down(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn up(&mut self) {
        let future = self.client.up(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn left(&mut self) {
        let future = self.client.left(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn right(&mut self) {
        let future = self.client.right(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    // FIXME: the core stops answering when we send "page_up" or "page_down"
    fn page_down(&mut self) {
        // let future = self.client.page_down(&self.current_view).map_err(|_| ());
        // self.handle.spawn(future);
    }

    fn page_up(&mut self) {
        // let future = self.client.page_up(&self.current_view).map_err(|_| ());
        // self.handle.spawn(future);
    }

    fn delete(&mut self) {
        let future = self.client.del(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    pub fn open(&mut self, file_path: String) {
        let task = self.client
            .new_view(Some(file_path.clone()))
            .and_then(move |view_id| Ok((view_id, View::new(Some(file_path)))));
        self.pending_open_requests.push(Box::new(task));
    }

    pub fn exit(&mut self) {
        self.shutdown = true;
    }

    pub fn save(&mut self) {
        let Tui {
            ref current_view,
            ref views,
            ref mut client,
            ref mut handle,
            ..
        } = *self;
        match views.get(current_view) {
            Some(view) => if let Some(file) = view.file() {
                info!("saving {} as {}", current_view, file);
                handle.spawn(client.save(current_view, file).map_err(|_| ()));
            } else {
                error!(
                    "view {} does not correspond to a file. Could not save it.",
                    current_view
                );
            },
            None => warn!("view {} not found", current_view),
        }
    }

    pub fn click(&mut self, x: u64, y: u64) {
        let Tui {
            ref mut client,
            ref mut views,
            ref mut handle,
            ref current_view,
            ..
        } = *self;
        if let Some(view) = views.get_mut(current_view) {
            let (line, column) = view.click(x, y);
            let future = client.click(current_view, line, column).map_err(|_| ());
            handle.spawn(future);
        }
        error!("view not found");
    }

    pub fn drag(&mut self, x: u64, y: u64) {
        let Tui {
            ref mut client,
            ref mut views,
            ref mut handle,
            ref current_view,
            ..
        } = *self;
        if let Some(view) = views.get_mut(current_view) {
            let (line, column) = view.click(x, y);
            let future = client.drag(current_view, line, column).map_err(|_| ());
            handle.spawn(future);
        }
        error!("view not found");
    }

    pub fn handle_input(&mut self, event: Event) {
        match event {
            Event::Key(key) => match key {
                Key::Char(c) => self.insert(c),
                Key::Ctrl(c) => match c {
                    'c' => {
                        info!("exiting");
                        self.exit();
                    }
                    'w' => self.save(),
                    _ => error!("un-handled input ctrl+{}", c),
                },
                Key::Backspace => self.delete(),
                Key::Left => self.left(),
                Key::Right => self.right(),
                Key::Up => self.up(),
                Key::Down => self.down(),
                Key::PageUp => self.page_up(),
                Key::PageDown => self.page_down(),
                k => error!("un-handled key {:?}", k),
            },
            Event::Mouse(mouse_event) => match mouse_event {
                MouseEvent::Press(press_event, y, x) => match press_event {
                    MouseButton::Left => self.click(u64::from(x) - 1, u64::from(y) - 1),
                    MouseButton::WheelUp => self.up(),
                    MouseButton::WheelDown => self.down(),
                    button => error!("un-handled button {:?}", button),
                },
                MouseEvent::Release(..) => {}
                MouseEvent::Hold(y, x) => self.drag(u64::from(x) - 1, u64::from(y) - 1),
            },
            ev => error!("un-handled event {:?}", ev),
        }
    }

    pub fn set_theme(&mut self, theme: &str) {
        let future = self.client.set_theme(theme).map_err(|_| ());
        self.handle.spawn(future);
    }

    pub fn process_open_requests(&mut self) {
        if self.pending_open_requests.is_empty() {
            return;
        }

        info!("process pending open requests");

        let Tui {
            ref mut pending_open_requests,
            ref mut views,
            ref mut current_view,
            ref mut client,
            ref mut handle,
            ref term_size,
            ..
        } = *self;

        let mut done = vec![];
        for (idx, task) in pending_open_requests.iter_mut().enumerate() {
            match task.poll() {
                Ok(Async::Ready((id, view))) => {
                    info!("open request succeeded for {}", &id);
                    done.push(idx);
                    views.insert(id.clone(), view);
                    *current_view = id;

                    let future = client
                        .scroll(current_view, 0, u64::from(term_size.1))
                        .map_err(|_| ());
                    handle.spawn(future);
                }
                Ok(Async::NotReady) => continue,
                Err(e) => panic!("\"open\" task failed: {}", e),
            }
        }
        for idx in done.iter().rev() {
            pending_open_requests.remove(*idx);
        }

        if pending_open_requests.is_empty() {
            info!("no more pending open request");
        }
    }

    pub fn process_terminal_events(&mut self) {
        let mut new_size: Option<(u16, u16)> = None;
        loop {
            match self.term.poll() {
                Ok(Async::Ready(Some(event))) => match event {
                    TerminalEvent::Resize(size) => {
                        new_size = Some(size);
                    }
                    TerminalEvent::Input(input) => self.handle_input(input),
                },
                Ok(Async::Ready(None)) => {
                    error!("terminal stream shut down => exiting");
                    self.shutdown = true;
                }
                Ok(Async::NotReady) => break,
                Err(_) => {
                    error!("error while polling terminal stream => exiting");
                    self.shutdown = true;
                }
            }
        }
        if let Some(size) = new_size {
            if !self.shutdown {
                self.handle_resize(size);
            }
        }
    }

    pub fn process_core_events(&mut self) {
        loop {
            match self.events.poll() {
                Ok(Async::Ready(Some(event))) => {
                    self.handle_core_event(event);
                }
                Ok(Async::Ready(None)) => {
                    error!("core stdout shut down => panicking");
                    panic!("core stdout shut down");
                }
                Ok(Async::NotReady) => break,
                Err(_) => {
                    error!("error while polling core => panicking");
                    panic!("error while polling core");
                }
            }
        }
    }

    pub fn process_delayed_events(&mut self) {
        let delayed_events: Vec<CoreEvent> = self.delayed_events.drain(..).collect();
        for event in delayed_events {
            self.handle_core_event(event);
        }
    }

    pub fn render(&mut self) -> Result<()> {
        let Tui {
            ref mut views,
            ref mut term,
            ref current_view,
            ref term_size,
            ref styles,
            ..
        } = *self;
        if let Some(view) = views.get_mut(current_view) {
            view.resize(term_size.1);
            view.render(term.stdout(), styles)?;
            if let Err(e) = term.stdout().flush() {
                error!("failed to flush stdout: {}", e);
            }
        }
        Ok(())
    }
}

#[derive(Debug)]
pub enum CoreEvent {
    Update(Update),
    ScrollTo(ScrollTo),
    SetStyle(Style),
}

impl Future for Tui {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.process_open_requests();
        self.process_delayed_events();
        self.process_terminal_events();
        self.process_core_events();

        if let Err(e) = self.render() {
            log_error(&e);
        }

        if self.shutdown {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

pub struct TuiService(UnboundedSender<CoreEvent>);

impl TuiService {
    fn send_core_event(&mut self, event: CoreEvent) -> ServerResult<()> {
        if let Err(e) = self.0.start_send(event) {
            let e = format!("failed to send core event to TUI: {}", e);
            error!("{}", e);
            return Box::new(future::err(e.into()));
        }
        match self.0.poll_complete() {
            Ok(_) => Box::new(future::ok(())),
            Err(e) => {
                let e = format!("failed to send core event to TUI: {}", e);
                Box::new(future::err(e.into()))
            }
        }
    }
}

impl Frontend for TuiService {
    fn update(&mut self, update: Update) -> ServerResult<()> {
        self.send_core_event(CoreEvent::Update(update))
    }

    fn scroll_to(&mut self, scroll_to: ScrollTo) -> ServerResult<()> {
        self.send_core_event(CoreEvent::ScrollTo(scroll_to))
    }

    fn def_style(&mut self, style: Style) -> ServerResult<()> {
        self.send_core_event(CoreEvent::SetStyle(style))
    }
}

pub struct TuiServiceBuilder(UnboundedSender<CoreEvent>);

impl TuiServiceBuilder {
    pub fn new() -> (Self, UnboundedReceiver<CoreEvent>) {
        let (tx, rx) = unbounded();
        (TuiServiceBuilder(tx), rx)
    }
}

impl FrontendBuilder<TuiService> for TuiServiceBuilder {
    fn build(self, _client: Client) -> TuiService {
        TuiService(self.0)
    }
}
<commit_msg>re-enable page_{up,down}<commit_after>use std::io::{self, Write};
use std::collections::HashMap;

use futures::{future, Async, Future, Poll, Sink, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};

use termion::event::{Event, Key, MouseButton, MouseEvent};
use tokio_core::reactor::Handle;
use xrl::{Client, ClientResult, Frontend, FrontendBuilder, ScrollTo, ServerResult, Style, Update};

use errors::*;
use terminal::{Terminal, TerminalEvent};
use view::View;

pub struct Tui {
    pub pending_open_requests: Vec<ClientResult<(String, View)>>,
    pub delayed_events: Vec<CoreEvent>,
    pub views: HashMap<String, View>,
    pub current_view: String,
    pub events: UnboundedReceiver<CoreEvent>,
    pub handle: Handle,
    pub client: Client,
    pub term: Terminal,
    pub term_size: (u16, u16),
    pub shutdown: bool,
    pub styles: HashMap<u64, Style>,
}

impl Tui {
    pub fn new(
        handle: Handle,
        client: Client,
        events: UnboundedReceiver<CoreEvent>,
    ) -> Result<Self> {
        let mut styles = HashMap::new();
        styles.insert(0, Default::default());

        Ok(Tui {
            events: events,
            delayed_events: Vec::new(),
            pending_open_requests: Vec::new(),
            handle: handle,
            term: Terminal::new()?,
            term_size: (0, 0),
            views: HashMap::new(),
            styles: styles,
            current_view: "".into(),
            client: client,
            shutdown: false,
        })
    }

    pub fn handle_core_event(&mut self, event: CoreEvent) {
        match event {
            CoreEvent::Update(update) => self.handle_update(update),
            CoreEvent::SetStyle(style) => self.handle_def_style(style),
            CoreEvent::ScrollTo(scroll_to) => self.handle_scroll_to(scroll_to),
        }
    }

    pub fn handle_update(&mut self, update: Update) {
        let Tui {
            ref mut views,
            ref mut delayed_events,
            ..
        } = *self;
        match views.get_mut(&update.view_id) {
            Some(view) => view.update_cache(update),
            None => delayed_events.push(CoreEvent::Update(update)),
        }
    }

    pub fn handle_scroll_to(&mut self, scroll_to: ScrollTo) {
        let Tui {
            ref mut views,
            ref mut delayed_events,
            ..
        } = *self;
        match views.get_mut(&scroll_to.view_id) {
            Some(view) => view.set_cursor(scroll_to.line, scroll_to.column),
            None => delayed_events.push(CoreEvent::ScrollTo(scroll_to)),
        }
    }

    pub fn handle_def_style(&mut self, style: Style) {
        self.styles.insert(style.id, style);
    }

    pub fn handle_resize(&mut self, size: (u16, u16)) {
        let Tui {
            ref mut views,
            ref current_view,
            ref mut client,
            ref mut handle,
            ..
        } = *self;
        info!("setting new terminal size");
        self.term_size = size;
        match views.get_mut(current_view) {
            Some(view) => {
                view.resize(size.1);
                let region = view.scroll_region();
                let future = client
                    .scroll(current_view, region.0, region.1)
                    .map_err(|_| ());
                handle.spawn(future);
            }
            None => warn!("view {} not found", current_view),
        }
    }

    pub fn insert(&mut self, character: char) {
        let future = self.client
            .char(&self.current_view, character)
            .map_err(|_| ());
        self.handle.spawn(future);
    }

    fn down(&mut self) {
        let future = self.client.down(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn up(&mut self) {
        let future = self.client.up(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn left(&mut self) {
        let future = self.client.left(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn right(&mut self) {
        let future = self.client.right(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn page_down(&mut self) {
        let future = self.client.page_down(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn page_up(&mut self) {
        let future = self.client.page_up(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    fn delete(&mut self) {
        let future = self.client.del(&self.current_view).map_err(|_| ());
        self.handle.spawn(future);
    }

    pub fn open(&mut self, file_path: String) {
        let task = self.client
            .new_view(Some(file_path.clone()))
            .and_then(move |view_id| Ok((view_id, View::new(Some(file_path)))));
        self.pending_open_requests.push(Box::new(task));
    }

    pub fn exit(&mut self) {
        self.shutdown = true;
    }

    pub fn save(&mut self) {
        let Tui {
            ref current_view,
            ref views,
            ref mut client,
            ref mut handle,
            ..
        } = *self;
        match views.get(current_view) {
            Some(view) => if let Some(file) = view.file() {
                info!("saving {} as {}", current_view, file);
                handle.spawn(client.save(current_view, file).map_err(|_| ()));
            } else {
                error!(
                    "view {} does not correspond to a file. Could not save it.",
                    current_view
                );
            },
            None => warn!("view {} not found", current_view),
        }
    }

    pub fn click(&mut self, x: u64, y: u64) {
        let Tui {
            ref mut client,
            ref mut views,
            ref mut handle,
            ref current_view,
            ..
        } = *self;
        if let Some(view) = views.get_mut(current_view) {
            let (line, column) = view.click(x, y);
            let future = client.click(current_view, line, column).map_err(|_| ());
            handle.spawn(future);
        }
        error!("view not found");
    }

    pub fn drag(&mut self, x: u64, y: u64) {
        let Tui {
            ref mut client,
            ref mut views,
            ref mut handle,
            ref current_view,
            ..
        } = *self;
        if let Some(view) = views.get_mut(current_view) {
            let (line, column) = view.click(x, y);
            let future = client.drag(current_view, line, column).map_err(|_| ());
            handle.spawn(future);
        }
        error!("view not found");
    }

    pub fn handle_input(&mut self, event: Event) {
        match event {
            Event::Key(key) => match key {
                Key::Char(c) => self.insert(c),
                Key::Ctrl(c) => match c {
                    'c' => {
                        info!("exiting");
                        self.exit();
                    }
                    'w' => self.save(),
                    _ => error!("un-handled input ctrl+{}", c),
                },
                Key::Backspace => self.delete(),
                Key::Left => self.left(),
                Key::Right => self.right(),
                Key::Up => self.up(),
                Key::Down => self.down(),
                Key::PageUp => self.page_up(),
                Key::PageDown => self.page_down(),
                k => error!("un-handled key {:?}", k),
            },
            Event::Mouse(mouse_event) => match mouse_event {
                MouseEvent::Press(press_event, y, x) => match press_event {
                    MouseButton::Left => self.click(u64::from(x) - 1, u64::from(y) - 1),
                    MouseButton::WheelUp => self.up(),
                    MouseButton::WheelDown => self.down(),
                    button => error!("un-handled button {:?}", button),
                },
                MouseEvent::Release(..) => {}
                MouseEvent::Hold(y, x) => self.drag(u64::from(x) - 1, u64::from(y) - 1),
            },
            ev => error!("un-handled event {:?}", ev),
        }
    }

    pub fn set_theme(&mut self, theme: &str) {
        let future = self.client.set_theme(theme).map_err(|_| ());
        self.handle.spawn(future);
    }

    pub fn process_open_requests(&mut self) {
        if self.pending_open_requests.is_empty() {
            return;
        }

        info!("process pending open requests");

        let Tui {
            ref mut pending_open_requests,
            ref mut views,
            ref mut current_view,
            ref mut client,
            ref mut handle,
            ref term_size,
            ..
        } = *self;

        let mut done = vec![];
        for (idx, task) in pending_open_requests.iter_mut().enumerate() {
            match task.poll() {
                Ok(Async::Ready((id, view))) => {
                    info!("open request succeeded for {}", &id);
                    done.push(idx);
                    views.insert(id.clone(), view);
                    *current_view = id;

                    let future = client
                        .scroll(current_view, 0, u64::from(term_size.1))
                        .map_err(|_| ());
                    handle.spawn(future);
                }
                Ok(Async::NotReady) => continue,
                Err(e) => panic!("\"open\" task failed: {}", e),
            }
        }
        for idx in done.iter().rev() {
            pending_open_requests.remove(*idx);
        }

        if pending_open_requests.is_empty() {
            info!("no more pending open request");
        }
    }

    pub fn process_terminal_events(&mut self) {
        let mut new_size: Option<(u16, u16)> = None;
        loop {
            match self.term.poll() {
                Ok(Async::Ready(Some(event))) => match event {
                    TerminalEvent::Resize(size) => {
                        new_size = Some(size);
                    }
                    TerminalEvent::Input(input) => self.handle_input(input),
                },
                Ok(Async::Ready(None)) => {
                    error!("terminal stream shut down => exiting");
                    self.shutdown = true;
                }
                Ok(Async::NotReady) => break,
                Err(_) => {
                    error!("error while polling terminal stream => exiting");
                    self.shutdown = true;
                }
            }
        }
        if let Some(size) = new_size {
            if !self.shutdown {
                self.handle_resize(size);
            }
        }
    }

    pub fn process_core_events(&mut self) {
        loop {
            match self.events.poll() {
                Ok(Async::Ready(Some(event))) => {
                    self.handle_core_event(event);
                }
                Ok(Async::Ready(None)) => {
                    error!("core stdout shut down => panicking");
                    panic!("core stdout shut down");
                }
                Ok(Async::NotReady) => break,
                Err(_) => {
                    error!("error while polling core => panicking");
                    panic!("error while polling core");
                }
            }
        }
    }

    pub fn process_delayed_events(&mut self) {
        let delayed_events: Vec<CoreEvent> = self.delayed_events.drain(..).collect();
        for event in delayed_events {
            self.handle_core_event(event);
        }
    }

    pub fn render(&mut self) -> Result<()> {
        let Tui {
            ref mut views,
            ref mut term,
            ref current_view,
            ref term_size,
            ref styles,
            ..
        } = *self;
        if let Some(view) = views.get_mut(current_view) {
            view.resize(term_size.1);
            view.render(term.stdout(), styles)?;
            if let Err(e) = term.stdout().flush() {
                error!("failed to flush stdout: {}", e);
            }
        }
        Ok(())
    }
}

#[derive(Debug)]
pub enum CoreEvent {
    Update(Update),
    ScrollTo(ScrollTo),
    SetStyle(Style),
}

impl Future for Tui {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        self.process_open_requests();
        self.process_delayed_events();
        self.process_terminal_events();
        self.process_core_events();

        if let Err(e) = self.render() {
            log_error(&e);
        }

        if self.shutdown {
            Ok(Async::Ready(()))
        } else {
            Ok(Async::NotReady)
        }
    }
}

pub struct TuiService(UnboundedSender<CoreEvent>);

impl TuiService {
    fn send_core_event(&mut self, event: CoreEvent) -> ServerResult<()> {
        if let Err(e) = self.0.start_send(event) {
            let e = format!("failed to send core event to TUI: {}", e);
            error!("{}", e);
            return Box::new(future::err(e.into()));
        }
        match self.0.poll_complete() {
            Ok(_) => Box::new(future::ok(())),
            Err(e) => {
                let e = format!("failed to send core event to TUI: {}", e);
                Box::new(future::err(e.into()))
            }
        }
    }
}

impl Frontend for TuiService {
    fn update(&mut self, update: Update) -> ServerResult<()> {
        self.send_core_event(CoreEvent::Update(update))
    }

    fn scroll_to(&mut self, scroll_to: ScrollTo) -> ServerResult<()> {
        self.send_core_event(CoreEvent::ScrollTo(scroll_to))
    }

    fn def_style(&mut self, style: Style) -> ServerResult<()> {
        self.send_core_event(CoreEvent::SetStyle(style))
    }
}

pub struct TuiServiceBuilder(UnboundedSender<CoreEvent>);

impl TuiServiceBuilder {
    pub fn new() -> (Self, UnboundedReceiver<CoreEvent>) {
        let (tx, rx) = unbounded();
        (TuiServiceBuilder(tx), rx)
    }
}

impl FrontendBuilder<TuiService> for TuiServiceBuilder {
    fn build(self, _client: Client) -> TuiService {
        TuiService(self.0)
    }
}
<|endoftext|>


<commit_before>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

#![crate_name = "msgsend"]

extern crate zmq;

use std::env;
use std::thread;
use std::time::Instant;
use std::sync::mpsc::{channel, Sender, Receiver};

fn server(pull_socket: zmq::Socket, push_socket: zmq::Socket, mut workers: u64) {
    let mut count = 0;
    let mut msg = zmq::Message::new().unwrap();

    while workers != 0 {
        pull_socket.recv(&mut msg, 0).unwrap();
        let s = msg.as_str().unwrap();
        if s.is_empty() {
            workers -= 1;
        } else {
            count += s.parse::<u32>().unwrap();
        }
    }

    push_socket.send_str(&count.to_string(), 0).unwrap();
}

fn spawn_server(ctx: &mut zmq::Context, workers: u64) -> Sender<()> {
    let pull_socket = ctx.socket(zmq::PULL).unwrap();
    let push_socket = ctx.socket(zmq::PUSH).unwrap();

    pull_socket.bind("inproc://server-pull").unwrap();
    push_socket.bind("inproc://server-push").unwrap();

    // Spawn the server.
    let (ready_tx, ready_rx) = channel();
    let (start_tx, start_rx) = channel();

    thread::spawn(move|| {
        // Let the main thread know we're ready.
        ready_tx.send(()).unwrap();

        // Wait until we need to start.
        start_rx.recv().unwrap();

        server(pull_socket, push_socket, workers);
    });

    // Wait for the server to start.
    ready_rx.recv().unwrap();

    start_tx
}

fn worker(push_socket: zmq::Socket, count: u64) {
    for _ in 0 .. count {
        push_socket.send_str(&100.to_string(), 0).unwrap();
    }

    // Let the server know we're done.
    push_socket.send_str("", 0).unwrap();
}

fn spawn_worker(ctx: &mut zmq::Context, count: u64) -> Receiver<()> {
    let push_socket = ctx.socket(zmq::PUSH).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();

    // Spawn the worker.
    let (tx, rx) = channel();
    thread::spawn(move|| {
        // Let the main thread we're ready.
        tx.send(()).unwrap();

        worker(push_socket, count);

        tx.send(()).unwrap();
    });

    // Wait for the worker to start.
    rx.recv().unwrap();

    rx
}

fn run(ctx: &mut zmq::Context, size: u64, workers: u64) {
    let start_ch = spawn_server(ctx, workers);

    // Create some command/control sockets.
    let push_socket = ctx.socket(zmq::PUSH).unwrap();
    let pull_socket = ctx.socket(zmq::PULL).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    pull_socket.connect("inproc://server-push").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();
    //pull_socket.connect("tcp://127.0.0.1:3457").unwrap();

    // Spawn all the workers.
    let mut worker_results = Vec::new();
    for _ in 0 .. workers {
        worker_results.push(spawn_worker(ctx, size / workers));
    }

    let start = Instant::now();

    start_ch.send(()).unwrap();

    // Block until all the workers finish.
    for po in worker_results {
        po.recv().unwrap();
    }

    // Receive the final count.
    let msg = pull_socket.recv_msg(0).unwrap();
    let result = msg.as_str().unwrap().parse::<i32>().unwrap();

    let elapsed = start.elapsed();

    println!("Count is {}", result);
    println!("Test took {} seconds", elapsed.as_secs());
    let thruput = ((size / workers * workers) as f64) / (elapsed.as_secs() as f64);
    println!("Throughput={} per sec", thruput);
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let args = if env::var("RUST_BENCH").is_ok() {
        vec!("".to_string(), "1000000".to_string(), "10000".to_string())
    } else if args.len() <= 1 {
        vec!("".to_string(), "10000".to_string(), "4".to_string())
    } else {
        args
    };

    let size = args[1].parse().unwrap();
    let workers = args[2].parse().unwrap();

    let mut ctx = zmq::Context::new();

    run(&mut ctx, size, workers);
}
<commit_msg>Fix throughput calculation in `msgsend` example<commit_after>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

#![crate_name = "msgsend"]

extern crate zmq;

use std::env;
use std::thread;
use std::time::{Duration, Instant};
use std::sync::mpsc::{channel, Sender, Receiver};

fn server(pull_socket: zmq::Socket, push_socket: zmq::Socket, mut workers: u64) {
    let mut count = 0;
    let mut msg = zmq::Message::new().unwrap();

    while workers != 0 {
        pull_socket.recv(&mut msg, 0).unwrap();
        let s = msg.as_str().unwrap();
        if s.is_empty() {
            workers -= 1;
        } else {
            count += s.parse::<u32>().unwrap();
        }
    }

    push_socket.send_str(&count.to_string(), 0).unwrap();
}

fn spawn_server(ctx: &mut zmq::Context, workers: u64) -> Sender<()> {
    let pull_socket = ctx.socket(zmq::PULL).unwrap();
    let push_socket = ctx.socket(zmq::PUSH).unwrap();

    pull_socket.bind("inproc://server-pull").unwrap();
    push_socket.bind("inproc://server-push").unwrap();

    // Spawn the server.
    let (ready_tx, ready_rx) = channel();
    let (start_tx, start_rx) = channel();

    thread::spawn(move|| {
        // Let the main thread know we're ready.
        ready_tx.send(()).unwrap();

        // Wait until we need to start.
        start_rx.recv().unwrap();

        server(pull_socket, push_socket, workers);
    });

    // Wait for the server to start.
    ready_rx.recv().unwrap();

    start_tx
}

fn worker(push_socket: zmq::Socket, count: u64) {
    for _ in 0 .. count {
        push_socket.send_str(&100.to_string(), 0).unwrap();
    }

    // Let the server know we're done.
    push_socket.send_str("", 0).unwrap();
}

fn spawn_worker(ctx: &mut zmq::Context, count: u64) -> Receiver<()> {
    let push_socket = ctx.socket(zmq::PUSH).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();

    // Spawn the worker.
    let (tx, rx) = channel();
    thread::spawn(move|| {
        // Let the main thread we're ready.
        tx.send(()).unwrap();

        worker(push_socket, count);

        tx.send(()).unwrap();
    });

    // Wait for the worker to start.
    rx.recv().unwrap();

    rx
}

fn seconds(d: &Duration) -> f64 {
    d.as_secs() as f64 + (d.subsec_nanos() as f64 / 1e9)
}

fn run(ctx: &mut zmq::Context, size: u64, workers: u64) {
    let start_ch = spawn_server(ctx, workers);

    // Create some command/control sockets.
    let push_socket = ctx.socket(zmq::PUSH).unwrap();
    let pull_socket = ctx.socket(zmq::PULL).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    pull_socket.connect("inproc://server-push").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();
    //pull_socket.connect("tcp://127.0.0.1:3457").unwrap();

    // Spawn all the workers.
    let mut worker_results = Vec::new();
    for _ in 0 .. workers {
        worker_results.push(spawn_worker(ctx, size / workers));
    }

    let start = Instant::now();

    start_ch.send(()).unwrap();

    // Block until all the workers finish.
    for po in worker_results {
        po.recv().unwrap();
    }

    // Receive the final count.
    let msg = pull_socket.recv_msg(0).unwrap();
    let result = msg.as_str().unwrap().parse::<i32>().unwrap();

    let elapsed = seconds(&start.elapsed());

    println!("Count is {}", result);
    println!("Test took {} seconds", elapsed);
    let thruput = ((size / workers * workers) as f64) / elapsed;
    println!("Throughput={} per sec", thruput);
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let args = if env::var("RUST_BENCH").is_ok() {
        vec!("".to_string(), "1000000".to_string(), "10000".to_string())
    } else if args.len() <= 1 {
        vec!("".to_string(), "10000".to_string(), "4".to_string())
    } else {
        args
    };

    let size = args[1].parse().unwrap();
    let workers = args[2].parse().unwrap();

    let mut ctx = zmq::Context::new();

    run(&mut ctx, size, workers);
}
<|endoftext|>


<commit_before>// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use std::fs::File;

use std::io::prelude::*;
use std::io::BufReader;

use quiche::h3::qpack;

const USAGE: &str = "Usage:
  qpack-encode [options] FILE
  qpack-encode -h | --help

Options:
  -h --help  Show this screen.
";

fn main() -> Result<(), Box<std::error::Error>> {
    env_logger::init();

    let args = docopt::Docopt::new(USAGE)
        .and_then(|dopt| dopt.parse())
        .unwrap_or_else(|e| e.exit());

    let file = File::open(args.get_str("FILE"))?;
    let file = BufReader::new(&file);

    let mut enc = qpack::Encoder::new();

    let mut headers: Vec<qpack::Header> = Vec::new();

    let mut stream_id = 1u64;

    for line in file.lines().map(|l| l.unwrap()) {
        if line.starts_with('#') {
            continue;
        }

        if line.is_empty() {
            let mut out = [0u8; 65535];

            let len = enc.encode(&headers, &mut out)?;

            debug!("Writing header block stream={} len={}", stream_id, len);

            std::io::stdout().write_all(&stream_id.to_be_bytes())?;
            std::io::stdout().write_all(&(len as u32).to_be_bytes())?;
            std::io::stdout().write_all(&out[..len])?;

            stream_id += 1;

            headers.clear();

            continue;
        }

        let name = line.split('\t').nth(0).unwrap();
        let value = line.split('\t').last().unwrap();

        headers.push(qpack::Header::new(name, value));
    }

    Ok(())
}
<commit_msg>qpack-encode: remove redundant closure<commit_after>// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use std::fs::File;

use std::io::prelude::*;
use std::io::BufReader;

use quiche::h3::qpack;

const USAGE: &str = "Usage:
  qpack-encode [options] FILE
  qpack-encode -h | --help

Options:
  -h --help  Show this screen.
";

fn main() -> Result<(), Box<std::error::Error>> {
    env_logger::init();

    let args = docopt::Docopt::new(USAGE)
        .and_then(|dopt| dopt.parse())
        .unwrap_or_else(|e| e.exit());

    let file = File::open(args.get_str("FILE"))?;
    let file = BufReader::new(&file);

    let mut enc = qpack::Encoder::new();

    let mut headers: Vec<qpack::Header> = Vec::new();

    let mut stream_id = 1u64;

    for line in file.lines().map(Result::unwrap) {
        if line.starts_with('#') {
            continue;
        }

        if line.is_empty() {
            let mut out = [0u8; 65535];

            let len = enc.encode(&headers, &mut out)?;

            debug!("Writing header block stream={} len={}", stream_id, len);

            std::io::stdout().write_all(&stream_id.to_be_bytes())?;
            std::io::stdout().write_all(&(len as u32).to_be_bytes())?;
            std::io::stdout().write_all(&out[..len])?;

            stream_id += 1;

            headers.clear();

            continue;
        }

        let name = line.split('\t').nth(0).unwrap();
        let value = line.split('\t').last().unwrap();

        headers.push(qpack::Header::new(name, value));
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::io;
use std::collections::{HashMap, VecDeque};
use debug::{self, SymbolHandler};
use api;

pub fn parse(
    value: &debug::Value, symbols: &SymbolHandler,
    pointers: &mut VecDeque<(usize, u32)>
) -> api::Value {
    parse_bytes(&value.data, &value.data_type, symbols, value.module, pointers)
}

fn parse_bytes(
    data: &[u8], data_type: &debug::Type, symbols: &SymbolHandler, module: usize,
    pointers: &mut VecDeque<(usize, u32)>
) -> api::Value {
    let value = data.as_ptr();

    use debug::Type::*;
    match *data_type {
        Base { base, size } => {
            use debug::Primitive::*;
            match base {
                Void => api::Value::Null,
                Bool => api::Value::Boolean(unsafe { *(value as *const bool) }),
                Int { signed: true } => match size {
                    1 => api::Value::Integer(unsafe { *(value as *const i8) } as i64),
                    2 => api::Value::Integer(unsafe { *(value as *const i16) } as i64),
                    4 => api::Value::Integer(unsafe { *(value as *const i32) } as i64),
                    8 => api::Value::Integer(unsafe { *(value as *const i64) } as i64),
                    _ => unreachable!(),
                },
                Int { signed: false } => match size {
                    1 => api::Value::Integer(unsafe { *(value as *const u8) } as i64),
                    2 => api::Value::Integer(unsafe { *(value as *const u16) } as i64),
                    4 => api::Value::Integer(unsafe { *(value as *const u32) } as i64),
                    8 => api::Value::Integer(unsafe { *(value as *const u64) } as i64),
                    _ => unreachable!(),
                },
                Float => match size {
                    4 => api::Value::Number(unsafe { *(value as *const f32) } as f64),
                    8 => api::Value::Number(unsafe { *(value as *const f64) } as f64),
                    _ => unreachable!(),
                },
            }
        }

        Pointer { type_index } => {
            let address = unsafe { *(value as *const usize) };
            pointers.push_back((address, type_index));

            api::Value::Integer(address as i64)
        }

        Array { type_index, count } => {
            let element_type = symbols.type_from_index(module, type_index)
                .expect("corrupt element type");
            let size = element_type.size(symbols, module);

            let mut values = vec![];
            for offset in (0..count).map(|i| i * size) {
                let data = &data[offset..offset+size];

                let value = parse_bytes(data, &element_type, symbols, module, pointers);
                values.push(value);
            }

            api::Value::Array(values)
        }

        Struct { ref fields, .. } => {
            let mut values = HashMap::new();
            for &debug::Field { type_index, offset, .. } in fields {
                let field_type = symbols.type_from_index(module, type_index)
                    .expect("corrupt field type");

                let offset = offset as usize;
                let size = field_type.size(symbols, module);
                let data = &data[offset..offset + size];

                let value = parse_bytes(data, &field_type, symbols, module, pointers);
                values.insert(offset as u32, value);
            }

            api::Value::Struct(values)
        }

        _ => api::Value::Null,
    }
}

pub fn trace_pointers(
    child: &debug::Child, symbols: &debug::SymbolHandler, module: usize, base: usize,
    pointers: &mut VecDeque<(usize, u32)>, values: &mut HashMap<usize, api::Value>
) {
    while let Some((address, type_index)) = pointers.pop_front() {
        let offset = address - base;
        if values.contains_key(&address) || values.contains_key(&offset) {
            continue;
        }

        let value = match debug::Value::read_pointer(
            child, symbols, address, module, type_index
        ) {
            Ok(value) => value,
            _ => continue,
        };

        if value.data[0] == 0xcc {
            continue;
        }

        let value = parse(&value, symbols, pointers);
        values.insert(address, value);
    }
}

impl debug::IntoValue for api::Value {
    fn into_value(
        self, data_type: debug::Type, module: usize, symbols: &debug::SymbolHandler,
        value_offset: usize, offsets: &mut HashMap<usize, usize>,
        pointers: &mut VecDeque<(usize, u32)>
    ) -> io::Result<debug::Value> {
        let mut data = vec![0; data_type.size(symbols, module)];

        use debug::Type::*;
        use debug::Primitive::*;
        match (&data_type, self) {
            (&Base { base: Void, .. }, api::Value::Null) => {}

            (&Base { base: Bool, .. }, api::Value::Boolean(value)) => {
                unsafe { *(data.as_mut_ptr() as *mut bool) = value };
            }

            (&Base { base: Int { signed }, size }, api::Value::Integer(value)) => {
                if signed {
                    match size {
                        1 => unsafe { *(data.as_mut_ptr() as *mut i8) = value as i8 },
                        2 => unsafe { *(data.as_mut_ptr() as *mut i16) = value as i16 },
                        4 => unsafe { *(data.as_mut_ptr() as *mut i32) = value as i32 },
                        8 => unsafe { *(data.as_mut_ptr() as *mut i64) = value as i64 },
                        _ => unreachable!(),
                    }
                } else {
                    match size {
                        1 => unsafe { *(data.as_mut_ptr() as *mut u8) = value as u8 },
                        2 => unsafe { *(data.as_mut_ptr() as *mut u16) = value as u16 },
                        4 => unsafe { *(data.as_mut_ptr() as *mut u32) = value as u32 },
                        8 => unsafe { *(data.as_mut_ptr() as *mut u64) = value as u64 },
                        _ => unreachable!(),
                    }
                }
            }

            (&Pointer { type_index }, api::Value::Integer(value)) => {
                offsets.insert(value_offset, value as usize);
                pointers.push_back((value as usize, type_index));
            }

            (&Array { type_index, count }, api::Value::Array(values)) => {
                if count != values.len() {
                    return Err(io::Error::from(io::ErrorKind::InvalidInput));
                }

                let element_type = symbols.type_from_index(module, type_index)?;
                let size = element_type.size(symbols, module);

                for (offset, value) in values.into_iter().enumerate().map(|(i, v)| (i * size, v)) {
                    let data_type = element_type.clone();
                    let data = &mut data[offset..offset + size];

                    let offset = value_offset + offset;
                    let value = value
                        .into_value(data_type, module, symbols, offset, offsets, pointers)?;
                    data.copy_from_slice(&value.data);
                }
            }

            (&Struct { ref fields, .. }, api::Value::Struct(ref mut values)) => {
                for &debug::Field { type_index, offset, .. } in fields {
                    let value = match values.remove(&offset) {
                        Some(value) => value,
                        _ => return Err(io::Error::from(io::ErrorKind::InvalidInput)),
                    };

                    let data_type = symbols.type_from_index(module, type_index)?;

                    let offset = offset as usize;
                    let size = data_type.size(symbols, module);
                    let data = &mut data[offset..offset + size];

                    let offset = value_offset + offset;
                    let value = value
                        .into_value(data_type, module, symbols, offset, offsets, pointers)?;
                    data.copy_from_slice(&value.data);
                }
            }

            _ => return Err(io::Error::from(io::ErrorKind::InvalidInput)),
        }

        Ok(debug::Value { data, data_type, module })
    }
}
<commit_msg>Don't panic on value offsets<commit_after>use std::io;
use std::collections::{HashMap, VecDeque};
use debug::{self, SymbolHandler};
use api;

pub fn parse(
    value: &debug::Value, symbols: &SymbolHandler,
    pointers: &mut VecDeque<(usize, u32)>
) -> api::Value {
    parse_bytes(&value.data, &value.data_type, symbols, value.module, pointers)
}

fn parse_bytes(
    data: &[u8], data_type: &debug::Type, symbols: &SymbolHandler, module: usize,
    pointers: &mut VecDeque<(usize, u32)>
) -> api::Value {
    let value = data.as_ptr();

    use debug::Type::*;
    match *data_type {
        Base { base, size } => {
            use debug::Primitive::*;
            match base {
                Void => api::Value::Null,
                Bool => api::Value::Boolean(unsafe { *(value as *const bool) }),
                Int { signed: true } => match size {
                    1 => api::Value::Integer(unsafe { *(value as *const i8) } as i64),
                    2 => api::Value::Integer(unsafe { *(value as *const i16) } as i64),
                    4 => api::Value::Integer(unsafe { *(value as *const i32) } as i64),
                    8 => api::Value::Integer(unsafe { *(value as *const i64) } as i64),
                    _ => unreachable!(),
                },
                Int { signed: false } => match size {
                    1 => api::Value::Integer(unsafe { *(value as *const u8) } as i64),
                    2 => api::Value::Integer(unsafe { *(value as *const u16) } as i64),
                    4 => api::Value::Integer(unsafe { *(value as *const u32) } as i64),
                    8 => api::Value::Integer(unsafe { *(value as *const u64) } as i64),
                    _ => unreachable!(),
                },
                Float => match size {
                    4 => api::Value::Number(unsafe { *(value as *const f32) } as f64),
                    8 => api::Value::Number(unsafe { *(value as *const f64) } as f64),
                    _ => unreachable!(),
                },
            }
        }

        Pointer { type_index } => {
            let address = unsafe { *(value as *const usize) };
            pointers.push_back((address, type_index));

            api::Value::Integer(address as i64)
        }

        Array { type_index, count } => {
            let element_type = symbols.type_from_index(module, type_index)
                .expect("corrupt element type");
            let size = element_type.size(symbols, module);

            let mut values = vec![];
            for offset in (0..count).map(|i| i * size) {
                let data = &data[offset..offset+size];

                let value = parse_bytes(data, &element_type, symbols, module, pointers);
                values.push(value);
            }

            api::Value::Array(values)
        }

        Struct { ref fields, .. } => {
            let mut values = HashMap::new();
            for &debug::Field { type_index, offset, .. } in fields {
                let field_type = symbols.type_from_index(module, type_index)
                    .expect("corrupt field type");

                let offset = offset as usize;
                let size = field_type.size(symbols, module);
                let data = &data[offset..offset + size];

                let value = parse_bytes(data, &field_type, symbols, module, pointers);
                values.insert(offset as u32, value);
            }

            api::Value::Struct(values)
        }

        _ => api::Value::Null,
    }
}

pub fn trace_pointers(
    child: &debug::Child, symbols: &debug::SymbolHandler, module: usize, base: usize,
    pointers: &mut VecDeque<(usize, u32)>, values: &mut HashMap<usize, api::Value>
) {
    while let Some((address, type_index)) = pointers.pop_front() {
        let offset = address.checked_sub(base);
        if
            values.contains_key(&address) ||
            offset.map(|offset| values.contains_key(&offset)).unwrap_or(false)
        {
            continue;
        }

        let value = match debug::Value::read_pointer(
            child, symbols, address, module, type_index
        ) {
            Ok(value) => value,
            _ => continue,
        };

        if value.data[0] == 0xcc {
            continue;
        }

        let value = parse(&value, symbols, pointers);
        values.insert(address, value);
    }
}

impl debug::IntoValue for api::Value {
    fn into_value(
        self, data_type: debug::Type, module: usize, symbols: &debug::SymbolHandler,
        value_offset: usize, offsets: &mut HashMap<usize, usize>,
        pointers: &mut VecDeque<(usize, u32)>
    ) -> io::Result<debug::Value> {
        let mut data = vec![0; data_type.size(symbols, module)];

        use debug::Type::*;
        use debug::Primitive::*;
        match (&data_type, self) {
            (&Base { base: Void, .. }, api::Value::Null) => {}

            (&Base { base: Bool, .. }, api::Value::Boolean(value)) => {
                unsafe { *(data.as_mut_ptr() as *mut bool) = value };
            }

            (&Base { base: Int { signed }, size }, api::Value::Integer(value)) => {
                if signed {
                    match size {
                        1 => unsafe { *(data.as_mut_ptr() as *mut i8) = value as i8 },
                        2 => unsafe { *(data.as_mut_ptr() as *mut i16) = value as i16 },
                        4 => unsafe { *(data.as_mut_ptr() as *mut i32) = value as i32 },
                        8 => unsafe { *(data.as_mut_ptr() as *mut i64) = value as i64 },
                        _ => unreachable!(),
                    }
                } else {
                    match size {
                        1 => unsafe { *(data.as_mut_ptr() as *mut u8) = value as u8 },
                        2 => unsafe { *(data.as_mut_ptr() as *mut u16) = value as u16 },
                        4 => unsafe { *(data.as_mut_ptr() as *mut u32) = value as u32 },
                        8 => unsafe { *(data.as_mut_ptr() as *mut u64) = value as u64 },
                        _ => unreachable!(),
                    }
                }
            }

            (&Pointer { type_index }, api::Value::Integer(value)) => {
                offsets.insert(value_offset, value as usize);
                pointers.push_back((value as usize, type_index));
            }

            (&Array { type_index, count }, api::Value::Array(values)) => {
                if count != values.len() {
                    return Err(io::Error::from(io::ErrorKind::InvalidInput));
                }

                let element_type = symbols.type_from_index(module, type_index)?;
                let size = element_type.size(symbols, module);

                for (offset, value) in values.into_iter().enumerate().map(|(i, v)| (i * size, v)) {
                    let data_type = element_type.clone();
                    let data = &mut data[offset..offset + size];

                    let offset = value_offset + offset;
                    let value = value
                        .into_value(data_type, module, symbols, offset, offsets, pointers)?;
                    data.copy_from_slice(&value.data);
                }
            }

            (&Struct { ref fields, .. }, api::Value::Struct(ref mut values)) => {
                for &debug::Field { type_index, offset, .. } in fields {
                    let value = match values.remove(&offset) {
                        Some(value) => value,
                        _ => return Err(io::Error::from(io::ErrorKind::InvalidInput)),
                    };

                    let data_type = symbols.type_from_index(module, type_index)?;

                    let offset = offset as usize;
                    let size = data_type.size(symbols, module);
                    let data = &mut data[offset..offset + size];

                    let offset = value_offset + offset;
                    let value = value
                        .into_value(data_type, module, symbols, offset, offsets, pointers)?;
                    data.copy_from_slice(&value.data);
                }
            }

            _ => return Err(io::Error::from(io::ErrorKind::InvalidInput)),
        }

        Ok(debug::Value { data, data_type, module })
    }
}
<|endoftext|>


<commit_before>use serialize::{Encodable, Encoder, Decodable, Decoder};

use std::hash;
use std::iter::FromIterator;
use std::ops::{
    Index,
    IndexMut,
};

use super::{Array, Dimension, Ix};

impl<'a, A, D: Dimension> Index<D> for Array<A, D>
{
    type Output = A;
    #[inline]
    /// Access the element at **index**.
    ///
    /// **Panics** if index is out of bounds.
    fn index(&self, index: &D) -> &A {
        self.at(index.clone()).expect("Array::index: out of bounds")
    }
}

impl<'a, A: Clone, D: Dimension> IndexMut<D> for Array<A, D>
{
    type Output = A;
    #[inline]
    /// Access the element at **index** mutably.
    ///
    /// **Panics** if index is out of bounds.
    fn index_mut(&mut self, index: &D) -> &mut A {
        self.at_mut(index.clone()).expect("Array::index_mut: out of bounds")
    }
}

impl<A: PartialEq, D: Dimension>
PartialEq for Array<A, D>
{
    /// Return `true` if the array shapes and all elements of `self` and
    /// `other` are equal. Return `false` otherwise.
    fn eq(&self, other: &Array<A, D>) -> bool
    {
        self.shape() == other.shape() &&
        self.iter().zip(other.iter()).all(|(a, b)| a == b)
    }
}

impl<A: Eq, D: Dimension>
Eq for Array<A, D> {}

impl<A> FromIterator<A> for Array<A, Ix>
{
    fn from_iter<I: Iterator<Item=A>>(it: I) -> Array<A, Ix>
    {
        Array::from_iter(it)
    }
}

impl<S: hash::Writer + hash::Hasher, A: hash::Hash<S>, D: Dimension>
hash::Hash<S> for Array<A, D>
{
    fn hash(&self, state: &mut S)
    {
        self.shape().hash(state);
        for elt in self.iter() {
            elt.hash(state)
        }
    }
}

// Use version number so we can add a packed format later.
static ARRAY_FORMAT_VERSION: u8 = 1u8;

impl<A: Encodable, D: Dimension + Encodable> Encodable for Array<A, D>
{
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error>
    {
        s.emit_struct("Array", 3, |e| {
            try!(e.emit_struct_field("v", 0, |e| {
                ARRAY_FORMAT_VERSION.encode(e)
            }));
            // FIXME: Write self.dim as a slice (self.shape)
            // The problem is decoding it.
            try!(e.emit_struct_field("dim", 1,
                                           |e| self.dim.encode(e)));
            try!(e.emit_struct_field("data", 2, |e| {
                let sz = self.dim.size();
                e.emit_seq(sz, |e| {
                    for (i, elt) in self.iter().enumerate() {
                        try!(e.emit_seq_elt(i, |e| {
                            elt.encode(e)
                        }))
                    }
                    Ok(())
                })
            }));
            Ok(())
        })
    }
}

impl<A: Decodable, D: Dimension + Decodable>
    Decodable for Array<A, D>
{
    fn decode<S: Decoder>(d: &mut S) -> Result<Array<A, D>, S::Error>
    {
        d.read_struct("Array", 3, |d| {
            let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode));
            if version > ARRAY_FORMAT_VERSION {
                return Err(d.error("unknown array version"))
            }
            let dim: D = try!(d.read_struct_field("dim", 1, |d| {
                Decodable::decode(d)
            }));
            let elements = try!(
                d.read_struct_field("data", 2, |d| {
                    d.read_seq(|d, len| {
                        if len != dim.size() {
                            Err(d.error("data and dimension must match in size"))
                        } else {
                            let mut elements = Vec::with_capacity(len);
                            for i in (0..len) {
                                elements.push(try!(d.read_seq_elt::<A, _>(i, Decodable::decode)))
                            }
                            Ok(elements)
                        }
                    })
            }));
            unsafe {
                Ok(Array::from_vec_dim(dim, elements))
            }
        })
    }
}
<commit_msg>Fix for IndexMut change<commit_after>use serialize::{Encodable, Encoder, Decodable, Decoder};

use std::hash;
use std::iter::FromIterator;
use std::ops::{
    Index,
    IndexMut,
};

use super::{Array, Dimension, Ix};

impl<'a, A, D: Dimension> Index<D> for Array<A, D>
{
    type Output = A;
    #[inline]
    /// Access the element at **index**.
    ///
    /// **Panics** if index is out of bounds.
    fn index(&self, index: &D) -> &A {
        self.at(index.clone()).expect("Array::index: out of bounds")
    }
}

impl<'a, A: Clone, D: Dimension> IndexMut<D> for Array<A, D>
{
    #[inline]
    /// Access the element at **index** mutably.
    ///
    /// **Panics** if index is out of bounds.
    fn index_mut(&mut self, index: &D) -> &mut A {
        self.at_mut(index.clone()).expect("Array::index_mut: out of bounds")
    }
}

impl<A: PartialEq, D: Dimension>
PartialEq for Array<A, D>
{
    /// Return `true` if the array shapes and all elements of `self` and
    /// `other` are equal. Return `false` otherwise.
    fn eq(&self, other: &Array<A, D>) -> bool
    {
        self.shape() == other.shape() &&
        self.iter().zip(other.iter()).all(|(a, b)| a == b)
    }
}

impl<A: Eq, D: Dimension>
Eq for Array<A, D> {}

impl<A> FromIterator<A> for Array<A, Ix>
{
    fn from_iter<I: Iterator<Item=A>>(it: I) -> Array<A, Ix>
    {
        Array::from_iter(it)
    }
}

impl<S: hash::Writer + hash::Hasher, A: hash::Hash<S>, D: Dimension>
hash::Hash<S> for Array<A, D>
{
    fn hash(&self, state: &mut S)
    {
        self.shape().hash(state);
        for elt in self.iter() {
            elt.hash(state)
        }
    }
}

// Use version number so we can add a packed format later.
static ARRAY_FORMAT_VERSION: u8 = 1u8;

impl<A: Encodable, D: Dimension + Encodable> Encodable for Array<A, D>
{
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error>
    {
        s.emit_struct("Array", 3, |e| {
            try!(e.emit_struct_field("v", 0, |e| {
                ARRAY_FORMAT_VERSION.encode(e)
            }));
            // FIXME: Write self.dim as a slice (self.shape)
            // The problem is decoding it.
            try!(e.emit_struct_field("dim", 1,
                                           |e| self.dim.encode(e)));
            try!(e.emit_struct_field("data", 2, |e| {
                let sz = self.dim.size();
                e.emit_seq(sz, |e| {
                    for (i, elt) in self.iter().enumerate() {
                        try!(e.emit_seq_elt(i, |e| {
                            elt.encode(e)
                        }))
                    }
                    Ok(())
                })
            }));
            Ok(())
        })
    }
}

impl<A: Decodable, D: Dimension + Decodable>
    Decodable for Array<A, D>
{
    fn decode<S: Decoder>(d: &mut S) -> Result<Array<A, D>, S::Error>
    {
        d.read_struct("Array", 3, |d| {
            let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode));
            if version > ARRAY_FORMAT_VERSION {
                return Err(d.error("unknown array version"))
            }
            let dim: D = try!(d.read_struct_field("dim", 1, |d| {
                Decodable::decode(d)
            }));
            let elements = try!(
                d.read_struct_field("data", 2, |d| {
                    d.read_seq(|d, len| {
                        if len != dim.size() {
                            Err(d.error("data and dimension must match in size"))
                        } else {
                            let mut elements = Vec::with_capacity(len);
                            for i in (0..len) {
                                elements.push(try!(d.read_seq_elt::<A, _>(i, Decodable::decode)))
                            }
                            Ok(elements)
                        }
                    })
            }));
            unsafe {
                Ok(Array::from_vec_dim(dim, elements))
            }
        })
    }
}
<|endoftext|>