<commit_before>use color::{Color888, Colorf32};
use fastup::{self, Node, parse_for_first_node, parse_color};
use sysinfo::System;
use super::error_node;
use std::time::Duration;
use std::thread::sleep;

#[derive(Debug, Copy, Clone, Default)]
pub struct Widget;

impl super::Widget for Widget {
    fn expand(&self, args: Vec<String>) -> Node {
        match args.len() {
            2 => node_from_args(args),
            _ => error_node("(ccdd44: cpu) takes 2 arguments: color-cold\\|color-hot"),
        }
    }
}

fn node_from_args(args: Vec<String>) -> Node {
    try_node_from_args(args).unwrap_or_else(|e| error_node(&e))
}

fn try_node_from_args(args: Vec<String>) -> Result<Node, String> {
    assert_eq!(args.len(), 2);

    let cold = parse_color(&args[0]).map_err(escape_fastup)?;
    let hot = parse_color(&args[1]).map_err(escape_fastup)?;

    Ok(cpu_node(cold.into(), hot.into()))
}

fn cpu_node(cold: Colorf32, hot: Colorf32) -> Node {
    const BG_LIGHTNESS: f32 = 0.15;
    const FG_LIGHTNESS: f32 = 0.7;
    const IDLE_LIGHTNESS: f32 = 0.3;
    const IDLE_THRESHOLD: f32 = 0.05;
    const PROGRESS_INDICATOR: &'static str = "▁▂▃▄▅▆▇";

    let (cpu_total, cpu_usages) = cpu_usages();

    let bg_cold = cold.set_lightness(BG_LIGHTNESS);
    let bg_hot = hot.set_lightness(BG_LIGHTNESS);
    let bg = bg_cold.mix(bg_hot, cpu_total).clamp_to_888();

    let idle_cold = cold.set_lightness(IDLE_LIGHTNESS);
    let idle_hot = hot.set_lightness(IDLE_LIGHTNESS);
    let idle = idle_cold.mix(idle_hot, cpu_total).clamp_to_888();

    let fg_cold = cold.set_lightness(FG_LIGHTNESS);
    let fg_hot = hot.set_lightness(FG_LIGHTNESS);
    let make_fg_color = |usage: f32| {
        if usage <= IDLE_THRESHOLD {
            idle
        } else {
            let usage = (usage - IDLE_THRESHOLD) / (1.0 - IDLE_THRESHOLD);
            fg_cold.mix(fg_hot, usage).clamp_to_888()
        }
    };
    let make_cpu_indicator = |usage: f32| {
        let len = PROGRESS_INDICATOR.chars().count() as f32;
        let i = (len * usage).min(len - 1.0).max(0.0) as usize;
        PROGRESS_INDICATOR.chars().nth(i).unwrap()
    };

    let cpu_usages = cpu_usages.into_iter()
        .map(|usage| format!("({}:{})", make_fg_color(usage), make_cpu_indicator(usage)))
        .collect::<String>();
    let total_usage = {
        let color = make_fg_color(cpu_total);
        let percent = (100.0 * cpu_total) as i32;
        let percent = format!("{:>3}%", percent);
        let percent = escape_fastup(percent);
        format!("({}:{})", color, percent)
    };

    let node = format!("[{}: \\ {}{} ]", bg, cpu_usages, total_usage);
    parse_for_first_node(&node).unwrap()
}

/// return (total, [usage])
fn cpu_usages() -> (f32, Vec<f32>) {
    let mut sys = System::new();
    // FIXME: Dirty hack by sleeping.
    // System refreshing should be done globally.
    sleep(Duration::from_millis(100));
    sys.refresh_system();
    let p = sys.get_processor_list();
    let total = p[0].get_cpu_usage();
    let usages = p.iter()
        .skip(1)
        .map(|x| x.get_cpu_usage())
        .collect::<Vec<_>>();
    (total, usages)
}

fn escape_fastup<T>(input: T) -> String
    where T: ToString
{
    fastup::escape_for_text(&input.to_string())
}

<commit_msg>widget: cpu: @ normalize floats to prevent NaN, Inf, etc.<commit_after>use color::{Color888, Colorf32};
use fastup::{self, Node, parse_for_first_node, parse_color};
use sysinfo::System;
use super::error_node;
use std::time::Duration;
use std::thread::sleep;

#[derive(Debug, Copy, Clone, Default)]
pub struct Widget;

impl super::Widget for Widget {
    fn expand(&self, args: Vec<String>) -> Node {
        match args.len() {
            2 => node_from_args(args),
            _ => error_node("(ccdd44: cpu) takes 2 arguments: color-cold\\|color-hot"),
        }
    }
}

fn node_from_args(args: Vec<String>) -> Node {
    try_node_from_args(args).unwrap_or_else(|e| error_node(&e))
}

fn try_node_from_args(args: Vec<String>) -> Result<Node, String> {
    assert_eq!(args.len(), 2);

    let cold = parse_color(&args[0]).map_err(escape_fastup)?;
    let hot = parse_color(&args[1]).map_err(escape_fastup)?;

    Ok(cpu_node(cold.into(), hot.into()))
}

fn cpu_node(cold: Colorf32, hot: Colorf32) -> Node {
    const BG_LIGHTNESS: f32 = 0.15;
    const FG_LIGHTNESS: f32 = 0.7;
    const IDLE_LIGHTNESS: f32 = 0.3;
    const IDLE_THRESHOLD: f32 = 0.05;
    const PROGRESS_INDICATOR: &'static str = "▁▂▃▄▅▆▇";

    let (cpu_total, cpu_usages) = cpu_usages();

    let bg_cold = cold.set_lightness(BG_LIGHTNESS);
    let bg_hot = hot.set_lightness(BG_LIGHTNESS);
    let bg = bg_cold.mix(bg_hot, cpu_total).clamp_to_888();

    let idle_cold = cold.set_lightness(IDLE_LIGHTNESS);
    let idle_hot = hot.set_lightness(IDLE_LIGHTNESS);
    let idle = idle_cold.mix(idle_hot, cpu_total).clamp_to_888();

    let fg_cold = cold.set_lightness(FG_LIGHTNESS);
    let fg_hot = hot.set_lightness(FG_LIGHTNESS);
    let make_fg_color = |usage: f32| {
        if usage <= IDLE_THRESHOLD {
            idle
        } else {
            let usage = (usage - IDLE_THRESHOLD) / (1.0 - IDLE_THRESHOLD);
            fg_cold.mix(fg_hot, usage).clamp_to_888()
        }
    };
    let make_cpu_indicator = |usage: f32| {
        let len = PROGRESS_INDICATOR.chars().count() as f32;
        let i = (len * usage).min(len - 1.0).max(0.0) as usize;
        PROGRESS_INDICATOR.chars().nth(i).unwrap()
    };

    let cpu_usages = cpu_usages.into_iter()
        .map(|usage| format!("({}:{})", make_fg_color(usage), make_cpu_indicator(usage)))
        .collect::<String>();
    let total_usage = {
        let color = make_fg_color(cpu_total);
        let percent = (100.0 * cpu_total) as i32;
        let percent = format!("{:>3}%", percent);
        let percent = escape_fastup(percent);
        format!("({}:{})", color, percent)
    };

    let node = format!("[{}: \\ {}{} ]", bg, cpu_usages, total_usage);
    parse_for_first_node(&node).unwrap()
}

/// Returns `(total, vec![usage, ...])`.
///
/// Any float `x` in the return value are guranteed
/// that `0.0 <= x <= 1.0` holds true.
fn cpu_usages() -> (f32, Vec<f32>) {
    let mut sys = System::new();
    // FIXME: Dirty hack by sleeping.
    // System refreshing should be done globally.
    sleep(Duration::from_millis(100));
    sys.refresh_system();
    let p = sys.get_processor_list();
    let total = p[0].get_cpu_usage();
    let total = normalize_float(total);
    let usages = p.iter()
        .skip(1)
        .map(|x| x.get_cpu_usage())
        .map(normalize_float)
        .collect::<Vec<_>>();
    (total, usages)
}

fn escape_fastup<T>(input: T) -> String
    where T: ToString
{
    fastup::escape_for_text(&input.to_string())
}

fn normalize_float(x: f32) -> f32 {
    match x {
        x if x < 0.0 => 0.0,
        x if x > 1.0 => 1.0,
        x if x.is_nan() => 0.0,
        _ => x,
    }
}

<|endoftext|>


<commit_before>use std::{
    io,
    ops::{Deref, DerefMut},
    pin::Pin,
    task::{Context, Poll},
    time,
};

use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
use actix_rt::task::JoinHandle;
use bytes::Bytes;
use futures_core::future::LocalBoxFuture;
use h2::client::SendRequest;

use crate::body::MessageBody;
use crate::h1::ClientCodec;
use crate::message::{RequestHeadType, ResponseHead};
use crate::payload::Payload;

use super::error::SendRequestError;
use super::pool::Acquired;
use super::{h1proto, h2proto};

/// Trait alias for types impl [tokio::io::AsyncRead] and [tokio::io::AsyncWrite].
pub trait ConnectionIo: AsyncRead + AsyncWrite + Unpin + 'static {}

impl<T: AsyncRead + AsyncWrite + Unpin + 'static> ConnectionIo for T {}

/// HTTP client connection
pub struct H1Connection<Io: ConnectionIo> {
    io: Option<Io>,
    created: time::Instant,
    acquired: Acquired<Io>,
}

impl<Io: ConnectionIo> H1Connection<Io> {
    /// close or release the connection to pool based on flag input
    pub(super) fn on_release(&mut self, keep_alive: bool) {
        if keep_alive {
            self.release();
        } else {
            self.close();
        }
    }

    /// Close connection
    fn close(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired.close(ConnectionInnerType::H1(io));
    }

    /// Release this connection to the connection pool
    fn release(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired
            .release(ConnectionInnerType::H1(io), self.created);
    }

    fn io_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Io> {
        Pin::new(self.get_mut().io.as_mut().unwrap())
    }
}

impl<Io: ConnectionIo> AsyncRead for H1Connection<Io> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        self.io_pin_mut().poll_read(cx, buf)
    }
}

impl<Io: ConnectionIo> AsyncWrite for H1Connection<Io> {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.io_pin_mut().poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.io_pin_mut().poll_flush(cx)
    }

    fn poll_shutdown(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), io::Error>> {
        self.io_pin_mut().poll_shutdown(cx)
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        bufs: &[io::IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        self.io_pin_mut().poll_write_vectored(cx, bufs)
    }

    fn is_write_vectored(&self) -> bool {
        self.io.as_ref().unwrap().is_write_vectored()
    }
}

/// HTTP2 client connection
pub struct H2Connection<Io: ConnectionIo> {
    io: Option<H2ConnectionInner>,
    created: time::Instant,
    acquired: Acquired<Io>,
}

impl<Io: ConnectionIo> Deref for H2Connection<Io> {
    type Target = SendRequest<Bytes>;

    fn deref(&self) -> &Self::Target {
        &self.io.as_ref().unwrap().sender
    }
}

impl<Io: ConnectionIo> DerefMut for H2Connection<Io> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.io.as_mut().unwrap().sender
    }
}

impl<Io: ConnectionIo> H2Connection<Io> {
    /// close or release the connection to pool based on flag input
    pub(super) fn on_release(&mut self, close: bool) {
        if close {
            self.close();
        } else {
            self.release();
        }
    }

    /// Close connection
    fn close(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired.close(ConnectionInnerType::H2(io));
    }

    /// Release this connection to the connection pool
    fn release(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired
            .release(ConnectionInnerType::H2(io), self.created);
    }
}

/// `H2ConnectionInner` has two parts: `SendRequest` and `Connection`.
///
/// `Connection` is spawned as an async task on runtime and `H2ConnectionInner` holds a handle
/// for this task. Therefore, it can wake up and quit the task when SendRequest is dropped.
pub(super) struct H2ConnectionInner {
    handle: JoinHandle<()>,
    sender: SendRequest<Bytes>,
}

impl H2ConnectionInner {
    pub(super) fn new<Io: ConnectionIo>(
        sender: SendRequest<Bytes>,
        connection: h2::client::Connection<Io>,
    ) -> Self {
        let handle = actix_rt::spawn(async move {
            let _ = connection.await;
        });

        Self { handle, sender }
    }
}

/// Cancel spawned connection task on drop.
impl Drop for H2ConnectionInner {
    fn drop(&mut self) {
        self.handle.abort();
    }
}

#[allow(dead_code)]
/// Unified connection type cover Http1 Plain/Tls and Http2 protocols
pub enum Connection<A, B = Box<dyn ConnectionIo>>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    Tcp(ConnectionType<A>),
    Tls(ConnectionType<B>),
}

/// Unified connection type cover Http1/2 protocols
pub enum ConnectionType<Io: ConnectionIo> {
    H1(H1Connection<Io>),
    H2(H2Connection<Io>),
}

/// Helper type for storing connection types in pool.
pub(super) enum ConnectionInnerType<Io> {
    H1(Io),
    H2(H2ConnectionInner),
}

impl<Io: ConnectionIo> ConnectionType<Io> {
    pub(super) fn from_pool(
        inner: ConnectionInnerType<Io>,
        created: time::Instant,
        acquired: Acquired<Io>,
    ) -> Self {
        match inner {
            ConnectionInnerType::H1(io) => Self::from_h1(io, created, acquired),
            ConnectionInnerType::H2(io) => Self::from_h2(io, created, acquired),
        }
    }

    pub(super) fn from_h1(
        io: Io,
        created: time::Instant,
        acquired: Acquired<Io>,
    ) -> Self {
        Self::H1(H1Connection {
            io: Some(io),
            created,
            acquired,
        })
    }

    pub(super) fn from_h2(
        io: H2ConnectionInner,
        created: time::Instant,
        acquired: Acquired<Io>,
    ) -> Self {
        Self::H2(H2Connection {
            io: Some(io),
            created,
            acquired,
        })
    }
}

impl<A, B> Connection<A, B>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    /// Send a request through connection.
    pub fn send_request<RB, H>(
        self,
        head: H,
        body: RB,
    ) -> LocalBoxFuture<'static, Result<(ResponseHead, Payload), SendRequestError>>
    where
        RB: MessageBody + 'static,
        H: Into<RequestHeadType> + 'static,
    {
        Box::pin(async move {
            match self {
                Connection::Tcp(ConnectionType::H1(conn)) => {
                    h1proto::send_request(conn, head.into(), body).await
                }
                Connection::Tls(ConnectionType::H1(conn)) => {
                    h1proto::send_request(conn, head.into(), body).await
                }
                Connection::Tls(ConnectionType::H2(conn)) => {
                    h2proto::send_request(conn, head.into(), body).await
                }
                _ => unreachable!(
                    "Plain Tcp connection can be used only in Http1 protocol"
                ),
            }
        })
    }

    /// Send request, returns Response and Framed tunnel.
    pub fn open_tunnel<H: Into<RequestHeadType> + 'static>(
        self,
        head: H,
    ) -> LocalBoxFuture<
        'static,
        Result<(ResponseHead, Framed<Connection<A, B>, ClientCodec>), SendRequestError>,
    > {
        Box::pin(async move {
            match self {
                Connection::Tcp(ConnectionType::H1(ref _conn)) => {
                    let (head, framed) = h1proto::open_tunnel(self, head.into()).await?;
                    Ok((head, framed))
                }
                Connection::Tls(ConnectionType::H1(ref _conn)) => {
                    let (head, framed) = h1proto::open_tunnel(self, head.into()).await?;
                    Ok((head, framed))
                }
                Connection::Tls(ConnectionType::H2(mut conn)) => {
                    conn.release();
                    Err(SendRequestError::TunnelNotSupported)
                }
                Connection::Tcp(ConnectionType::H2(_)) => {
                    unreachable!(
                        "Plain Tcp connection can be used only in Http1 protocol"
                    )
                }
            }
        })
    }
}

impl<A, B> AsyncRead for Connection<A, B>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_read(cx, buf)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_read(cx, buf)
            }
            _ => unreachable!("H2Connection can not impl AsyncRead trait"),
        }
    }
}

const H2_UNREACHABLE_WRITE: &str = "H2Connection can not impl AsyncWrite trait";

impl<A, B> AsyncWrite for Connection<A, B>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write(cx, buf)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write(cx, buf)
            }
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => Pin::new(conn).poll_flush(cx),
            Connection::Tls(ConnectionType::H1(conn)) => Pin::new(conn).poll_flush(cx),
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn poll_shutdown(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<io::Result<()>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_shutdown(cx)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_shutdown(cx)
            }
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        bufs: &[io::IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write_vectored(cx, bufs)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write_vectored(cx, bufs)
            }
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn is_write_vectored(&self) -> bool {
        match *self {
            Connection::Tcp(ConnectionType::H1(ref conn)) => conn.is_write_vectored(),
            Connection::Tls(ConnectionType::H1(ref conn)) => conn.is_write_vectored(),
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }
}

#[cfg(test)]
mod test {
    use std::net;

    use actix_rt::net::TcpStream;

    use super::*;

    #[actix_rt::test]
    async fn test_h2_connection_drop() {
        let addr = "127.0.0.1:0".parse::<net::SocketAddr>().unwrap();
        let listener = net::TcpListener::bind(addr).unwrap();
        let local = listener.local_addr().unwrap();

        std::thread::spawn(move || while listener.accept().is_ok() {});

        let tcp = TcpStream::connect(local).await.unwrap();
        let (sender, connection) = h2::client::handshake(tcp).await.unwrap();
        let conn = H2ConnectionInner::new(sender.clone(), connection);

        assert!(sender.clone().ready().await.is_ok());
        assert!(h2::client::SendRequest::clone(&conn.sender)
            .ready()
            .await
            .is_ok());

        drop(conn);

        match sender.ready().await {
            Ok(_) => panic!("connection should be gone and can not be ready"),
            Err(e) => assert!(e.is_io()),
        };
    }
}
<commit_msg>fix broken pipe for h2 when client is instantly dropped (#2113)<commit_after>use std::{
    io,
    ops::{Deref, DerefMut},
    pin::Pin,
    task::{Context, Poll},
    time,
};

use actix_codec::{AsyncRead, AsyncWrite, Framed, ReadBuf};
use actix_rt::task::JoinHandle;
use bytes::Bytes;
use futures_core::future::LocalBoxFuture;
use h2::client::SendRequest;

use crate::body::MessageBody;
use crate::h1::ClientCodec;
use crate::message::{RequestHeadType, ResponseHead};
use crate::payload::Payload;

use super::error::SendRequestError;
use super::pool::Acquired;
use super::{h1proto, h2proto};

/// Trait alias for types impl [tokio::io::AsyncRead] and [tokio::io::AsyncWrite].
pub trait ConnectionIo: AsyncRead + AsyncWrite + Unpin + 'static {}

impl<T: AsyncRead + AsyncWrite + Unpin + 'static> ConnectionIo for T {}

/// HTTP client connection
pub struct H1Connection<Io: ConnectionIo> {
    io: Option<Io>,
    created: time::Instant,
    acquired: Acquired<Io>,
}

impl<Io: ConnectionIo> H1Connection<Io> {
    /// close or release the connection to pool based on flag input
    pub(super) fn on_release(&mut self, keep_alive: bool) {
        if keep_alive {
            self.release();
        } else {
            self.close();
        }
    }

    /// Close connection
    fn close(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired.close(ConnectionInnerType::H1(io));
    }

    /// Release this connection to the connection pool
    fn release(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired
            .release(ConnectionInnerType::H1(io), self.created);
    }

    fn io_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Io> {
        Pin::new(self.get_mut().io.as_mut().unwrap())
    }
}

impl<Io: ConnectionIo> AsyncRead for H1Connection<Io> {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        self.io_pin_mut().poll_read(cx, buf)
    }
}

impl<Io: ConnectionIo> AsyncWrite for H1Connection<Io> {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.io_pin_mut().poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.io_pin_mut().poll_flush(cx)
    }

    fn poll_shutdown(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), io::Error>> {
        self.io_pin_mut().poll_shutdown(cx)
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        bufs: &[io::IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        self.io_pin_mut().poll_write_vectored(cx, bufs)
    }

    fn is_write_vectored(&self) -> bool {
        self.io.as_ref().unwrap().is_write_vectored()
    }
}

/// HTTP2 client connection
pub struct H2Connection<Io: ConnectionIo> {
    io: Option<H2ConnectionInner>,
    created: time::Instant,
    acquired: Acquired<Io>,
}

impl<Io: ConnectionIo> Deref for H2Connection<Io> {
    type Target = SendRequest<Bytes>;

    fn deref(&self) -> &Self::Target {
        &self.io.as_ref().unwrap().sender
    }
}

impl<Io: ConnectionIo> DerefMut for H2Connection<Io> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.io.as_mut().unwrap().sender
    }
}

impl<Io: ConnectionIo> H2Connection<Io> {
    /// close or release the connection to pool based on flag input
    pub(super) fn on_release(&mut self, close: bool) {
        if close {
            self.close();
        } else {
            self.release();
        }
    }

    /// Close connection
    fn close(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired.close(ConnectionInnerType::H2(io));
    }

    /// Release this connection to the connection pool
    fn release(&mut self) {
        let io = self.io.take().unwrap();
        self.acquired
            .release(ConnectionInnerType::H2(io), self.created);
    }
}

/// `H2ConnectionInner` has two parts: `SendRequest` and `Connection`.
///
/// `Connection` is spawned as an async task on runtime and `H2ConnectionInner` holds a handle
/// for this task. Therefore, it can wake up and quit the task when SendRequest is dropped.
pub(super) struct H2ConnectionInner {
    handle: JoinHandle<()>,
    sender: SendRequest<Bytes>,
}

impl H2ConnectionInner {
    pub(super) fn new<Io: ConnectionIo>(
        sender: SendRequest<Bytes>,
        connection: h2::client::Connection<Io>,
    ) -> Self {
        let handle = actix_rt::spawn(async move {
            let _ = connection.await;
        });

        Self { handle, sender }
    }
}

/// Cancel spawned connection task on drop.
impl Drop for H2ConnectionInner {
    fn drop(&mut self) {
        if self
            .sender
            .send_request(http::Request::new(()), true)
            .is_err()
        {
            self.handle.abort();
        }
    }
}

#[allow(dead_code)]
/// Unified connection type cover Http1 Plain/Tls and Http2 protocols
pub enum Connection<A, B = Box<dyn ConnectionIo>>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    Tcp(ConnectionType<A>),
    Tls(ConnectionType<B>),
}

/// Unified connection type cover Http1/2 protocols
pub enum ConnectionType<Io: ConnectionIo> {
    H1(H1Connection<Io>),
    H2(H2Connection<Io>),
}

/// Helper type for storing connection types in pool.
pub(super) enum ConnectionInnerType<Io> {
    H1(Io),
    H2(H2ConnectionInner),
}

impl<Io: ConnectionIo> ConnectionType<Io> {
    pub(super) fn from_pool(
        inner: ConnectionInnerType<Io>,
        created: time::Instant,
        acquired: Acquired<Io>,
    ) -> Self {
        match inner {
            ConnectionInnerType::H1(io) => Self::from_h1(io, created, acquired),
            ConnectionInnerType::H2(io) => Self::from_h2(io, created, acquired),
        }
    }

    pub(super) fn from_h1(
        io: Io,
        created: time::Instant,
        acquired: Acquired<Io>,
    ) -> Self {
        Self::H1(H1Connection {
            io: Some(io),
            created,
            acquired,
        })
    }

    pub(super) fn from_h2(
        io: H2ConnectionInner,
        created: time::Instant,
        acquired: Acquired<Io>,
    ) -> Self {
        Self::H2(H2Connection {
            io: Some(io),
            created,
            acquired,
        })
    }
}

impl<A, B> Connection<A, B>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    /// Send a request through connection.
    pub fn send_request<RB, H>(
        self,
        head: H,
        body: RB,
    ) -> LocalBoxFuture<'static, Result<(ResponseHead, Payload), SendRequestError>>
    where
        RB: MessageBody + 'static,
        H: Into<RequestHeadType> + 'static,
    {
        Box::pin(async move {
            match self {
                Connection::Tcp(ConnectionType::H1(conn)) => {
                    h1proto::send_request(conn, head.into(), body).await
                }
                Connection::Tls(ConnectionType::H1(conn)) => {
                    h1proto::send_request(conn, head.into(), body).await
                }
                Connection::Tls(ConnectionType::H2(conn)) => {
                    h2proto::send_request(conn, head.into(), body).await
                }
                _ => unreachable!(
                    "Plain Tcp connection can be used only in Http1 protocol"
                ),
            }
        })
    }

    /// Send request, returns Response and Framed tunnel.
    pub fn open_tunnel<H: Into<RequestHeadType> + 'static>(
        self,
        head: H,
    ) -> LocalBoxFuture<
        'static,
        Result<(ResponseHead, Framed<Connection<A, B>, ClientCodec>), SendRequestError>,
    > {
        Box::pin(async move {
            match self {
                Connection::Tcp(ConnectionType::H1(ref _conn)) => {
                    let (head, framed) = h1proto::open_tunnel(self, head.into()).await?;
                    Ok((head, framed))
                }
                Connection::Tls(ConnectionType::H1(ref _conn)) => {
                    let (head, framed) = h1proto::open_tunnel(self, head.into()).await?;
                    Ok((head, framed))
                }
                Connection::Tls(ConnectionType::H2(mut conn)) => {
                    conn.release();
                    Err(SendRequestError::TunnelNotSupported)
                }
                Connection::Tcp(ConnectionType::H2(_)) => {
                    unreachable!(
                        "Plain Tcp connection can be used only in Http1 protocol"
                    )
                }
            }
        })
    }
}

impl<A, B> AsyncRead for Connection<A, B>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_read(cx, buf)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_read(cx, buf)
            }
            _ => unreachable!("H2Connection can not impl AsyncRead trait"),
        }
    }
}

const H2_UNREACHABLE_WRITE: &str = "H2Connection can not impl AsyncWrite trait";

impl<A, B> AsyncWrite for Connection<A, B>
where
    A: ConnectionIo,
    B: ConnectionIo,
{
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write(cx, buf)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write(cx, buf)
            }
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => Pin::new(conn).poll_flush(cx),
            Connection::Tls(ConnectionType::H1(conn)) => Pin::new(conn).poll_flush(cx),
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn poll_shutdown(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<io::Result<()>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_shutdown(cx)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_shutdown(cx)
            }
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn poll_write_vectored(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        bufs: &[io::IoSlice<'_>],
    ) -> Poll<io::Result<usize>> {
        match self.get_mut() {
            Connection::Tcp(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write_vectored(cx, bufs)
            }
            Connection::Tls(ConnectionType::H1(conn)) => {
                Pin::new(conn).poll_write_vectored(cx, bufs)
            }
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }

    fn is_write_vectored(&self) -> bool {
        match *self {
            Connection::Tcp(ConnectionType::H1(ref conn)) => conn.is_write_vectored(),
            Connection::Tls(ConnectionType::H1(ref conn)) => conn.is_write_vectored(),
            _ => unreachable!(H2_UNREACHABLE_WRITE),
        }
    }
}

#[cfg(test)]
mod test {
    use std::{
        future::Future,
        net,
        pin::Pin,
        task::{Context, Poll},
        time::{Duration, Instant},
    };

    use actix_rt::{
        net::TcpStream,
        time::{interval, Interval},
    };

    use super::*;

    #[actix_rt::test]
    async fn test_h2_connection_drop() {
        let addr = "127.0.0.1:0".parse::<net::SocketAddr>().unwrap();
        let listener = net::TcpListener::bind(addr).unwrap();
        let local = listener.local_addr().unwrap();

        std::thread::spawn(move || while listener.accept().is_ok() {});

        let tcp = TcpStream::connect(local).await.unwrap();
        let (sender, connection) = h2::client::handshake(tcp).await.unwrap();
        let conn = H2ConnectionInner::new(sender.clone(), connection);

        assert!(sender.clone().ready().await.is_ok());
        assert!(h2::client::SendRequest::clone(&conn.sender)
            .ready()
            .await
            .is_ok());

        drop(conn);

        struct DropCheck {
            sender: h2::client::SendRequest<Bytes>,
            interval: Interval,
            start_from: Instant,
        }

        impl Future for DropCheck {
            type Output = ();

            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
                let this = self.get_mut();
                match futures_core::ready!(this.sender.poll_ready(cx)) {
                    Ok(()) => {
                        if this.start_from.elapsed() > Duration::from_secs(10) {
                            panic!("connection should be gone and can not be ready");
                        } else {
                            let _ = this.interval.poll_tick(cx);
                            Poll::Pending
                        }
                    }
                    Err(_) => Poll::Ready(()),
                }
            }
        }

        DropCheck {
            sender,
            interval: interval(Duration::from_millis(100)),
            start_from: Instant::now(),
        }
        .await;
    }
}
<|endoftext|>


<commit_before>#![crate_id = "js.rs"]
#![comment = "Javascript parsing and execution command line tool"]
#![license = "MIT"]
#![crate_type = "bin"]
#![doc(
	html_favicon_url = "http://tombebbington.github.io/favicon.png",
	html_root_url = "http://tombebbington.github.io/js.rs/"
)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, non_camel_case_types, unused_must_use)]
#![feature(phase)]
//! A Javascript execution command line tool

extern crate js;
extern crate syntax = "js_syntax";
extern crate getopts;
extern crate collections;
#[phase(plugin, link)]
extern crate log;
/// Interactive mode
pub mod interactive;
/// Unit test mode
pub mod tests;
/// Script runner mode
pub mod runner;
/// The main function
pub fn main() {
	let opts = [
		getopts::optflag("h", "help", "Show this message"),
		getopts::optflag("t", "tests", "Run tests"),
		getopts::optflag("i", "interactive", "Run in interactive mode"),
		getopts::optopt("s", "source-code", "Run some Javascript code", "The path to the source code")
	];
	let m = getopts::getopts(std::os::args().as_slice(), opts).unwrap();
	match m.opt_str("s") {
		Some(path) => {
			runner::Runner::new(m).run(path)
		},
		None if m.opt_present("h") => {
			println!("{}", getopts::usage("Usage: js.rs [OPTIONS] [INPUT]", opts));
		},
		None if m.opt_present("t") || (m.free.len() >= 2 && m.free.get(1).as_slice() == "test") => {
			tests::Tests::new(m).run();
		},
		None if m.opt_present("i") || (m.free.len() >= 2 && m.free.get(1).as_slice() == "interactive") => {
			interactive::Interactive::new(m).run();
		},
		None if m.free.len() >= 2 => {
			runner::Runner::new(m.clone()).run(m.free.get(1).clone());
		},
		None => {
			println!("{}", getopts::short_usage("Usage: js.rs [OPTIONS] [INPUT]", opts));
		}
	}
}<commit_msg>Make command-line modes exported by frontend<commit_after>#![crate_id = "js.rs"]
#![comment = "Javascript parsing and execution command line tool"]
#![license = "MIT"]
#![crate_type = "bin"]
#![doc(
	html_favicon_url = "http://tombebbington.github.io/favicon.png",
	html_root_url = "http://tombebbington.github.io/js.rs/"
)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, non_camel_case_types, unused_must_use)]
#![feature(phase)]
//! A Javascript execution command line tool

extern crate js;
extern crate syntax = "js_syntax";
extern crate getopts;
extern crate collections;
#[phase(plugin, link)]
extern crate log;
/// Interactive mode
pub use interactive::Interactive;
/// Unit test mode
pub use tests::Tests;
/// Script runner mode
pub use runner::Runner;
mod interactive;
mod tests;
mod runner;
/// The main function
pub fn main() {
	let opts = [
		getopts::optflag("h", "help", "Show this message"),
		getopts::optflag("t", "tests", "Run tests"),
		getopts::optflag("i", "interactive", "Run in interactive mode"),
		getopts::optopt("s", "source-code", "Run some Javascript code", "The path to the source code")
	];
	let m = getopts::getopts(std::os::args().as_slice(), opts).unwrap();
	match m.opt_str("s") {
		Some(path) => {
			Runner::new(m).run(path)
		},
		None if m.opt_present("h") => {
			println!("{}", getopts::usage("Usage: js.rs [OPTIONS] [INPUT]", opts));
		},
		None if m.opt_present("t") || (m.free.len() >= 2 && m.free.get(1).as_slice() == "test") => {
			Tests::new(m).run();
		},
		None if m.opt_present("i") || (m.free.len() >= 2 && m.free.get(1).as_slice() == "interactive") => {
			Interactive::new(m).run();
		},
		None if m.free.len() >= 2 => {
			Runner::new(m.clone()).run(m.free.get(1).clone());
		},
		None => {
			println!("{}", getopts::short_usage("Usage: js.rs [OPTIONS] [INPUT]", opts));
		}
	}
}<|endoftext|>


<commit_before>
use rand;

use graphics::*;
use piston::*;

use aabb::AABB;
use settings;
use player::Player;

pub struct Ball {
    pos: [f64, ..2],
    v: [f64, ..2],

    aabb: AABB,

    image: Image,
}

impl Ball {
    pub fn new(image: Image) -> Ball {
        Ball {
            pos: [0.0, 0.0],
            v: [0.0, 0.0],

            aabb: AABB::new(0.0, 0.0, image.texture_width as f64, image.texture_height as f64),

            image: image,
        }
    }

    pub fn aabb(&self) -> AABB {
        self.aabb.trans(self.pos)
    }

    pub fn position(&self) -> [f64, ..2] {
        self.pos
    }

    pub fn update(
        &mut self, dt: f64,
        top_wall_aabb: &AABB,
        bottom_wall_aabb: &AABB,
        left_wall_aabb: &AABB,
        right_wall_aabb: &AABB,
        player1: &mut Player,
        player2: &mut Player
    ) {
        let size = self.aabb.size;
        let dp = [self.v[0] * dt, self.v[1] * dt];

        // check collision of x direction
        let aabb = self.aabb.trans([self.pos[0] + dp[0], self.pos[1]]);
        if dp[0] < 0.0 {
            if aabb.is_collided_with(left_wall_aabb) {
                player2.win();
                self.reset();
                println!("{} : {}", player1.score(), player2.score());
                return;
            } else if aabb.is_collided_with(&player1.aabb()) {
                let dy = self.reflection(player1);
                self.set_direction(1.0, dy);
            } else {
                self.pos[0] += dp[0];
            }
        } else {
            if aabb.is_collided_with(right_wall_aabb) {
                player1.win();
                self.reset();
                println!("{} : {}", player1.score(), player2.score());
                return;
            } else if aabb.is_collided_with(&player2.aabb()) {
                let dy = self.reflection(player2);
                self.set_direction(-1.0, dy);
            } else {
                self.pos[0] += dp[0];
            }
        }

        // check collision of y direction
        let aabb = self.aabb.trans([self.pos[0], self.pos[1] + dp[1]]);
        if dp[1] < 0.0 {
            if aabb.is_collided_with(top_wall_aabb) {
                self.pos[1] = top_wall_aabb.bottom() + size[1] / 2.0;
                self.v[1] = -self.v[1];
            } else {
                self.pos[1] += dp[1];
            }
        } else {
            if aabb.is_collided_with(bottom_wall_aabb) {
                self.pos[1] = bottom_wall_aabb.top() - size[1] / 2.0;
                self.v[1] = -self.v[1];
            } else {
                self.pos[1] += dp[1];
            }
        }
    }

    pub fn render(&self, c: &Context, gl: &mut Gl) {
        c.view().rect_centered(self.pos[0], self.pos[1], self.image.texture_width as f64 / 2.0, self.image.texture_height as f64 / 2.0).image(self.image).draw(gl);
    }

    pub fn emit(&mut self) {
        if self.v[0] == 0.0 && self.v[1] == 0.0 {
            let dx = if rand::random::<f64>() > 0.5 {
                0.5
            } else {
                -0.5
            };
            self.set_direction(dx, rand::random::<f64>() * 2.0 - 1.0);
        }
    }

    pub fn reset(&mut self) {
        self.v = [0.0, 0.0];
        self.pos = [settings::WINDOW_SIZE[0] as f64 / 2.0, settings::WINDOW_SIZE[1] as f64 / 2.0];
    }

    fn set_direction(&mut self, dx: f64, dy: f64) {
        let len = (dx * dx + dy * dy).sqrt();
        let dx = dx / len;
        let dy = dy / len;
        self.v = [dx * settings::BALL_MOVE_SPEED, dy * settings::BALL_MOVE_SPEED];
    }

    fn reflection(&self, player: &Player) -> f64 {
        let player_pos = player.position();
        let mut y = self.pos[1] - player_pos[1];

        y = y * rand::random::<f64>() * 0.4 + 0.8;

        let size =  player.aabb().size;
        if y > size[1] / 2.0 {
            y = size[1] / 2.0;
        } else if y < -size[1] / 2.0 {
            y = -size[1] / 2.0;
        }
        y * 4.0 / size[1]
    }
}

<commit_msg>Emit ball will only random at x axis<commit_after>
use rand;

use graphics::*;
use piston::*;

use aabb::AABB;
use settings;
use player::Player;

pub struct Ball {
    pos: [f64, ..2],
    v: [f64, ..2],

    aabb: AABB,

    image: Image,
}

impl Ball {
    pub fn new(image: Image) -> Ball {
        Ball {
            pos: [0.0, 0.0],
            v: [0.0, 0.0],

            aabb: AABB::new(0.0, 0.0, image.texture_width as f64, image.texture_height as f64),

            image: image,
        }
    }

    pub fn aabb(&self) -> AABB {
        self.aabb.trans(self.pos)
    }

    pub fn position(&self) -> [f64, ..2] {
        self.pos
    }

    pub fn update(
        &mut self, dt: f64,
        top_wall_aabb: &AABB,
        bottom_wall_aabb: &AABB,
        left_wall_aabb: &AABB,
        right_wall_aabb: &AABB,
        player1: &mut Player,
        player2: &mut Player
    ) {
        let size = self.aabb.size;
        let dp = [self.v[0] * dt, self.v[1] * dt];

        // check collision of x direction
        let aabb = self.aabb.trans([self.pos[0] + dp[0], self.pos[1]]);
        if dp[0] < 0.0 {
            if aabb.is_collided_with(left_wall_aabb) {
                player2.win();
                self.reset();
                println!("{} : {}", player1.score(), player2.score());
                return;
            } else if aabb.is_collided_with(&player1.aabb()) {
                let dy = self.reflection(player1);
                self.set_direction(1.0, dy);
            } else {
                self.pos[0] += dp[0];
            }
        } else {
            if aabb.is_collided_with(right_wall_aabb) {
                player1.win();
                self.reset();
                println!("{} : {}", player1.score(), player2.score());
                return;
            } else if aabb.is_collided_with(&player2.aabb()) {
                let dy = self.reflection(player2);
                self.set_direction(-1.0, dy);
            } else {
                self.pos[0] += dp[0];
            }
        }

        // check collision of y direction
        let aabb = self.aabb.trans([self.pos[0], self.pos[1] + dp[1]]);
        if dp[1] < 0.0 {
            if aabb.is_collided_with(top_wall_aabb) {
                self.pos[1] = top_wall_aabb.bottom() + size[1] / 2.0;
                self.v[1] = -self.v[1];
            } else {
                self.pos[1] += dp[1];
            }
        } else {
            if aabb.is_collided_with(bottom_wall_aabb) {
                self.pos[1] = bottom_wall_aabb.top() - size[1] / 2.0;
                self.v[1] = -self.v[1];
            } else {
                self.pos[1] += dp[1];
            }
        }
    }

    pub fn render(&self, c: &Context, gl: &mut Gl) {
        c.view().rect_centered(self.pos[0], self.pos[1], self.image.texture_width as f64 / 2.0, self.image.texture_height as f64 / 2.0).image(self.image).draw(gl);
    }

    pub fn emit(&mut self) {
        if self.v[0] == 0.0 && self.v[1] == 0.0 {
            let dx = if rand::random::<f64>() > 0.5 {
                0.5
            } else {
                -0.5
            };
            self.set_direction(dx, 0.0);
        }
    }

    pub fn reset(&mut self) {
        self.v = [0.0, 0.0];
        self.pos = [settings::WINDOW_SIZE[0] as f64 / 2.0, settings::WINDOW_SIZE[1] as f64 / 2.0];
    }

    fn set_direction(&mut self, dx: f64, dy: f64) {
        let len = (dx * dx + dy * dy).sqrt();
        let dx = dx / len;
        let dy = dy / len;
        self.v = [dx * settings::BALL_MOVE_SPEED, dy * settings::BALL_MOVE_SPEED];
    }

    fn reflection(&self, player: &Player) -> f64 {
        let player_pos = player.position();
        let mut y = self.pos[1] - player_pos[1];

        y = y * rand::random::<f64>() * 0.4 + 0.8;

        let size =  player.aabb().size;
        if y > size[1] / 2.0 {
            y = size[1] / 2.0;
        } else if y < -size[1] / 2.0 {
            y = -size[1] / 2.0;
        }
        y * 4.0 / size[1]
    }
}

<|endoftext|>


<commit_before>//! Bit level parsers and combinators
//!
//!

#[macro_export]
macro_rules! bits (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    bit_impl!($i, $submac!($($args)*));
  );
  ($i:expr, $f:expr, $g:expr) => (
    bit_impl!($i, call!($f));
  );
);

#[macro_export]
macro_rules! bits_impl (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    {
      match $submac!( ($i, 0usize), $($args)*) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)),
        $crate::IResult::Done((i, bit_index), o)             => {
          let byte_index = if bit_index == 0 { 0 } else { 1 };

          $crate::IResult::Done(&i[byte_index..], o)
        }
      }
    }
  );
);

/// `take!(nb) => &[T] -> IResult<&[T], &[T]>`
/// generates a parser consuming the specified number of bytes
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  // Desmond parser
///  named!(take5, take!( 5 ) );
///
///  let a = b"abcdefgh";
///
///  assert_eq!(take5(&a[..]), Done(&b"fgh"[..], &b"abcde"[..]));
/// # }
/// ```
#[macro_export]
macro_rules! take_bits (
  (($i:expr, $bit_offset:expr), $t:ty, $count:expr) => (
    {
      use std::ops::Div;
      if $count == 0 {
        $crate::IResult::Done( ($i, $bit_offset) , 0)
      } else {
        let cnt = ($count as usize + $bit_offset).div(8);
        if $i.len() * 8 < $count as usize + $bit_offset {
          $crate::IResult::Incomplete($crate::Needed::Size(cnt+1))
        } else {
          let mut acc:$t            = 0;
          let mut offset: usize     = $bit_offset;
          let mut remaining: usize  = $count;
          let mut end_offset: usize = 0;

          for it in 0..cnt+1 {
            if remaining == 0 {
              break;
            }
            let val: $t = if offset == 0 {
              $i[it] as $t
            } else {
              (($i[it] << offset) as u8 >> offset) as $t
            };

            if remaining < 8 - offset {
              acc += val >> (8 - offset - remaining);
              end_offset = remaining + offset;
              break;
            } else {
              acc += val << remaining - (8 - offset);
              remaining -= 8 - offset;
              offset = 0;
            }
          }
          $crate::IResult::Done( (&$i[cnt..], end_offset) , acc)
        }
      }
    }
  );
);

#[cfg(test)]
mod tests {
  use internal::{IResult,Needed};

  #[test]
  fn take_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(take_bits!( (sl, 0), u8,   0 ), IResult::Done((sl, 0), 0));
    assert_eq!(take_bits!( (sl, 0), u8,   8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 0), u8,   3 ), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(take_bits!( (sl, 1), u8,   1 ), IResult::Done((&sl[0..], 2), 0));
    assert_eq!(take_bits!( (sl, 1), u8,   2 ), IResult::Done((&sl[0..], 3), 1));
    assert_eq!(take_bits!( (sl, 1), u8,   3 ), IResult::Done((&sl[0..], 4), 2));
    assert_eq!(take_bits!( (sl, 6), u8,   3 ), IResult::Done((&sl[1..], 1), 5));
    assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
    assert_eq!(take_bits!( (sl, 0), u16,  8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
    assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
    assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
    assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
    assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(4)));
  }
}
<commit_msg>fix bit level macros<commit_after>//! Bit level parsers and combinators
//!
//!

#[macro_export]
macro_rules! bits (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    bits_impl!($i, $submac!($($args)*));
  );
  ($i:expr, $f:expr, $g:expr) => (
    bits_impl!($i, call!($f));
  );
);

#[macro_export]
macro_rules! bits_impl (
  ($i:expr, $submac:ident!( $($args:tt)* )) => (
    {
      let input = ($i, 0usize);
      match $submac!( input, $($args)*) {
        $crate::IResult::Error(e)                            => $crate::IResult::Error(e),
        $crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
        $crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)),
        $crate::IResult::Done((i, bit_index), o)             => {
          let byte_index = if bit_index == 0 { 0 } else { 1 };

          $crate::IResult::Done(&i[byte_index..], o)
        }
      }
    }
  );
);

/// `take!(nb) => &[T] -> IResult<&[T], &[T]>`
/// generates a parser consuming the specified number of bytes
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use nom::IResult::Done;
/// # fn main() {
///  // Desmond parser
///  named!(take5, take!( 5 ) );
///
///  let a = b"abcdefgh";
///
///  assert_eq!(take5(&a[..]), Done(&b"fgh"[..], &b"abcde"[..]));
/// # }
/// ```
#[macro_export]
macro_rules! take_bits (
  ($i:expr, $t:ty, $count:expr) => (
    {
      use std::ops::Div;
      let (input, bit_offset) = $i;
      if $count == 0 {
        $crate::IResult::Done( (input, bit_offset), 0)
      } else {
        let cnt = ($count as usize + bit_offset).div(8);
        if input.len() * 8 < $count as usize + bit_offset {
          $crate::IResult::Incomplete($crate::Needed::Size(cnt+1))
        } else {
          let mut acc:$t            = 0;
          let mut offset: usize     = bit_offset;
          let mut remaining: usize  = $count;
          let mut end_offset: usize = 0;

          for it in 0..cnt+1 {
            if remaining == 0 {
              break;
            }
            let val: $t = if offset == 0 {
              input[it] as $t
            } else {
              ((input[it] << offset) as u8 >> offset) as $t
            };

            if remaining < 8 - offset {
              acc += val >> (8 - offset - remaining);
              end_offset = remaining + offset;
              break;
            } else {
              acc += val << remaining - (8 - offset);
              remaining -= 8 - offset;
              offset = 0;
            }
          }
          $crate::IResult::Done( (&input[cnt..], end_offset) , acc)
        }
      }
    }
  );
);

#[cfg(test)]
mod tests {
  use internal::{IResult,Needed};

  #[test]
  fn take_bits() {
    let input = vec![0b10101010, 0b11110000, 0b00110011];
    let sl    = &input[..];

    assert_eq!(take_bits!( (sl, 0), u8,   0 ), IResult::Done((sl, 0), 0));
    assert_eq!(take_bits!( (sl, 0), u8,   8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 0), u8,   3 ), IResult::Done((&sl[0..], 3), 5));
    assert_eq!(take_bits!( (sl, 1), u8,   1 ), IResult::Done((&sl[0..], 2), 0));
    assert_eq!(take_bits!( (sl, 1), u8,   2 ), IResult::Done((&sl[0..], 3), 1));
    assert_eq!(take_bits!( (sl, 1), u8,   3 ), IResult::Done((&sl[0..], 4), 2));
    assert_eq!(take_bits!( (sl, 6), u8,   3 ), IResult::Done((&sl[1..], 1), 5));
    assert_eq!(take_bits!( (sl, 0), u16, 10 ), IResult::Done((&sl[1..], 2), 683));
    assert_eq!(take_bits!( (sl, 0), u16,  8 ), IResult::Done((&sl[1..], 0), 170));
    assert_eq!(take_bits!( (sl, 6), u16, 10 ), IResult::Done((&sl[2..], 0), 752));
    assert_eq!(take_bits!( (sl, 6), u16, 11 ), IResult::Done((&sl[2..], 1), 1504));
    assert_eq!(take_bits!( (sl, 0), u32, 20 ), IResult::Done((&sl[2..], 4), 700163));
    assert_eq!(take_bits!( (sl, 4), u32, 20 ), IResult::Done((&sl[3..], 0), 716851));
    assert_eq!(take_bits!( (sl, 4), u32, 22 ), IResult::Incomplete(Needed::Size(4)));
  }
}
<|endoftext|>


<commit_before>// Build script.
//
// This program is run by Cargo when building lib/codegen. It is used to generate Rust code from
// the language definitions in the lib/codegen/meta directory.
//
// Environment:
//
// OUT_DIR
//     Directory where generated files should be placed.
//
// TARGET
//     Target triple provided by Cargo.
//
// CRETONNE_TARGETS (Optional)
//     A setting for conditional compilation of isa targets. Possible values can be "native" or
//     known isa targets separated by ','.
//
// The build script expects to be run from the directory where this build.rs file lives. The
// current directory is used to find the sources.

use std::env;
use std::process;

fn main() {
    let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
    let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
    let cretonne_targets = env::var("CRETONNE_TARGETS").ok();
    let cretonne_targets = cretonne_targets.as_ref().map(|s| s.as_ref());

    // Configure isa targets cfg.
    match isa_targets(cretonne_targets, &target_triple) {
        Ok(isa_targets) => {
            for isa in &isa_targets {
                println!("cargo:rustc-cfg=build_{}", isa.name());
            }
        }
        Err(err) => {
            eprintln!("Error: {}", err);
            process::exit(1);
        }
    }

    println!("Build script generating files in {}", out_dir);

    let cur_dir = env::current_dir().expect("Can't access current working directory");
    let crate_dir = cur_dir.as_path();

    // Make sure we rebuild if this build script changes.
    // I guess that won't happen if you have non-UTF8 bytes in your path names.
    // The `build.py` script prints out its own dependencies.
    println!(
        "cargo:rerun-if-changed={}",
        crate_dir.join("build.rs").to_string_lossy()
    );

    // Scripts are in `$crate_dir/meta`.
    let meta_dir = crate_dir.join("meta");
    let build_script = meta_dir.join("build.py");

    // Launch build script with Python. We'll just find python in the path.
    // Use -B to disable .pyc files, because they cause trouble for vendoring
    // scripts, and this is a build step that isn't run very often anyway.
    let status = process::Command::new("python")
        .current_dir(crate_dir)
        .arg("-B")
        .arg(build_script)
        .arg("--out-dir")
        .arg(out_dir)
        .status()
        .expect("Failed to launch second-level build script; is python installed?");
    if !status.success() {
        process::exit(status.code().unwrap());
    }
}

/// Represents known ISA target.
#[derive(Copy, Clone)]
enum Isa {
    Riscv,
    X86,
    Arm32,
    Arm64,
}

impl Isa {
    /// Creates isa target using name.
    fn new(name: &str) -> Option<Self> {
        Isa::all()
            .iter()
            .cloned()
            .filter(|isa| isa.name() == name)
            .next()
    }

    /// Creates isa target from arch.
    fn from_arch(arch: &str) -> Option<Isa> {
        Isa::all()
            .iter()
            .cloned()
            .filter(|isa| isa.is_arch_applicable(arch))
            .next()
    }

    /// Returns all supported isa targets.
    fn all() -> [Isa; 4] {
        [Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
    }

    /// Returns name of the isa target.
    fn name(&self) -> &'static str {
        match *self {
            Isa::Riscv => "riscv",
            Isa::X86 => "x86",
            Isa::Arm32 => "arm32",
            Isa::Arm64 => "arm64",
        }
    }

    /// Checks if arch is applicable for the isa target.
    fn is_arch_applicable(&self, arch: &str) -> bool {
        match *self {
            Isa::Riscv => arch == "riscv",
            Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch),
            Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"),
            Isa::Arm64 => arch == "aarch64",
        }
    }
}

/// Returns isa targets to configure conditional compilation.
fn isa_targets(cretonne_targets: Option<&str>, target_triple: &str) -> Result<Vec<Isa>, String> {
    match cretonne_targets {
        Some("native") => Isa::from_arch(target_triple.split('-').next().unwrap())
            .map(|isa| vec![isa])
            .ok_or_else(|| {
                format!(
                    "no supported isa found for target triple `{}`",
                    target_triple
                )
            }),
        Some(targets) => {
            let unknown_isa_targets = targets
                .split(',')
                .filter(|target| Isa::new(target).is_none())
                .collect::<Vec<_>>();
            let isa_targets = targets.split(',').flat_map(Isa::new).collect::<Vec<_>>();
            match (unknown_isa_targets.is_empty(), isa_targets.is_empty()) {
                (true, true) => Ok(Isa::all().to_vec()),
                (true, _) => Ok(isa_targets),
                (_, _) => Err(format!(
                    "unknown isa targets: `{}`",
                    unknown_isa_targets.join(", ")
                )),
            }
        }
        None => Ok(Isa::all().to_vec()),
    }
}
<commit_msg>Fail loudly if a build.rs dependency path can't be printed.<commit_after>// Build script.
//
// This program is run by Cargo when building lib/codegen. It is used to generate Rust code from
// the language definitions in the lib/codegen/meta directory.
//
// Environment:
//
// OUT_DIR
//     Directory where generated files should be placed.
//
// TARGET
//     Target triple provided by Cargo.
//
// CRETONNE_TARGETS (Optional)
//     A setting for conditional compilation of isa targets. Possible values can be "native" or
//     known isa targets separated by ','.
//
// The build script expects to be run from the directory where this build.rs file lives. The
// current directory is used to find the sources.

use std::env;
use std::process;

fn main() {
    let out_dir = env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set");
    let target_triple = env::var("TARGET").expect("The TARGET environment variable must be set");
    let cretonne_targets = env::var("CRETONNE_TARGETS").ok();
    let cretonne_targets = cretonne_targets.as_ref().map(|s| s.as_ref());

    // Configure isa targets cfg.
    match isa_targets(cretonne_targets, &target_triple) {
        Ok(isa_targets) => {
            for isa in &isa_targets {
                println!("cargo:rustc-cfg=build_{}", isa.name());
            }
        }
        Err(err) => {
            eprintln!("Error: {}", err);
            process::exit(1);
        }
    }

    println!("Build script generating files in {}", out_dir);

    let cur_dir = env::current_dir().expect("Can't access current working directory");
    let crate_dir = cur_dir.as_path();

    // Make sure we rebuild if this build script changes.
    // I guess that won't happen if you have non-UTF8 bytes in your path names.
    // The `build.py` script prints out its own dependencies.
    println!(
        "cargo:rerun-if-changed={}",
        crate_dir.join("build.rs").to_str().unwrap()
    );

    // Scripts are in `$crate_dir/meta`.
    let meta_dir = crate_dir.join("meta");
    let build_script = meta_dir.join("build.py");

    // Launch build script with Python. We'll just find python in the path.
    // Use -B to disable .pyc files, because they cause trouble for vendoring
    // scripts, and this is a build step that isn't run very often anyway.
    let status = process::Command::new("python")
        .current_dir(crate_dir)
        .arg("-B")
        .arg(build_script)
        .arg("--out-dir")
        .arg(out_dir)
        .status()
        .expect("Failed to launch second-level build script; is python installed?");
    if !status.success() {
        process::exit(status.code().unwrap());
    }
}

/// Represents known ISA target.
#[derive(Copy, Clone)]
enum Isa {
    Riscv,
    X86,
    Arm32,
    Arm64,
}

impl Isa {
    /// Creates isa target using name.
    fn new(name: &str) -> Option<Self> {
        Isa::all()
            .iter()
            .cloned()
            .filter(|isa| isa.name() == name)
            .next()
    }

    /// Creates isa target from arch.
    fn from_arch(arch: &str) -> Option<Isa> {
        Isa::all()
            .iter()
            .cloned()
            .filter(|isa| isa.is_arch_applicable(arch))
            .next()
    }

    /// Returns all supported isa targets.
    fn all() -> [Isa; 4] {
        [Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64]
    }

    /// Returns name of the isa target.
    fn name(&self) -> &'static str {
        match *self {
            Isa::Riscv => "riscv",
            Isa::X86 => "x86",
            Isa::Arm32 => "arm32",
            Isa::Arm64 => "arm64",
        }
    }

    /// Checks if arch is applicable for the isa target.
    fn is_arch_applicable(&self, arch: &str) -> bool {
        match *self {
            Isa::Riscv => arch == "riscv",
            Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch),
            Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"),
            Isa::Arm64 => arch == "aarch64",
        }
    }
}

/// Returns isa targets to configure conditional compilation.
fn isa_targets(cretonne_targets: Option<&str>, target_triple: &str) -> Result<Vec<Isa>, String> {
    match cretonne_targets {
        Some("native") => Isa::from_arch(target_triple.split('-').next().unwrap())
            .map(|isa| vec![isa])
            .ok_or_else(|| {
                format!(
                    "no supported isa found for target triple `{}`",
                    target_triple
                )
            }),
        Some(targets) => {
            let unknown_isa_targets = targets
                .split(',')
                .filter(|target| Isa::new(target).is_none())
                .collect::<Vec<_>>();
            let isa_targets = targets.split(',').flat_map(Isa::new).collect::<Vec<_>>();
            match (unknown_isa_targets.is_empty(), isa_targets.is_empty()) {
                (true, true) => Ok(Isa::all().to_vec()),
                (true, _) => Ok(isa_targets),
                (_, _) => Err(format!(
                    "unknown isa targets: `{}`",
                    unknown_isa_targets.join(", ")
                )),
            }
        }
        None => Ok(Isa::all().to_vec()),
    }
}
<|endoftext|>


<commit_before>//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
//! - [**Diff**](./enum.Diff.html) (produced by the [**diff**](./fn.diff.html) function) describes
//! the difference between two non-`Clone` iterators `a` and `b` after breaking ASAP from a
//! comparison with enough data to update `a`'s collection.
//! - [**copy_on_diff**](./fn.copy_on_diff.html) is an application of [**diff**] that compares two
//! iterators `a` and `b`, borrowing the source of `a` if they are the same or creating a new owned
//! collection with `b`'s elements if they are different.

use adaptors::PutBack;
use std::borrow::{Cow, ToOwned};
use std::iter::FromIterator;

/// A type returned by the [`diff`](./fn.diff.html) function.
///
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
/// iterator `J`.
pub enum Diff<I, J>
    where I: Iterator,
          J: Iterator,
{
    /// The index of the first non-matching element along with the iterator's remaining elements
    /// starting with the first mis-matched element.
    FirstMismatch(usize, PutBack<I>, PutBack<J>),
    /// The total number of elements that were in the iterator.
    Shorter(usize, PutBack<I>),
    /// The remaining elements of the iterator.
    Longer(usize, PutBack<J>),
}

/// Compares every element yielded by both `i` and `j` in lock-step and returns a `Diff` which
/// describes how `j` differs from `i`.
///
/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
/// `Diff::Shorter`.
///
/// If the two elements of a step differ, the index of those elements along with the remaining
/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`.
///
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
/// the remaining `j` elements will be returned as `Diff::Longer`.
pub fn diff<I, J>(i: I, j: J) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator,
          J: IntoIterator,
          I::Item: PartialEq<J::Item>,
{
    diff_internal(i, j, |ie, je| ie != je)
}

/// Similar to [`diff`](./fn.diff), however expects `i` to yield references to its elements.
///
/// This function is useful for caching some iterator `j` in some sequential collection without
/// requiring `j` to be `Clone` in order to compare it to the collection before determining if the
/// collection needs to be updated. The function returns as soon as a difference is found,
/// producing a `Diff` that provides the data necessary to update the collection without ever
/// requiring `J` to be `Clone`. This allows for efficiently caching iterators like `Map` or
/// `Filter` that do not implement `Clone`.
///
/// See [`copy_on_diff`](./fn.copy_on_diff.html) for an application of `diff`.
pub fn diff_by_ref<'a, I, J>(i: I, j: J) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator<Item=&'a J::Item>,
          J: IntoIterator,
          J::Item: PartialEq + 'a,
{
    diff_internal(i, j, |ie, je| *ie != je)
}

// Compares every element yielded by both `i` and `j`  with the given `is_diff` function in
// lock-step.
//
// Returns a `Diff` which describes how `j` differs from `i`.
fn diff_internal<I, J, F>(i: I, j: J, is_diff: F) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator,
          J: IntoIterator,
          F: Fn(&I::Item, &J::Item) -> bool,
{
    let mut i = i.into_iter();
    let mut j = j.into_iter();
    let mut idx = 0;
    while let Some(i_elem) = i.next() {
        match j.next() {
            None => return Some(Diff::Shorter(idx, PutBack::value(i_elem, i))),
            Some(j_elem) => if is_diff(&i_elem, &j_elem) {
                let remaining_i = PutBack::value(i_elem, i);
                let remaining_j = PutBack::value(j_elem, j);
                return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
            },
        }
        idx += 1;
    }
    j.next().map(|j_elem| Diff::Longer(idx, PutBack::value(j_elem, j)))
}

/// Returns `Cow::Borrowed` `collection` if `collection` contains the same elements as yielded by
/// `update`'s iterator.
///
/// Collects into a new `C::Owned` and returns `Cow::Owned` if either the number of elements or the
/// elements themselves differ.
///
/// # Examples
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let cow = copy_on_diff(&a, b_map);
///
/// assert!(match cow {
///     Cow::Borrowed(slice) => slice == &a,
///     _ => false,
/// });
/// ```
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2, 3];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let cow = copy_on_diff(&a, b_map);
///
/// assert!(match cow {
///     Cow::Owned(vec) => vec == vec![0, 1, 2],
///     _ => false,
/// });
/// ```
pub fn copy_on_diff<'a, C, U, T: 'a>(collection: &'a C, update: U) -> Cow<'a, C>
    where &'a C: IntoIterator<Item=&'a T>,
          <&'a C as IntoIterator>::IntoIter: Clone,
          C: ToOwned,
          <C as ToOwned>::Owned: FromIterator<T>,
          U: IntoIterator<Item=T>,
          T: Clone + PartialEq,
{
    let c_iter = collection.into_iter();
    match diff_by_ref(c_iter.clone(), update.into_iter()) {
        Some(diff) => match diff {
            Diff::FirstMismatch(idx, _, mismatch) =>
                Cow::Owned(c_iter.take(idx).cloned().chain(mismatch).collect()),
            Diff::Longer(_, remaining) =>
                Cow::Owned(c_iter.cloned().chain(remaining).collect()),
            Diff::Shorter(num_update, _) =>
                Cow::Owned(c_iter.cloned().take(num_update).collect()),
        },
        None => Cow::Borrowed(collection),
    }
}
<commit_msg>Updated some comments to the symmetric diff changes.<commit_after>//! "Diff"ing iterators for caching elements to sequential collections without requiring the new
//! elements' iterator to be `Clone`.
//!
//! - [**Diff**](./enum.Diff.html) (produced by the [**diff**](./fn.diff.html) and
//! [**diff_by_ref**](./fn.diff_by_ref.html) functions) describes the difference between two
//! non-`Clone` iterators `a` and `b` after breaking ASAP from a comparison with enough data to
//! update `a`'s collection.
//! - [**copy_on_diff**](./fn.copy_on_diff.html) is an application of [**diff**] that compares two
//! iterators `a` and `b`, borrowing the source of `a` if they are the same or creating a new owned
//! collection with `b`'s elements if they are different.

use adaptors::PutBack;
use std::borrow::{Cow, ToOwned};
use std::iter::FromIterator;

/// A type returned by the [`diff`](./fn.diff.html) function.
///
/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some
/// iterator `J`.
pub enum Diff<I, J>
    where I: Iterator,
          J: Iterator,
{
    /// The index of the first non-matching element along with both iterator's remaining elements
    /// starting with the first mis-match.
    FirstMismatch(usize, PutBack<I>, PutBack<J>),
    /// The total number of elements that were in `J` along with the remaining elements of `I`.
    Shorter(usize, PutBack<I>),
    /// The total number of elements that were in `I` along with the remaining elements of `J`.
    Longer(usize, PutBack<J>),
}

/// Compares every element yielded by both `i` and `j` in lock-step and returns a `Diff` which
/// describes how `j` differs from `i`.
///
/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`,
/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as
/// `Diff::Shorter`.
///
/// If the two elements of a step differ, the index of those elements along with the remaining
/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`.
///
/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with
/// the remaining `j` elements will be returned as `Diff::Longer`.
pub fn diff<I, J>(i: I, j: J) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator,
          J: IntoIterator,
          I::Item: PartialEq<J::Item>,
{
    diff_internal(i, j, |ie, je| ie != je)
}

/// Similar to [`diff`](./fn.diff.html), however expects `i` to yield references to its elements.
///
/// This function is useful for caching some iterator `j` in some sequential collection without
/// requiring `j` to be `Clone` in order to compare it to the collection before determining if the
/// collection needs to be updated. The function returns as soon as a difference is found,
/// producing a `Diff` that provides the data necessary to update the collection without ever
/// requiring `J` to be `Clone`. This allows for efficiently caching iterators like `Map` or
/// `Filter` that do not implement `Clone`.
///
/// See [`copy_on_diff`](./fn.copy_on_diff.html) for an application of `diff`.
pub fn diff_by_ref<'a, I, J>(i: I, j: J) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator<Item=&'a J::Item>,
          J: IntoIterator,
          J::Item: PartialEq + 'a,
{
    diff_internal(i, j, |ie, je| *ie != je)
}

// Compares every element yielded by both `i` and `j`  with the given `is_diff` function in
// lock-step.
//
// Returns a `Diff` which describes how `j` differs from `i`.
fn diff_internal<I, J, F>(i: I, j: J, is_diff: F) -> Option<Diff<I::IntoIter, J::IntoIter>>
    where I: IntoIterator,
          J: IntoIterator,
          F: Fn(&I::Item, &J::Item) -> bool,
{
    let mut i = i.into_iter();
    let mut j = j.into_iter();
    let mut idx = 0;
    while let Some(i_elem) = i.next() {
        match j.next() {
            None => return Some(Diff::Shorter(idx, PutBack::value(i_elem, i))),
            Some(j_elem) => if is_diff(&i_elem, &j_elem) {
                let remaining_i = PutBack::value(i_elem, i);
                let remaining_j = PutBack::value(j_elem, j);
                return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j));
            },
        }
        idx += 1;
    }
    j.next().map(|j_elem| Diff::Longer(idx, PutBack::value(j_elem, j)))
}

/// Returns `Cow::Borrowed` `collection` if `collection` contains the same elements as yielded by
/// `update`'s iterator.
///
/// Collects into a new `C::Owned` and returns `Cow::Owned` if either the number of elements or the
/// elements themselves differ.
///
/// # Examples
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let cow = copy_on_diff(&a, b_map);
///
/// assert!(match cow {
///     Cow::Borrowed(slice) => slice == &a,
///     _ => false,
/// });
/// ```
///
/// ```
/// use itertools::copy_on_diff;
/// use std::borrow::Cow;
///
/// let a = vec![0, 1, 2, 3];
/// let b = vec![0.0, 1.0, 2.0];
/// let b_map = b.into_iter().map(|f| f as i32);
/// let cow = copy_on_diff(&a, b_map);
///
/// assert!(match cow {
///     Cow::Owned(vec) => vec == vec![0, 1, 2],
///     _ => false,
/// });
/// ```
pub fn copy_on_diff<'a, C, U, T: 'a>(collection: &'a C, update: U) -> Cow<'a, C>
    where &'a C: IntoIterator<Item=&'a T>,
          <&'a C as IntoIterator>::IntoIter: Clone,
          C: ToOwned,
          <C as ToOwned>::Owned: FromIterator<T>,
          U: IntoIterator<Item=T>,
          T: Clone + PartialEq,
{
    let c_iter = collection.into_iter();
    match diff_by_ref(c_iter.clone(), update.into_iter()) {
        Some(diff) => match diff {
            Diff::FirstMismatch(idx, _, mismatch) =>
                Cow::Owned(c_iter.take(idx).cloned().chain(mismatch).collect()),
            Diff::Longer(_, remaining) =>
                Cow::Owned(c_iter.cloned().chain(remaining).collect()),
            Diff::Shorter(num_update, _) =>
                Cow::Owned(c_iter.cloned().take(num_update).collect()),
        },
        None => Cow::Borrowed(collection),
    }
}
<|endoftext|>


<commit_before>use imgui::{Ui,ImStr,ImString};
use lichen::parse::{StreamParser,Env};

use std::fs;
use std::path::Path;

use app::AppState;

use std::io::{BufReader};
use std::fs::File;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
    stream: Option<StreamParser<BufReader<File>>>,
    failed: String,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
            stream: None,
            failed: "".to_owned(),
        }
    }
}

impl FileState {
    fn update(&mut self) -> Option<Env> {
        if self.idx > 0 { // chose a file?
            self.failed.clear();

            if let Some(file) = self.files.get(self.idx as usize) {
                self.cd.clear();
                self.cd.push_str(file);
                self.idx = -1;
            }
        }
        else if self.idx == 0 { // up a directory?
            self.failed.clear();
            self.to_parent();
        }

        let cd = self.cd.to_string();
        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(&cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path().to_str().unwrap().to_owned()
                    })
                    .collect();

                self.files.insert(0,"..".to_owned());
            }
            // NOTE: we should throw a warning here if directory cannot be traversed
        }
        else {
            if !cd.is_empty() {
                self.selected = Some(cd);
            }
        }

        if self.stream.is_some() {
            let r = self.step_stream();
            if !self.failed.is_empty() {
                self.stream = None;
            }
            r
        }
        else { None }
    }

    /// Steps through the stream chunks, finally returns parsed lichen environment
    fn step_stream (&mut self) -> Option<Env> {
        let r = {
            if let Some(ref mut stream) = self.stream {
                stream.next()
            }
            else { None }
        };

        if r.is_none() { // close stream, we're probably done
            let mut env = Env::empty();
            if let Some(ref mut stream) = self.stream {
                if let Err(e) = stream.sink(&mut env) {
                    self.failed = e.to_owned();
                    return None;
                }
            }

            self.stream = None;
            self.to_parent();

            return Some(env);
        }

        None
    }

    fn to_parent(&mut self) {
        self.selected = None;
        if let Some(path) = Path::new(&self.cd.to_string()).parent() {
            self.cd.clear();
            self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
            self.idx = -1;
        }
        // NOTE: this fails if we're at the top of a relative directory listing,
        // or the root of the drive/share
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }
        state.env = self.update(); // NOTE: we should check if the environment is empty
        state.open_file = !state.env.is_some(); // close file if done

        ui.window(im_str!("Select source"))
            .always_auto_resize(true)
            .movable(true)
            .show_borders(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                }).collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);

                if let Some(ref file) = self.selected {
                    ui.text(im_str!("Select File {:}?",file));

                    if ui.small_button(im_str!("open")) {
                        if let Ok(f) = File::open(file) {
                            let f = BufReader::new(f);
                            let s = StreamParser::new(f,None);
                            self.stream = Some(s);
                        }
                    }
                }

                if !self.failed.is_empty() {
                    ui.text(im_str!("Failed to parse file {:}\nParse Error at: {:}",
                                    &self.cd.to_str(), &self.failed));
                }
            })
    }

}

<commit_msg>cleanup ui and fix file opener<commit_after>use imgui::{Ui,ImStr,ImString};
use lichen::parse::{StreamParser,Env};

use std::fs;
use std::path::Path;

use app::AppState;

use std::io::{BufReader};
use std::fs::File;

pub struct FileState {
    /// MAX_PATH set to 260 chars
    cd: ImString,
    idx: i32,
    files: Vec<String>,
    selected: Option<String>,
    stream: Option<StreamParser<BufReader<File>>>,
    failed: String,
}

impl Default for FileState {
    fn default() -> Self {
        let mut cd = ImString::from(im_str!("./"));
        cd.reserve(261); //arbitrary max path size

        FileState {
            cd: cd,
            idx: 1,
            files: vec![],
            selected: None,
            stream: None,
            failed: "".to_owned(),
        }
    }
}

impl FileState {
    fn update(&mut self) -> Option<Env> {
        if self.idx > 0 { // chose a file?
            self.failed.clear();

            if let Some(file) = self.files.get(self.idx as usize) {
                let mut p = Path::new(&self.cd.to_str()).join(Path::new(&file));
                if !p.is_dir() && !p.is_file() {
                    if let Some(p_) = Path::new(&self.cd.to_str()).parent() {
                        p = p_.join(Path::new(&file));
                    }
                }

                self.cd.clear();
                self.cd.push_str(p.to_str().unwrap());
                self.idx = -1;
            }
        }
        else if self.idx == 0 { // up a directory?
            self.failed.clear();
            self.to_parent();
        }

        let cd = self.cd.to_string();
        if Path::new(&cd).is_dir() {
            if let Ok(paths) = fs::read_dir(&cd) {
                self.files = paths
                    .filter(|p| p.is_ok())
                    .map(|p| {
                        p.unwrap().path().as_path()
                            .iter().last().expect("Invalid listing")
                            .to_str().expect("Non-UTF8 Filename found").to_owned()
                    })
                    .collect();

                self.files.insert(0,"..".to_owned());
            }
            else { self.to_parent(); }
        }
        else {
            if !cd.is_empty() {
                let p = Path::new(&cd);
                let file: &str = p
                    .iter().last().expect("Invalid listing")
                    .to_str().expect("Non-UTF8 Filename found");
                self.selected = Some(file.to_owned());
                self.cd.clear();
                self.cd.push_str(p.to_str().unwrap());
            }
        }

        if self.stream.is_some() {
            let r = self.step_stream();
            if !self.failed.is_empty() {
                self.stream = None;
            }
            r
        }
        else { None }
    }

    /// Steps through the stream chunks, finally returns parsed lichen environment
    fn step_stream (&mut self) -> Option<Env> {
        let r = {
            if let Some(ref mut stream) = self.stream {
                stream.next()
            }
            else { None }
        };

        if r.is_none() { // close stream, we're probably done
            let mut env = Env::empty();
            if let Some(ref mut stream) = self.stream {
                if let Err(e) = stream.sink(&mut env) {
                    self.failed = e.to_owned();
                    return None;
                }
            }

            self.stream = None;
            self.to_parent();

            return Some(env);
        }

        None
    }

    fn to_parent(&mut self) {
        self.selected = None;
        if let Some(path) = Path::new(&self.cd.to_string()).parent() {
            self.cd.clear();
            self.cd.push_str(path.to_str().expect("ERROR: Cannot parse path into string"));
            self.idx = -1;
        }
        // NOTE: this fails if we're at the top of a relative directory listing,
        // or the root of the drive/share
    }

    pub fn render (&mut self, ui: &Ui, state: &mut AppState) {
        if !state.open_file { return }
        state.env = self.update(); // NOTE: we should check if the environment is empty
        state.open_file = !state.env.is_some(); // close file if done

        ui.window(im_str!("Select source"))
            .movable(true)
            .opened(&mut state.open_file)
            .build(||{
                ui.text(im_str!("Select a source file to be parsed and evaluated.\nSource files must be parsable through the lichen crate."));
                ui.separator();
                ui.input_text(im_str!("Current Directory"), &mut self.cd)
                    .enter_returns_true(true)
                    .build();
                ui.separator();

                // NOTE: to appease the borrow checker and have the proper argument for list_box
                // we must build the list in two steps
                let paths: Vec<ImString> = self.files.iter().map(|p| {
                    im_str!("{:}", p).to_owned()
                }).collect();

                let paths: Vec<&ImStr> = paths.iter().map(|p|p.as_ref()).collect();

                ui.list_box(im_str!("Files"),
                            &mut self.idx,
                            &paths[..],
                            paths.len() as i32);

                if let Some(ref file) = self.selected {
                    ui.text(im_str!("Select File {:}?",file));

                    if ui.small_button(im_str!("open")) {
                        if let Ok(f) = File::open(Path::new(&self.cd.to_str())) {
                            let f = BufReader::new(f);
                            let s = StreamParser::new(f,None);
                            self.stream = Some(s);
                        }
                    }
                }

                if !self.failed.is_empty() {
                    ui.text(im_str!("Failed to parse file {:}\nParse Error at: {:}",
                                    &self.cd.to_str(), &self.failed));
                }
            })
    }

}

<|endoftext|>