<commit_before>use std::fmt;
use std::marker::PhantomData;
use std::time::Duration;

use actix_codec::{AsyncRead, AsyncWrite};
use actix_connect::{
    default_connector, Connect as TcpConnect, Connection as TcpConnection,
};
use actix_service::{apply_fn, Service, ServiceExt};
use actix_utils::timeout::{TimeoutError, TimeoutService};
use http::Uri;
use tokio_tcp::TcpStream;

use super::connection::Connection;
use super::error::ConnectError;
use super::pool::{ConnectionPool, Protocol};

#[cfg(feature = "ssl")]
use openssl::ssl::SslConnector;

#[cfg(not(feature = "ssl"))]
type SslConnector = ();

/// Http client connector builde instance.
/// `Connector` type uses builder-like pattern for connector service construction.
pub struct Connector<T, U> {
    connector: T,
    timeout: Duration,
    conn_lifetime: Duration,
    conn_keep_alive: Duration,
    disconnect_timeout: Duration,
    limit: usize,
    #[allow(dead_code)]
    ssl: SslConnector,
    _t: PhantomData<U>,
}

impl Connector<(), ()> {
    pub fn new() -> Connector<
        impl Service<
                Request = TcpConnect<Uri>,
                Response = TcpConnection<Uri, TcpStream>,
                Error = actix_connect::ConnectError,
            > + Clone,
        TcpStream,
    > {
        let ssl = {
            #[cfg(feature = "ssl")]
            {
                use log::error;
                use openssl::ssl::{SslConnector, SslMethod};

                let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap();
                let _ = ssl
                    .set_alpn_protos(b"\x02h2\x08http/1.1")
                    .map_err(|e| error!("Can not set alpn protocol: {:?}", e));
                ssl.build()
            }
            #[cfg(not(feature = "ssl"))]
            {}
        };

        Connector {
            ssl,
            connector: default_connector(),
            timeout: Duration::from_secs(1),
            conn_lifetime: Duration::from_secs(75),
            conn_keep_alive: Duration::from_secs(15),
            disconnect_timeout: Duration::from_millis(3000),
            limit: 100,
            _t: PhantomData,
        }
    }
}

impl<T, U> Connector<T, U> {
    /// Use custom connector.
    pub fn connector<T1, U1>(self, connector: T1) -> Connector<T1, U1>
    where
        U1: AsyncRead + AsyncWrite + fmt::Debug,
        T1: Service<
                Request = TcpConnect<Uri>,
                Response = TcpConnection<Uri, U1>,
                Error = actix_connect::ConnectError,
            > + Clone,
    {
        Connector {
            connector,
            timeout: self.timeout,
            conn_lifetime: self.conn_lifetime,
            conn_keep_alive: self.conn_keep_alive,
            disconnect_timeout: self.disconnect_timeout,
            limit: self.limit,
            ssl: self.ssl,
            _t: PhantomData,
        }
    }
}

impl<T, U> Connector<T, U>
where
    U: AsyncRead + AsyncWrite + fmt::Debug + 'static,
    T: Service<
            Request = TcpConnect<Uri>,
            Response = TcpConnection<Uri, U>,
            Error = actix_connect::ConnectError,
        > + Clone,
{
    /// Connection timeout, i.e. max time to connect to remote host including dns name resolution.
    /// Set to 1 second by default.
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    #[cfg(feature = "ssl")]
    /// Use custom `SslConnector` instance.
    pub fn ssl(mut self, connector: SslConnector) -> Self {
        self.ssl = connector;
        self
    }

    /// Set total number of simultaneous connections per type of scheme.
    ///
    /// If limit is 0, the connector has no limit.
    /// The default limit size is 100.
    pub fn limit(mut self, limit: usize) -> Self {
        self.limit = limit;
        self
    }

    /// Set keep-alive period for opened connection.
    ///
    /// Keep-alive period is the period between connection usage. If
    /// the delay between repeated usages of the same connection
    /// exceeds this period, the connection is closed.
    /// Default keep-alive period is 15 seconds.
    pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
        self.conn_keep_alive = dur;
        self
    }

    /// Set max lifetime period for connection.
    ///
    /// Connection lifetime is max lifetime of any opened connection
    /// until it is closed regardless of keep-alive period.
    /// Default lifetime period is 75 seconds.
    pub fn conn_lifetime(mut self, dur: Duration) -> Self {
        self.conn_lifetime = dur;
        self
    }

    /// Set server connection disconnect timeout in milliseconds.
    ///
    /// Defines a timeout for disconnect connection. If a disconnect procedure does not complete
    /// within this time, the socket get dropped. This timeout affects only secure connections.
    ///
    /// To disable timeout set value to 0.
    ///
    /// By default disconnect timeout is set to 3000 milliseconds.
    pub fn disconnect_timeout(mut self, dur: Duration) -> Self {
        self.disconnect_timeout = dur;
        self
    }

    /// Finish configuration process and create connector service.
    pub fn service(
        self,
    ) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
    {
        #[cfg(not(feature = "ssl"))]
        {
            let connector = TimeoutService::new(
                self.timeout,
                apply_fn(self.connector, |msg: Uri, srv| srv.call(msg.into()))
                    .map(|stream| (stream.into_parts().0, Protocol::Http1)),
            )
            .map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    connector,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
            }
        }
        #[cfg(feature = "ssl")]
        {
            const H2: &[u8] = b"h2";
            use actix_connect::ssl::OpensslConnector;

            let ssl_service = TimeoutService::new(
                self.timeout,
                apply_fn(self.connector.clone(), |msg: Uri, srv| srv.call(msg.into()))
                    .map_err(ConnectError::from)
                    .and_then(
                        OpensslConnector::service(self.ssl)
                            .map_err(ConnectError::from)
                            .map(|stream| {
                                let sock = stream.into_parts().0;
                                let h2 = sock
                                    .get_ref()
                                    .ssl()
                                    .selected_alpn_protocol()
                                    .map(|protos| protos.windows(2).any(|w| w == H2))
                                    .unwrap_or(false);
                                if h2 {
                                    (sock, Protocol::Http2)
                                } else {
                                    (sock, Protocol::Http1)
                                }
                            }),
                    ),
            )
            .map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectError::Timeout,
            });

            let tcp_service = TimeoutService::new(
                self.timeout,
                apply_fn(self.connector.clone(), |msg: Uri, srv| srv.call(msg.into()))
                    .map_err(ConnectError::from)
                    .map(|stream| (stream.into_parts().0, Protocol::Http1)),
            )
            .map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    tcp_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
                ssl_pool: ConnectionPool::new(
                    ssl_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    Some(self.disconnect_timeout),
                    self.limit,
                ),
            }
        }
    }
}

#[cfg(not(feature = "ssl"))]
mod connect_impl {
    use futures::future::{err, Either, FutureResult};
    use futures::Poll;

    use super::*;
    use crate::client::connection::IoConnection;

    pub(crate) struct InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectorError>,
    {
        pub(crate) tcp_pool: ConnectionPool<T, Io>,
    }

    impl<T, Io> Clone for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>
            + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
            }
        }
    }

    impl<T, Io> Service for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectorError>,
    {
        type Request = Uri;
        type Response = IoConnection<Io>;
        type Error = ConnectorError;
        type Future = Either<
            <ConnectionPool<T, Io> as Service>::Future,
            FutureResult<IoConnection<Io>, ConnectorError>,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Uri) -> Self::Future {
            match req.scheme_str() {
                Some("https") | Some("wss") => {
                    Either::B(err(ConnectError::SslIsNotSupported))
                }
                _ => Either::A(self.tcp_pool.call(req)),
            }
        }
    }
}

#[cfg(feature = "ssl")]
mod connect_impl {
    use std::marker::PhantomData;

    use futures::future::{Either, FutureResult};
    use futures::{Async, Future, Poll};

    use super::*;
    use crate::client::connection::EitherConnection;

    pub(crate) struct InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
        T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
    {
        pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
        pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
    }

    impl<T1, T2, Io1, Io2> Clone for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>
            + Clone,
        T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>
            + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
                ssl_pool: self.ssl_pool.clone(),
            }
        }
    }

    impl<T1, T2, Io1, Io2> Service for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
        T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
    {
        type Request = Uri;
        type Response = EitherConnection<Io1, Io2>;
        type Error = ConnectError;
        type Future = Either<
            FutureResult<Self::Response, Self::Error>,
            Either<
                InnerConnectorResponseA<T1, Io1, Io2>,
                InnerConnectorResponseB<T2, Io1, Io2>,
            >,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Uri) -> Self::Future {
            match req.scheme_str() {
                Some("https") | Some("wss") => {
                    Either::B(Either::B(InnerConnectorResponseB {
                        fut: self.ssl_pool.call(req),
                        _t: PhantomData,
                    }))
                }
                _ => Either::B(Either::A(InnerConnectorResponseA {
                    fut: self.tcp_pool.call(req),
                    _t: PhantomData,
                })),
            }
        }
    }

    pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
    {
        fut: <ConnectionPool<T, Io1> as Service>::Future,
        _t: PhantomData<Io2>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
    where
        T: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = EitherConnection<Io1, Io2>;
        type Error = ConnectError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(EitherConnection::A(res))),
            }
        }
    }

    pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
    where
        Io2: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
    {
        fut: <ConnectionPool<T, Io2> as Service>::Future,
        _t: PhantomData<Io1>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
    where
        T: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = EitherConnection<Io1, Io2>;
        type Error = ConnectError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(EitherConnection::B(res))),
            }
        }
    }
}
<commit_msg>fix names<commit_after>use std::fmt;
use std::marker::PhantomData;
use std::time::Duration;

use actix_codec::{AsyncRead, AsyncWrite};
use actix_connect::{
    default_connector, Connect as TcpConnect, Connection as TcpConnection,
};
use actix_service::{apply_fn, Service, ServiceExt};
use actix_utils::timeout::{TimeoutError, TimeoutService};
use http::Uri;
use tokio_tcp::TcpStream;

use super::connection::Connection;
use super::error::ConnectError;
use super::pool::{ConnectionPool, Protocol};

#[cfg(feature = "ssl")]
use openssl::ssl::SslConnector;

#[cfg(not(feature = "ssl"))]
type SslConnector = ();

/// Http client connector builde instance.
/// `Connector` type uses builder-like pattern for connector service construction.
pub struct Connector<T, U> {
    connector: T,
    timeout: Duration,
    conn_lifetime: Duration,
    conn_keep_alive: Duration,
    disconnect_timeout: Duration,
    limit: usize,
    #[allow(dead_code)]
    ssl: SslConnector,
    _t: PhantomData<U>,
}

impl Connector<(), ()> {
    pub fn new() -> Connector<
        impl Service<
                Request = TcpConnect<Uri>,
                Response = TcpConnection<Uri, TcpStream>,
                Error = actix_connect::ConnectError,
            > + Clone,
        TcpStream,
    > {
        let ssl = {
            #[cfg(feature = "ssl")]
            {
                use log::error;
                use openssl::ssl::{SslConnector, SslMethod};

                let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap();
                let _ = ssl
                    .set_alpn_protos(b"\x02h2\x08http/1.1")
                    .map_err(|e| error!("Can not set alpn protocol: {:?}", e));
                ssl.build()
            }
            #[cfg(not(feature = "ssl"))]
            {}
        };

        Connector {
            ssl,
            connector: default_connector(),
            timeout: Duration::from_secs(1),
            conn_lifetime: Duration::from_secs(75),
            conn_keep_alive: Duration::from_secs(15),
            disconnect_timeout: Duration::from_millis(3000),
            limit: 100,
            _t: PhantomData,
        }
    }
}

impl<T, U> Connector<T, U> {
    /// Use custom connector.
    pub fn connector<T1, U1>(self, connector: T1) -> Connector<T1, U1>
    where
        U1: AsyncRead + AsyncWrite + fmt::Debug,
        T1: Service<
                Request = TcpConnect<Uri>,
                Response = TcpConnection<Uri, U1>,
                Error = actix_connect::ConnectError,
            > + Clone,
    {
        Connector {
            connector,
            timeout: self.timeout,
            conn_lifetime: self.conn_lifetime,
            conn_keep_alive: self.conn_keep_alive,
            disconnect_timeout: self.disconnect_timeout,
            limit: self.limit,
            ssl: self.ssl,
            _t: PhantomData,
        }
    }
}

impl<T, U> Connector<T, U>
where
    U: AsyncRead + AsyncWrite + fmt::Debug + 'static,
    T: Service<
            Request = TcpConnect<Uri>,
            Response = TcpConnection<Uri, U>,
            Error = actix_connect::ConnectError,
        > + Clone,
{
    /// Connection timeout, i.e. max time to connect to remote host including dns name resolution.
    /// Set to 1 second by default.
    pub fn timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    #[cfg(feature = "ssl")]
    /// Use custom `SslConnector` instance.
    pub fn ssl(mut self, connector: SslConnector) -> Self {
        self.ssl = connector;
        self
    }

    /// Set total number of simultaneous connections per type of scheme.
    ///
    /// If limit is 0, the connector has no limit.
    /// The default limit size is 100.
    pub fn limit(mut self, limit: usize) -> Self {
        self.limit = limit;
        self
    }

    /// Set keep-alive period for opened connection.
    ///
    /// Keep-alive period is the period between connection usage. If
    /// the delay between repeated usages of the same connection
    /// exceeds this period, the connection is closed.
    /// Default keep-alive period is 15 seconds.
    pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
        self.conn_keep_alive = dur;
        self
    }

    /// Set max lifetime period for connection.
    ///
    /// Connection lifetime is max lifetime of any opened connection
    /// until it is closed regardless of keep-alive period.
    /// Default lifetime period is 75 seconds.
    pub fn conn_lifetime(mut self, dur: Duration) -> Self {
        self.conn_lifetime = dur;
        self
    }

    /// Set server connection disconnect timeout in milliseconds.
    ///
    /// Defines a timeout for disconnect connection. If a disconnect procedure does not complete
    /// within this time, the socket get dropped. This timeout affects only secure connections.
    ///
    /// To disable timeout set value to 0.
    ///
    /// By default disconnect timeout is set to 3000 milliseconds.
    pub fn disconnect_timeout(mut self, dur: Duration) -> Self {
        self.disconnect_timeout = dur;
        self
    }

    /// Finish configuration process and create connector service.
    pub fn service(
        self,
    ) -> impl Service<Request = Uri, Response = impl Connection, Error = ConnectError> + Clone
    {
        #[cfg(not(feature = "ssl"))]
        {
            let connector = TimeoutService::new(
                self.timeout,
                apply_fn(self.connector, |msg: Uri, srv| srv.call(msg.into()))
                    .map(|stream| (stream.into_parts().0, Protocol::Http1)),
            )
            .map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    connector,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
            }
        }
        #[cfg(feature = "ssl")]
        {
            const H2: &[u8] = b"h2";
            use actix_connect::ssl::OpensslConnector;

            let ssl_service = TimeoutService::new(
                self.timeout,
                apply_fn(self.connector.clone(), |msg: Uri, srv| srv.call(msg.into()))
                    .map_err(ConnectError::from)
                    .and_then(
                        OpensslConnector::service(self.ssl)
                            .map_err(ConnectError::from)
                            .map(|stream| {
                                let sock = stream.into_parts().0;
                                let h2 = sock
                                    .get_ref()
                                    .ssl()
                                    .selected_alpn_protocol()
                                    .map(|protos| protos.windows(2).any(|w| w == H2))
                                    .unwrap_or(false);
                                if h2 {
                                    (sock, Protocol::Http2)
                                } else {
                                    (sock, Protocol::Http1)
                                }
                            }),
                    ),
            )
            .map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectError::Timeout,
            });

            let tcp_service = TimeoutService::new(
                self.timeout,
                apply_fn(self.connector.clone(), |msg: Uri, srv| srv.call(msg.into()))
                    .map_err(ConnectError::from)
                    .map(|stream| (stream.into_parts().0, Protocol::Http1)),
            )
            .map_err(|e| match e {
                TimeoutError::Service(e) => e,
                TimeoutError::Timeout => ConnectError::Timeout,
            });

            connect_impl::InnerConnector {
                tcp_pool: ConnectionPool::new(
                    tcp_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    None,
                    self.limit,
                ),
                ssl_pool: ConnectionPool::new(
                    ssl_service,
                    self.conn_lifetime,
                    self.conn_keep_alive,
                    Some(self.disconnect_timeout),
                    self.limit,
                ),
            }
        }
    }
}

#[cfg(not(feature = "ssl"))]
mod connect_impl {
    use futures::future::{err, Either, FutureResult};
    use futures::Poll;

    use super::*;
    use crate::client::connection::IoConnection;

    pub(crate) struct InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>,
    {
        pub(crate) tcp_pool: ConnectionPool<T, Io>,
    }

    impl<T, Io> Clone for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>
            + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
            }
        }
    }

    impl<T, Io> Service for InnerConnector<T, Io>
    where
        Io: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io, Protocol), Error = ConnectError>,
    {
        type Request = Uri;
        type Response = IoConnection<Io>;
        type Error = ConnectError;
        type Future = Either<
            <ConnectionPool<T, Io> as Service>::Future,
            FutureResult<IoConnection<Io>, ConnectError>,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Uri) -> Self::Future {
            match req.scheme_str() {
                Some("https") | Some("wss") => {
                    Either::B(err(ConnectError::SslIsNotSupported))
                }
                _ => Either::A(self.tcp_pool.call(req)),
            }
        }
    }
}

#[cfg(feature = "ssl")]
mod connect_impl {
    use std::marker::PhantomData;

    use futures::future::{Either, FutureResult};
    use futures::{Async, Future, Poll};

    use super::*;
    use crate::client::connection::EitherConnection;

    pub(crate) struct InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
        T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
    {
        pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
        pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
    }

    impl<T1, T2, Io1, Io2> Clone for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>
            + Clone,
        T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>
            + Clone,
    {
        fn clone(&self) -> Self {
            InnerConnector {
                tcp_pool: self.tcp_pool.clone(),
                ssl_pool: self.ssl_pool.clone(),
            }
        }
    }

    impl<T1, T2, Io1, Io2> Service for InnerConnector<T1, T2, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
        T1: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
        T2: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
    {
        type Request = Uri;
        type Response = EitherConnection<Io1, Io2>;
        type Error = ConnectError;
        type Future = Either<
            FutureResult<Self::Response, Self::Error>,
            Either<
                InnerConnectorResponseA<T1, Io1, Io2>,
                InnerConnectorResponseB<T2, Io1, Io2>,
            >,
        >;

        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
            self.tcp_pool.poll_ready()
        }

        fn call(&mut self, req: Uri) -> Self::Future {
            match req.scheme_str() {
                Some("https") | Some("wss") => {
                    Either::B(Either::B(InnerConnectorResponseB {
                        fut: self.ssl_pool.call(req),
                        _t: PhantomData,
                    }))
                }
                _ => Either::B(Either::A(InnerConnectorResponseA {
                    fut: self.tcp_pool.call(req),
                    _t: PhantomData,
                })),
            }
        }
    }

    pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
    where
        Io1: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
    {
        fut: <ConnectionPool<T, Io1> as Service>::Future,
        _t: PhantomData<Io2>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
    where
        T: Service<Request = Uri, Response = (Io1, Protocol), Error = ConnectError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = EitherConnection<Io1, Io2>;
        type Error = ConnectError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(EitherConnection::A(res))),
            }
        }
    }

    pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
    where
        Io2: AsyncRead + AsyncWrite + 'static,
        T: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
    {
        fut: <ConnectionPool<T, Io2> as Service>::Future,
        _t: PhantomData<Io1>,
    }

    impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
    where
        T: Service<Request = Uri, Response = (Io2, Protocol), Error = ConnectError>,
        Io1: AsyncRead + AsyncWrite + 'static,
        Io2: AsyncRead + AsyncWrite + 'static,
    {
        type Item = EitherConnection<Io1, Io2>;
        type Error = ConnectError;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.fut.poll()? {
                Async::NotReady => Ok(Async::NotReady),
                Async::Ready(res) => Ok(Async::Ready(EitherConnection::B(res))),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Array { allowed_types: Box<Vec<FileHeaderSpec>> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

pub trait FileData : Sized {
    fn get_fulltext(&self) -> String;
    fn get_abbrev(&self) -> String;
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            if kname != n {
                // error
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

<commit_msg>Add "Map" type to FileHeaderSpec and FileHeaderData<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Debug)]
pub enum FileHeaderSpec {
    Null,
    Bool,
    Integer,
    UInteger,
    Float,
    Text,
    Key { name: String, value_type: Box<FileHeaderSpec> },
    Map { keys: Vec<FileHeaderSpec> },
    Array { allowed_types: Box<Vec<FileHeaderSpec>> },
}

#[derive(Debug)]
pub enum FileHeaderData {
    Null,
    Bool(bool),
    Integer(i64),
    UInteger(u64),
    Float(f64),
    Text(String),
    Key { name: String, value: Box<FileHeaderData> },
    Map { keys: Vec<FileHeaderData> },
    Array { values: Box<Vec<FileHeaderData>> },
}

pub trait FileData : Sized {
    fn get_fulltext(&self) -> String;
    fn get_abbrev(&self) -> String;
}

impl Display for FileHeaderSpec {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match self {
            &FileHeaderSpec::Null       => write!(fmt, "NULL"),
            &FileHeaderSpec::Bool       => write!(fmt, "Bool"),
            &FileHeaderSpec::Integer    => write!(fmt, "Integer"),
            &FileHeaderSpec::UInteger   => write!(fmt, "UInteger"),
            &FileHeaderSpec::Float      => write!(fmt, "Float"),
            &FileHeaderSpec::Text       => write!(fmt, "Text"),
            &FileHeaderSpec::Key{name: ref n, value_type: ref vt} => {
                write!(fmt, "Key({:?}) -> {:?}", n, vt)
            }
            &FileHeaderSpec::Map{keys: ref ks} => {
                write!(fmt, "Map -> {:?}", ks)
            }
            &FileHeaderSpec::Array{allowed_types: ref at}  => {
                write!(fmt, "Array({:?})", at)
            }
        }
    }

}

pub struct MatchError<'a> {
    summary: String,
    expected: &'a FileHeaderSpec,
    found: &'a FileHeaderData
}

impl<'a> MatchError<'a> {

    pub fn new(s: String,
               ex: &'a FileHeaderSpec,
               found: &'a FileHeaderData) -> MatchError<'a> {
        MatchError {
            summary: s,
            expected: ex,
            found: found,
        }
    }

    pub fn format(&self) -> String {
        format!("MatchError: {:?}\nExpected: {:?}\nFound: {:?}\n",
               self.summary, self.expected, self.found)
    }
}

impl<'a> Error for MatchError<'a> {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

impl<'a> Display for MatchError<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{}", self.format());
        Ok(())
    }

}

pub fn match_header_spec<'a>(spec: &'a FileHeaderSpec, data: &'a FileHeaderData)
    -> Option<MatchError<'a>>
{
    match (spec, data) {
        (&FileHeaderSpec::Null,     &FileHeaderData::Null)           => { }
        (&FileHeaderSpec::Bool,     &FileHeaderData::Bool(_))        => { }
        (&FileHeaderSpec::Integer,  &FileHeaderData::Integer(_))     => { }
        (&FileHeaderSpec::UInteger, &FileHeaderData::UInteger(_))    => { }
        (&FileHeaderSpec::Float,    &FileHeaderData::Float(_))       => { }
        (&FileHeaderSpec::Text,     &FileHeaderData::Text(_))        => { }

        (
            &FileHeaderSpec::Key{name: ref kname, value_type: ref vtype},
            &FileHeaderData::Key{name: ref n, value: ref val}
        ) => {
            if kname != n {
                // error
            }
            return match_header_spec(&*vtype, &*val);
        }

        (
            &FileHeaderSpec::Map{keys: ref sks},
            &FileHeaderData::Map{keys: ref dks}
        ) => {
            for (s, d) in sks.iter().zip(dks.iter()) {
                let res = match_header_spec(s, d);
                if res.is_some() {
                    return res;
                }
            }
        }

        (
            &FileHeaderSpec::Array{allowed_types: ref vtypes},
            &FileHeaderData::Array{values: ref vs}
        ) => {
            for (t, v) in vtypes.iter().zip(vs.iter()) {
                let res = match_header_spec(t, v);
                if res.is_some() {
                    return res;
                }
            }
        }

        (k, v) => {
            return Some(MatchError::new(String::from("Expected type does not match found type"),
                                 k, v
                                 ))
        }
    }
    None
}

<|endoftext|>


<commit_before>//! Vector with dimensions unknown at compile-time.

#[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait.

use std::num::{Zero, One, Algebraic};
use std::rand::Rand;
use std::rand;
use std::vec;
use std::vec::{VecIterator, VecMutIterator};
use std::cmp::ApproxEq;
use std::iter::FromIterator;
use traits::geometry::{Dot, Norm};
use traits::structure::{Iterable, IterableMut};

#[doc(hidden)]
mod metal;

/// Vector with a dimension unknown at compile-time.
#[deriving(Eq, ToStr, Clone)]
pub struct DVec<N> {
    /// Components of the vector. Contains as much elements as the vector dimension.
    at: ~[N]
}

double_dispatch_binop_decl_trait!(DVec, DVecMulRhs)
double_dispatch_binop_decl_trait!(DVec, DVecDivRhs)
double_dispatch_binop_decl_trait!(DVec, DVecAddRhs)
double_dispatch_binop_decl_trait!(DVec, DVecSubRhs)

mul_redispatch_impl!(DVec, DVecMulRhs)
div_redispatch_impl!(DVec, DVecDivRhs)
add_redispatch_impl!(DVec, DVecAddRhs)
sub_redispatch_impl!(DVec, DVecSubRhs)

impl<N: Zero + Clone> DVec<N> {
    /// Builds a vector filled with zeros.
    ///
    /// # Arguments
    ///   * `dim` - The dimension of the vector.
    #[inline]
    pub fn new_zeros(dim: uint) -> DVec<N> {
        DVec::from_elem(dim, Zero::zero())
    }

    /// Tests if all components of the vector are zeroes.
    #[inline]
    pub fn is_zero(&self) -> bool {
        self.at.iter().all(|e| e.is_zero())
    }
}

impl<N: Clone> DVec<N> {
    /// Indexing without bounds checking.
    pub unsafe fn at_fast(&self, i: uint) -> N {
        vec::raw::get(self.at, i)
    }
}

impl<N: One + Clone> DVec<N> {
    /// Builds a vector filled with ones.
    ///
    /// # Arguments
    ///   * `dim` - The dimension of the vector.
    #[inline]
    pub fn new_ones(dim: uint) -> DVec<N> {
        DVec::from_elem(dim, One::one())
    }
}

impl<N: Rand> DVec<N> {
    /// Builds a vector filled with random values.
    #[inline]
    pub fn new_random(dim: uint) -> DVec<N> {
        DVec::from_fn(dim, |_| rand::random())
    }
}

impl<N> DVec<N> {
    /// Creates an uninitialized vec.
    #[inline]
    pub unsafe fn new_uninitialized(dim: uint) -> DVec<N> {
        let mut vec = vec::with_capacity(dim);
        vec::raw::set_len(&mut vec, dim);

        DVec {
            at: vec
        }
    }

    #[inline]
    pub unsafe fn set_fast(&mut self, i: uint, val: N) {
        *self.at.unsafe_mut_ref(i) = val
    }

    #[inline]
    pub fn to_vec(self) -> ~[N] {
        self.at
    }
}

impl<N: Clone> DVec<N> {
    /// Builds a vector filled with a constant.
    #[inline]
    pub fn from_elem(dim: uint, elem: N) -> DVec<N> {
        DVec { at: vec::from_elem(dim, elem) }
    }

    /// Builds a vector filled with the components provided by a vector.
    ///
    /// The vector must have at least `dim` elements.
    #[inline]
    pub fn from_vec(dim: uint, vec: &[N]) -> DVec<N> {
        assert!(dim <= vec.len());

        DVec {
            at: vec.slice_to(dim).to_owned()
        }
    }
}

impl<N> DVec<N> {
    /// Builds a vector filled with the result of a function.
    #[inline(always)]
    pub fn from_fn(dim: uint, f: &fn(uint) -> N) -> DVec<N> {
        DVec { at: vec::from_fn(dim, |i| f(i)) }
    }
}

impl<N> Container for DVec<N> {
    #[inline]
    fn len(&self) -> uint {
        self.at.len()
    }
}

impl<N> Iterable<N> for DVec<N> {
    #[inline]
    fn iter<'l>(&'l self) -> VecIterator<'l, N> {
        self.at.iter()
    }
}

impl<N> IterableMut<N> for DVec<N> {
    #[inline]
    fn mut_iter<'l>(&'l mut self) -> VecMutIterator<'l, N> {
        self.at.mut_iter()
    }
}

impl<N> FromIterator<N> for DVec<N> {
    #[inline]
    fn from_iterator<I: Iterator<N>>(mut param: &mut I) -> DVec<N> {
        let mut res = DVec { at: ~[] };

        for e in param {
            res.at.push(e)
        }

        res
    }
}

impl<N: Clone + Num + Algebraic + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N> {
    /// Computes the canonical basis for the given dimension. A canonical basis is a set of
    /// vectors, mutually orthogonal, with all its component equal to 0.0 exept one which is equal
    /// to 1.0.
    pub fn canonical_basis_with_dim(dim: uint) -> ~[DVec<N>] {
        let mut res : ~[DVec<N>] = ~[];

        for i in range(0u, dim) {
            let mut basis_element : DVec<N> = DVec::new_zeros(dim);

            basis_element.at[i] = One::one();

            res.push(basis_element);
        }

        res
    }

    /// Computes a basis of the space orthogonal to the vector. If the input vector is of dimension
    /// `n`, this will return `n - 1` vectors.
    pub fn orthogonal_subspace_basis(&self) -> ~[DVec<N>] {
        // compute the basis of the orthogonal subspace using Gram-Schmidt
        // orthogonalization algorithm
        let     dim              = self.at.len();
        let mut res : ~[DVec<N>] = ~[];

        for i in range(0u, dim) {
            let mut basis_element : DVec<N> = DVec::new_zeros(self.at.len());

            basis_element.at[i] = One::one();

            if res.len() == dim - 1 {
                break;
            }

            let mut elt = basis_element.clone();

            elt = elt - self * basis_element.dot(self);

            for v in res.iter() {
                elt = elt - v * elt.dot(v)
            };

            if !elt.sqnorm().approx_eq(&Zero::zero()) {
                res.push(Norm::normalize_cpy(&elt));
            }
        }

        assert!(res.len() == dim - 1);

        res
    }
}

impl<N: Add<N, N>> DVecAddRhs<N, DVec<N>> for DVec<N> {
    #[inline]
    fn binop(left: &DVec<N>, right: &DVec<N>) -> DVec<N> {
        assert!(left.at.len() == right.at.len());
        DVec {
            at: left.at.iter().zip(right.at.iter()).map(|(a, b)| *a + *b).collect()
        }
    }
}

impl<N: Sub<N, N>> DVecSubRhs<N, DVec<N>> for DVec<N> {
    #[inline]
    fn binop(left: &DVec<N>, right: &DVec<N>) -> DVec<N> {
        assert!(left.at.len() == right.at.len());
        DVec {
            at: left.at.iter().zip(right.at.iter()).map(|(a, b)| *a - *b).collect()
        }
    }
}

impl<N: Neg<N>> Neg<DVec<N>> for DVec<N> {
    #[inline]
    fn neg(&self) -> DVec<N> {
        DVec { at: self.at.iter().map(|a| -a).collect() }
    }
}

impl<N: Num + Clone> Dot<N> for DVec<N> {
    #[inline]
    fn dot(&self, other: &DVec<N>) -> N {
        assert!(self.at.len() == other.at.len());

        let mut res: N = Zero::zero();

        for i in range(0u, self.at.len()) {
            res = res + unsafe { self.at_fast(i) * other.at_fast(i) };
        }

        res
    }

    #[inline]
    fn sub_dot(&self, a: &DVec<N>, b: &DVec<N>) -> N {
        let mut res: N = Zero::zero();

        for i in range(0u, self.at.len()) {
            res = res + unsafe { (self.at_fast(i) - a.at_fast(i)) * b.at_fast(i) };
        }

        res
    }
}

impl<N: Num + Algebraic + Clone> Norm<N> for DVec<N> {
    #[inline]
    fn sqnorm(&self) -> N {
        self.dot(self)
    }

    #[inline]
    fn norm(&self) -> N {
        self.sqnorm().sqrt()
    }

    #[inline]
    fn normalize_cpy(v: &DVec<N>) -> DVec<N> {
        let mut res : DVec<N> = v.clone();

        res.normalize();

        res
    }

    #[inline]
    fn normalize(&mut self) -> N {
        let l = self.norm();

        for i in range(0u, self.at.len()) {
            self.at[i] = self.at[i] / l;
        }

        l
    }
}

impl<N: ApproxEq<N>> ApproxEq<N> for DVec<N> {
    #[inline]
    fn approx_epsilon() -> N {
        fail!("Fix me.")
        // let res: N = ApproxEq::<N>::approx_epsilon();

        // res
    }

    #[inline]
    fn approx_eq(&self, other: &DVec<N>) -> bool {
        let mut zip = self.at.iter().zip(other.at.iter());

        do zip.all |(a, b)| {
            a.approx_eq(b)
        }
    }

    #[inline]
    fn approx_eq_eps(&self, other: &DVec<N>, epsilon: &N) -> bool {
        let mut zip = self.at.iter().zip(other.at.iter());

        do zip.all |(a, b)| {
            a.approx_eq_eps(b, epsilon)
        }
    }
}

macro_rules! scalar_mul_impl (
    ($n: ident) => (
        impl DVecMulRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a * *right).collect() }
            }
        }
    )
)

macro_rules! scalar_div_impl (
    ($n: ident) => (
        impl DVecDivRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a / *right).collect() }
            }
        }
    )
)

macro_rules! scalar_add_impl (
    ($n: ident) => (
        impl DVecAddRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a + *right).collect() }
            }
        }
    )
)

macro_rules! scalar_sub_impl (
    ($n: ident) => (
        impl DVecSubRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a - *right).collect() }
            }
        }
    )
)

scalar_mul_impl!(f64)
scalar_mul_impl!(f32)
scalar_mul_impl!(u64)
scalar_mul_impl!(u32)
scalar_mul_impl!(u16)
scalar_mul_impl!(u8)
scalar_mul_impl!(i64)
scalar_mul_impl!(i32)
scalar_mul_impl!(i16)
scalar_mul_impl!(i8)
scalar_mul_impl!(uint)
scalar_mul_impl!(int)

scalar_div_impl!(f64)
scalar_div_impl!(f32)
scalar_div_impl!(u64)
scalar_div_impl!(u32)
scalar_div_impl!(u16)
scalar_div_impl!(u8)
scalar_div_impl!(i64)
scalar_div_impl!(i32)
scalar_div_impl!(i16)
scalar_div_impl!(i8)
scalar_div_impl!(uint)
scalar_div_impl!(int)

scalar_add_impl!(f64)
scalar_add_impl!(f32)
scalar_add_impl!(u64)
scalar_add_impl!(u32)
scalar_add_impl!(u16)
scalar_add_impl!(u8)
scalar_add_impl!(i64)
scalar_add_impl!(i32)
scalar_add_impl!(i16)
scalar_add_impl!(i8)
scalar_add_impl!(uint)
scalar_add_impl!(int)

scalar_sub_impl!(f64)
scalar_sub_impl!(f32)
scalar_sub_impl!(u64)
scalar_sub_impl!(u32)
scalar_sub_impl!(u16)
scalar_sub_impl!(u8)
scalar_sub_impl!(i64)
scalar_sub_impl!(i32)
scalar_sub_impl!(i16)
scalar_sub_impl!(i8)
scalar_sub_impl!(uint)
scalar_sub_impl!(int)
<commit_msg>Add methods to access a DVec<N> as a &[N].<commit_after>//! Vector with dimensions unknown at compile-time.

#[allow(missing_doc)]; // we hide doc to not have to document the $trhs double dispatch trait.

use std::num::{Zero, One, Algebraic};
use std::rand::Rand;
use std::rand;
use std::vec;
use std::vec::{VecIterator, VecMutIterator};
use std::cmp::ApproxEq;
use std::iter::FromIterator;
use traits::geometry::{Dot, Norm};
use traits::structure::{Iterable, IterableMut};

#[doc(hidden)]
mod metal;

/// Vector with a dimension unknown at compile-time.
#[deriving(Eq, ToStr, Clone)]
pub struct DVec<N> {
    /// Components of the vector. Contains as much elements as the vector dimension.
    at: ~[N]
}

double_dispatch_binop_decl_trait!(DVec, DVecMulRhs)
double_dispatch_binop_decl_trait!(DVec, DVecDivRhs)
double_dispatch_binop_decl_trait!(DVec, DVecAddRhs)
double_dispatch_binop_decl_trait!(DVec, DVecSubRhs)

mul_redispatch_impl!(DVec, DVecMulRhs)
div_redispatch_impl!(DVec, DVecDivRhs)
add_redispatch_impl!(DVec, DVecAddRhs)
sub_redispatch_impl!(DVec, DVecSubRhs)

impl<N: Zero + Clone> DVec<N> {
    /// Builds a vector filled with zeros.
    ///
    /// # Arguments
    ///   * `dim` - The dimension of the vector.
    #[inline]
    pub fn new_zeros(dim: uint) -> DVec<N> {
        DVec::from_elem(dim, Zero::zero())
    }

    /// Tests if all components of the vector are zeroes.
    #[inline]
    pub fn is_zero(&self) -> bool {
        self.at.iter().all(|e| e.is_zero())
    }
}

impl<N: Clone> DVec<N> {
    /// Indexing without bounds checking.
    pub unsafe fn at_fast(&self, i: uint) -> N {
        vec::raw::get(self.at, i)
    }
}

impl<N: One + Clone> DVec<N> {
    /// Builds a vector filled with ones.
    ///
    /// # Arguments
    ///   * `dim` - The dimension of the vector.
    #[inline]
    pub fn new_ones(dim: uint) -> DVec<N> {
        DVec::from_elem(dim, One::one())
    }
}

impl<N: Rand> DVec<N> {
    /// Builds a vector filled with random values.
    #[inline]
    pub fn new_random(dim: uint) -> DVec<N> {
        DVec::from_fn(dim, |_| rand::random())
    }
}

impl<N> DVec<N> {
    /// Creates an uninitialized vec.
    #[inline]
    pub unsafe fn new_uninitialized(dim: uint) -> DVec<N> {
        let mut vec = vec::with_capacity(dim);
        vec::raw::set_len(&mut vec, dim);

        DVec {
            at: vec
        }
    }

    #[inline]
    pub unsafe fn set_fast(&mut self, i: uint, val: N) {
        *self.at.unsafe_mut_ref(i) = val
    }

    #[inline]
    pub fn as_vec<'r>(&'r self) -> &'r [N] {
        let data: &'r [N] = self.at;

        data
    }

    #[inline]
    pub fn as_mut_vec<'r>(&'r mut self) -> &'r mut [N] {
        let data: &'r mut [N] = self.at;

        data
    }

    #[inline]
    pub fn to_vec(self) -> ~[N] {
        self.at
    }
}

impl<N: Clone> DVec<N> {
    /// Builds a vector filled with a constant.
    #[inline]
    pub fn from_elem(dim: uint, elem: N) -> DVec<N> {
        DVec { at: vec::from_elem(dim, elem) }
    }

    /// Builds a vector filled with the components provided by a vector.
    ///
    /// The vector must have at least `dim` elements.
    #[inline]
    pub fn from_vec(dim: uint, vec: &[N]) -> DVec<N> {
        assert!(dim <= vec.len());

        DVec {
            at: vec.slice_to(dim).to_owned()
        }
    }
}

impl<N> DVec<N> {
    /// Builds a vector filled with the result of a function.
    #[inline(always)]
    pub fn from_fn(dim: uint, f: &fn(uint) -> N) -> DVec<N> {
        DVec { at: vec::from_fn(dim, |i| f(i)) }
    }
}

impl<N> Container for DVec<N> {
    #[inline]
    fn len(&self) -> uint {
        self.at.len()
    }
}

impl<N> Iterable<N> for DVec<N> {
    #[inline]
    fn iter<'l>(&'l self) -> VecIterator<'l, N> {
        self.at.iter()
    }
}

impl<N> IterableMut<N> for DVec<N> {
    #[inline]
    fn mut_iter<'l>(&'l mut self) -> VecMutIterator<'l, N> {
        self.at.mut_iter()
    }
}

impl<N> FromIterator<N> for DVec<N> {
    #[inline]
    fn from_iterator<I: Iterator<N>>(mut param: &mut I) -> DVec<N> {
        let mut res = DVec { at: ~[] };

        for e in param {
            res.at.push(e)
        }

        res
    }
}

impl<N: Clone + Num + Algebraic + ApproxEq<N> + DVecMulRhs<N, DVec<N>>> DVec<N> {
    /// Computes the canonical basis for the given dimension. A canonical basis is a set of
    /// vectors, mutually orthogonal, with all its component equal to 0.0 exept one which is equal
    /// to 1.0.
    pub fn canonical_basis_with_dim(dim: uint) -> ~[DVec<N>] {
        let mut res : ~[DVec<N>] = ~[];

        for i in range(0u, dim) {
            let mut basis_element : DVec<N> = DVec::new_zeros(dim);

            basis_element.at[i] = One::one();

            res.push(basis_element);
        }

        res
    }

    /// Computes a basis of the space orthogonal to the vector. If the input vector is of dimension
    /// `n`, this will return `n - 1` vectors.
    pub fn orthogonal_subspace_basis(&self) -> ~[DVec<N>] {
        // compute the basis of the orthogonal subspace using Gram-Schmidt
        // orthogonalization algorithm
        let     dim              = self.at.len();
        let mut res : ~[DVec<N>] = ~[];

        for i in range(0u, dim) {
            let mut basis_element : DVec<N> = DVec::new_zeros(self.at.len());

            basis_element.at[i] = One::one();

            if res.len() == dim - 1 {
                break;
            }

            let mut elt = basis_element.clone();

            elt = elt - self * basis_element.dot(self);

            for v in res.iter() {
                elt = elt - v * elt.dot(v)
            };

            if !elt.sqnorm().approx_eq(&Zero::zero()) {
                res.push(Norm::normalize_cpy(&elt));
            }
        }

        assert!(res.len() == dim - 1);

        res
    }
}

impl<N: Add<N, N>> DVecAddRhs<N, DVec<N>> for DVec<N> {
    #[inline]
    fn binop(left: &DVec<N>, right: &DVec<N>) -> DVec<N> {
        assert!(left.at.len() == right.at.len());
        DVec {
            at: left.at.iter().zip(right.at.iter()).map(|(a, b)| *a + *b).collect()
        }
    }
}

impl<N: Sub<N, N>> DVecSubRhs<N, DVec<N>> for DVec<N> {
    #[inline]
    fn binop(left: &DVec<N>, right: &DVec<N>) -> DVec<N> {
        assert!(left.at.len() == right.at.len());
        DVec {
            at: left.at.iter().zip(right.at.iter()).map(|(a, b)| *a - *b).collect()
        }
    }
}

impl<N: Neg<N>> Neg<DVec<N>> for DVec<N> {
    #[inline]
    fn neg(&self) -> DVec<N> {
        DVec { at: self.at.iter().map(|a| -a).collect() }
    }
}

impl<N: Num + Clone> Dot<N> for DVec<N> {
    #[inline]
    fn dot(&self, other: &DVec<N>) -> N {
        assert!(self.at.len() == other.at.len());

        let mut res: N = Zero::zero();

        for i in range(0u, self.at.len()) {
            res = res + unsafe { self.at_fast(i) * other.at_fast(i) };
        }

        res
    }

    #[inline]
    fn sub_dot(&self, a: &DVec<N>, b: &DVec<N>) -> N {
        let mut res: N = Zero::zero();

        for i in range(0u, self.at.len()) {
            res = res + unsafe { (self.at_fast(i) - a.at_fast(i)) * b.at_fast(i) };
        }

        res
    }
}

impl<N: Num + Algebraic + Clone> Norm<N> for DVec<N> {
    #[inline]
    fn sqnorm(&self) -> N {
        self.dot(self)
    }

    #[inline]
    fn norm(&self) -> N {
        self.sqnorm().sqrt()
    }

    #[inline]
    fn normalize_cpy(v: &DVec<N>) -> DVec<N> {
        let mut res : DVec<N> = v.clone();

        res.normalize();

        res
    }

    #[inline]
    fn normalize(&mut self) -> N {
        let l = self.norm();

        for i in range(0u, self.at.len()) {
            self.at[i] = self.at[i] / l;
        }

        l
    }
}

impl<N: ApproxEq<N>> ApproxEq<N> for DVec<N> {
    #[inline]
    fn approx_epsilon() -> N {
        fail!("Fix me.")
        // let res: N = ApproxEq::<N>::approx_epsilon();

        // res
    }

    #[inline]
    fn approx_eq(&self, other: &DVec<N>) -> bool {
        let mut zip = self.at.iter().zip(other.at.iter());

        do zip.all |(a, b)| {
            a.approx_eq(b)
        }
    }

    #[inline]
    fn approx_eq_eps(&self, other: &DVec<N>, epsilon: &N) -> bool {
        let mut zip = self.at.iter().zip(other.at.iter());

        do zip.all |(a, b)| {
            a.approx_eq_eps(b, epsilon)
        }
    }
}

macro_rules! scalar_mul_impl (
    ($n: ident) => (
        impl DVecMulRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a * *right).collect() }
            }
        }
    )
)

macro_rules! scalar_div_impl (
    ($n: ident) => (
        impl DVecDivRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a / *right).collect() }
            }
        }
    )
)

macro_rules! scalar_add_impl (
    ($n: ident) => (
        impl DVecAddRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a + *right).collect() }
            }
        }
    )
)

macro_rules! scalar_sub_impl (
    ($n: ident) => (
        impl DVecSubRhs<$n, DVec<$n>> for $n {
            #[inline]
            fn binop(left: &DVec<$n>, right: &$n) -> DVec<$n> {
                DVec { at: left.at.iter().map(|a| a - *right).collect() }
            }
        }
    )
)

scalar_mul_impl!(f64)
scalar_mul_impl!(f32)
scalar_mul_impl!(u64)
scalar_mul_impl!(u32)
scalar_mul_impl!(u16)
scalar_mul_impl!(u8)
scalar_mul_impl!(i64)
scalar_mul_impl!(i32)
scalar_mul_impl!(i16)
scalar_mul_impl!(i8)
scalar_mul_impl!(uint)
scalar_mul_impl!(int)

scalar_div_impl!(f64)
scalar_div_impl!(f32)
scalar_div_impl!(u64)
scalar_div_impl!(u32)
scalar_div_impl!(u16)
scalar_div_impl!(u8)
scalar_div_impl!(i64)
scalar_div_impl!(i32)
scalar_div_impl!(i16)
scalar_div_impl!(i8)
scalar_div_impl!(uint)
scalar_div_impl!(int)

scalar_add_impl!(f64)
scalar_add_impl!(f32)
scalar_add_impl!(u64)
scalar_add_impl!(u32)
scalar_add_impl!(u16)
scalar_add_impl!(u8)
scalar_add_impl!(i64)
scalar_add_impl!(i32)
scalar_add_impl!(i16)
scalar_add_impl!(i8)
scalar_add_impl!(uint)
scalar_add_impl!(int)

scalar_sub_impl!(f64)
scalar_sub_impl!(f32)
scalar_sub_impl!(u64)
scalar_sub_impl!(u32)
scalar_sub_impl!(u16)
scalar_sub_impl!(u8)
scalar_sub_impl!(i64)
scalar_sub_impl!(i32)
scalar_sub_impl!(i16)
scalar_sub_impl!(i8)
scalar_sub_impl!(uint)
scalar_sub_impl!(int)
<|endoftext|>


<commit_before>use std::io;
use std::mem;
use std::os::windows::io::{RawHandle, AsRawHandle};

use winapi::{CHAR, DWORD, HANDLE, STD_OUTPUT_HANDLE,
             CONSOLE_SCREEN_BUFFER_INFO, COORD};
use kernel32::{GetStdHandle, GetConsoleScreenBufferInfo,
               GetConsoleMode, SetConsoleCursorPosition,
               FillConsoleOutputCharacterA};

use term::Term;

pub const DEFAULT_WIDTH: u16 = 79;

pub fn is_a_terminal(out: &Term) -> bool {
    unsafe {
        let mut out = 0;
        GetConsoleMode(out.as_raw_handle(), &mut out) != 0
    }
}

pub fn terminal_size() -> Option<(u16, u16)> {
    let hand = STD_OUTPUT_HANDLE as RawHandle;
    if let Some((_, csbi)) = get_console_screen_buffer_info(hand) {
        Some(((csbi.srWindow.Right - csbi.srWindow.Left) as u16,
              (csbi.srWindow.Bottom - csbi.srWindow.Top) as u16))
    } else {
        None
    }
}

pub fn move_cursor_up(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y - n as i16,
            });
        }
    }
    Ok(())
}

pub fn move_cursor_down(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y + n as i16,
            });
        }
    }
    Ok(())
}

pub fn clear_line(out: &Term) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            let width = csbi.srWindow.Right - csbi.srWindow.Left;
            let pos = COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y,
            };
            let mut written = 0;
            FillConsoleOutputCharacterA(hand, b' ' as CHAR,
                                        width as DWORD, pos, &mut written);
        }
    }
    Ok(())
}

fn get_console_screen_buffer_info(hand: HANDLE)
    -> Option<(HANDLE, CONSOLE_SCREEN_BUFFER_INFO)>
{
    let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
    match unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } {
        0 => None,
        _ => Some((hand, csbi)),
    }
}
<commit_msg>Fixed windows build<commit_after>use std::io;
use std::mem;
use std::os::windows::io::{RawHandle, AsRawHandle};

use winapi::{CHAR, DWORD, HANDLE, STD_OUTPUT_HANDLE,
             CONSOLE_SCREEN_BUFFER_INFO, COORD};
use kernel32::{GetStdHandle, GetConsoleScreenBufferInfo,
               GetConsoleMode, SetConsoleCursorPosition,
               FillConsoleOutputCharacterA};

use term::Term;

pub const DEFAULT_WIDTH: u16 = 79;

pub fn is_a_terminal(out: &Term) -> bool {
    unsafe {
        let mut tmp = 0;
        GetConsoleMode(out.as_raw_handle(), &mut tmp) != 0
    }
}

pub fn terminal_size() -> Option<(u16, u16)> {
    let hand = STD_OUTPUT_HANDLE as RawHandle;
    if let Some((_, csbi)) = get_console_screen_buffer_info(hand) {
        Some(((csbi.srWindow.Right - csbi.srWindow.Left) as u16,
              (csbi.srWindow.Bottom - csbi.srWindow.Top) as u16))
    } else {
        None
    }
}

pub fn move_cursor_up(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y - n as i16,
            });
        }
    }
    Ok(())
}

pub fn move_cursor_down(out: &Term, n: usize) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            SetConsoleCursorPosition(hand, COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y + n as i16,
            });
        }
    }
    Ok(())
}

pub fn clear_line(out: &Term) -> io::Result<()> {
    if let Some((hand, csbi)) = get_console_screen_buffer_info(out.as_raw_handle()) {
        unsafe {
            let width = csbi.srWindow.Right - csbi.srWindow.Left;
            let pos = COORD {
                X: 0,
                Y: csbi.dwCursorPosition.Y,
            };
            let mut written = 0;
            FillConsoleOutputCharacterA(hand, b' ' as CHAR,
                                        width as DWORD, pos, &mut written);
        }
    }
    Ok(())
}

fn get_console_screen_buffer_info(hand: HANDLE)
    -> Option<(HANDLE, CONSOLE_SCREEN_BUFFER_INFO)>
{
    let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() };
    match unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } {
        0 => None,
        _ => Some((hand, csbi)),
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
  use strain::mutable::Event;
  use strain::mutable::Strain;
  use strain::branchable::Branchable;
  use strain::state::{State,Mutable};
  use strain::strain;
  use strain::strain::*;
  use strain::mutable::*;
  use strain::errors::{Errors, PreConditionNotMet, PostConditionNotMet};

  #[deriving(Clone)]
  struct Value {
    x: int
  }
  impl State for Value {}

  #[deriving(Clone)]
  struct Counter {
    count: Value
  }

  impl strain::Strain<Value> for Counter {
    fn new(state: Value) -> ~Counter {
      ~Counter { count: state }
    }
  }

  impl Mutable<Value> for Counter {
    fn state<'a>(&'a mut self) -> &'a mut Value {
      &'a mut self.count
    }
  }

  struct Increment;
  struct Decrement;

  impl Event<Value> for Increment {
    fn precondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 0 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, count: &mut Value) -> Result<(), Errors>  {
      count.x = count.x + 1;
      Ok(())
    }

    fn postcondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }
  }

  impl Event<Value> for Decrement {
    fn precondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 1 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, count: &mut Value) -> Result<(), Errors>  {
      count.x = count.x - 1;
      Ok(())
    }

    fn postcondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }

  }

  #[test]
  fn test_state_changes() {
    let mut strain: Counter = Counter { count: Value { x: 0 } };
    let res = strain.evolve(&Increment).and_then(|_| {
      strain.evolve(&Increment).and_then(|_| {
        strain.evolve(&Decrement)
      })
    });

    assert!(res.is_ok());
    assert_eq!(strain.count.x, 1);
  }

  #[test]
  fn test_unmet_pre_condition() {
    let mut strain: Counter = Counter { count: Value { x: -1 } };
    let res = strain.evolve(&Increment);
    assert!(res.is_err());
    assert_eq!(strain.count.x, -1);
  }

  #[test]
  fn test_branch() {
    let mut strain: Counter = Counter { count: Value { x: 0 } };
    let res = strain.evolve(&Increment);
    assert!(res.is_ok());
    let mut branch = strain.branch();
    let res1 = strain.evolve(&Increment);
    let res2 = branch.evolve(&Decrement);
    assert!(res1.is_ok());
    assert!(res2.is_ok());
    assert_eq!(strain.count.x, 2);
    assert_eq!(branch.count.x, 0);
  }
}
<commit_msg>Make mutable tests warning free<commit_after>#[cfg(test)]
mod tests {
  use strain::mutable::Event;
  use strain::mutable::Strain;
  use strain::branchable::Branchable;
  use strain::state::{State,Mutable};
  use strain::strain;
  use strain::errors::{Errors, PreConditionNotMet, PostConditionNotMet};

  #[deriving(Clone)]
  struct Value {
    x: int
  }
  impl State for Value {}

  #[deriving(Clone)]
  struct Counter {
    count: Value
  }

  impl strain::Strain<Value> for Counter {
    fn new(state: Value) -> ~Counter {
      ~Counter { count: state }
    }
  }

  impl Mutable<Value> for Counter {
    fn state<'a>(&'a mut self) -> &'a mut Value {
      &'a mut self.count
    }
  }

  struct Increment;
  struct Decrement;

  impl Event<Value> for Increment {
    fn precondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 0 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, count: &mut Value) -> Result<(), Errors>  {
      count.x = count.x + 1;
      Ok(())
    }

    fn postcondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }
  }

  impl Event<Value> for Decrement {
    fn precondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 1 {
        Err(PreConditionNotMet(~"I cannot count to negatives"))
      } else {
        Ok(())
      }
    }

    fn action(&self, count: &mut Value) -> Result<(), Errors>  {
      count.x = count.x - 1;
      Ok(())
    }

    fn postcondition(&self, count: &Value) -> Result<(), Errors> {
      if count.x < 0 {
        Err(PostConditionNotMet(~"I shouldn't have counted to negatives"))
      } else {
        Ok(())
      }
    }

  }

  #[test]
  fn test_state_changes() {
    let mut strain: Counter = Counter { count: Value { x: 0 } };
    let res = strain.evolve(&Increment).and_then(|_| {
      strain.evolve(&Increment).and_then(|_| {
        strain.evolve(&Decrement)
      })
    });

    assert!(res.is_ok());
    assert_eq!(strain.count.x, 1);
  }

  #[test]
  fn test_unmet_pre_condition() {
    let mut strain: Counter = Counter { count: Value { x: -1 } };
    let res = strain.evolve(&Increment);
    assert!(res.is_err());
    assert_eq!(strain.count.x, -1);
  }

  #[test]
  fn test_branch() {
    let mut strain: Counter = Counter { count: Value { x: 0 } };
    let res = strain.evolve(&Increment);
    assert!(res.is_ok());
    let mut branch = strain.branch();
    let res1 = strain.evolve(&Increment);
    let res2 = branch.evolve(&Decrement);
    assert!(res1.is_ok());
    assert!(res2.is_ok());
    assert_eq!(strain.count.x, 2);
    assert_eq!(branch.count.x, 0);
  }
}
<|endoftext|>


<commit_before>//! For either helper, see [`Either`].

use bytes::Bytes;
use futures_core::future::LocalBoxFuture;
use futures_util::{FutureExt as _, TryFutureExt as _};

use crate::{
    dev,
    web::{Form, Json},
    Error, FromRequest, HttpRequest, HttpResponse, Responder,
};

/// Combines two extractor or responder types into a single type.
///
/// Can be converted to and from an [`either::Either`].
///
/// # Extractor
/// Provides a mechanism for trying two extractors, a primary and a fallback. Useful for
/// "polymorphic payloads" where, for example, a form might be JSON or URL encoded.
///
/// It is important to note that this extractor, by necessity, buffers the entire request payload
/// as part of its implementation. Though, it does respect any `PayloadConfig` maximum size limits.
///
/// ```
/// use actix_web::{post, web, Either};
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Info {
///     name: String,
/// }
///
/// // handler that accepts form as JSON or form-urlencoded.
/// #[post("/")]
/// async fn index(form: Either<web::Json<Info>, web::Form<Info>>) -> String {
///     let name: String = match form {
///         Either::Left(json) => json.name.to_owned(),
///         Either::Right(form) => form.name.to_owned(),
///     };
///
///     format!("Welcome {}!", name)
/// }
/// ```
///
/// # Responder
/// It may be desireable to use a concrete type for a response with multiple branches. As long as
/// both types implement `Responder`, so will the `Either` type, enabling it to be used as a
/// handler's return type.
///
/// All properties of a response are determined by the Responder branch returned.
///
/// ```
/// use actix_web::{get, Either, Error, HttpResponse};
///
/// #[get("/")]
/// async fn index() -> Either<&'static str, Result<HttpResponse, Error>> {
///     if 1 == 2 {
///         // respond with Left variant
///         Either::Left("Bad data")
///     } else {
///         // respond with Right variant
///         Either::Right(
///             Ok(HttpResponse::Ok()
///                 .content_type(mime::TEXT_HTML)
///                 .body("<p>Hello!</p>"))
///         )
///     }
/// }
/// ```
#[derive(Debug, PartialEq)]
pub enum Either<L, R> {
    /// A value of type `L`.
    Left(L),

    /// A value of type `R`.
    Right(R),
}

impl<T> Either<Form<T>, Json<T>> {
    pub fn into_inner(self) -> T {
        match self {
            Either::Left(form) => form.into_inner(),
            Either::Right(form) => form.into_inner(),
        }
    }
}

impl<T> Either<Json<T>, Form<T>> {
    pub fn into_inner(self) -> T {
        match self {
            Either::Left(form) => form.into_inner(),
            Either::Right(form) => form.into_inner(),
        }
    }
}

impl<L, R> From<either::Either<L, R>> for Either<L, R> {
    fn from(val: either::Either<L, R>) -> Self {
        match val {
            either::Either::Left(l) => Either::Left(l),
            either::Either::Right(r) => Either::Right(r),
        }
    }
}

impl<L, R> From<Either<L, R>> for either::Either<L, R> {
    fn from(val: Either<L, R>) -> Self {
        match val {
            Either::Left(l) => either::Either::Left(l),
            Either::Right(r) => either::Either::Right(r),
        }
    }
}

#[cfg(test)]
impl<L, R> Either<L, R> {
    pub(self) fn unwrap_left(self) -> L {
        match self {
            Either::Left(data) => data,
            Either::Right(_) => {
                panic!("Cannot unwrap Left branch. Either contains an `R` type.")
            }
        }
    }

    pub(self) fn unwrap_right(self) -> R {
        match self {
            Either::Left(_) => {
                panic!("Cannot unwrap Right branch. Either contains an `L` type.")
            }
            Either::Right(data) => data,
        }
    }
}

/// See [here](#responder) for example of usage as a handler return type.
impl<L, R> Responder for Either<L, R>
where
    L: Responder,
    R: Responder,
{
    fn respond_to(self, req: &HttpRequest) -> HttpResponse {
        match self {
            Either::Left(a) => a.respond_to(req),
            Either::Right(b) => b.respond_to(req),
        }
    }
}

/// A composite error resulting from failure to extract an `Either<L, R>`.
///
/// The implementation of `Into<actix_web::Error>` will return the payload buffering error or the
/// error from the primary extractor. To access the fallback error, use a match clause.
#[derive(Debug)]
pub enum EitherExtractError<L, R> {
    /// Error from payload buffering, such as exceeding payload max size limit.
    Bytes(Error),

    /// Error from primary extractor.
    Extract(L, R),
}

impl<L, R> From<EitherExtractError<L, R>> for Error
where
    L: Into<Error>,
    R: Into<Error>,
{
    fn from(err: EitherExtractError<L, R>) -> Error {
        match err {
            EitherExtractError::Bytes(err) => err,
            EitherExtractError::Extract(a_err, _b_err) => a_err.into(),
        }
    }
}

/// See [here](#extractor) for example of usage as an extractor.
impl<L, R> FromRequest for Either<L, R>
where
    L: FromRequest + 'static,
    R: FromRequest + 'static,
{
    type Error = EitherExtractError<L::Error, R::Error>;
    type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
    type Config = ();

    fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
        let req2 = req.clone();

        Bytes::from_request(req, payload)
            .map_err(EitherExtractError::Bytes)
            .and_then(|bytes| bytes_to_l_or_r(req2, bytes))
            .boxed_local()
    }
}

async fn bytes_to_l_or_r<L, R>(
    req: HttpRequest,
    bytes: Bytes,
) -> Result<Either<L, R>, EitherExtractError<L::Error, R::Error>>
where
    L: FromRequest + 'static,
    R: FromRequest + 'static,
{
    let fallback = bytes.clone();
    let a_err;

    let mut pl = payload_from_bytes(bytes);
    match L::from_request(&req, &mut pl).await {
        Ok(a_data) => return Ok(Either::Left(a_data)),
        // store A's error for returning if B also fails
        Err(err) => a_err = err,
    };

    let mut pl = payload_from_bytes(fallback);
    match R::from_request(&req, &mut pl).await {
        Ok(b_data) => return Ok(Either::Right(b_data)),
        Err(b_err) => Err(EitherExtractError::Extract(a_err, b_err)),
    }
}

fn payload_from_bytes(bytes: Bytes) -> dev::Payload {
    let (_, mut h1_payload) = actix_http::h1::Payload::create(true);
    h1_payload.unread_data(bytes);
    dev::Payload::from(h1_payload)
}

#[cfg(test)]
mod tests {
    use serde::{Deserialize, Serialize};

    use super::*;
    use crate::{
        test::TestRequest,
        web::{Form, Json},
    };

    #[derive(Debug, Clone, Serialize, Deserialize)]
    struct TestForm {
        hello: String,
    }

    #[actix_rt::test]
    async fn test_either_extract_first_try() {
        let (req, mut pl) = TestRequest::default()
            .set_form(&TestForm {
                hello: "world".to_owned(),
            })
            .to_http_parts();

        let form = Either::<Form<TestForm>, Json<TestForm>>::from_request(&req, &mut pl)
            .await
            .unwrap()
            .unwrap_left()
            .into_inner();
        assert_eq!(&form.hello, "world");
    }

    #[actix_rt::test]
    async fn test_either_extract_fallback() {
        let (req, mut pl) = TestRequest::default()
            .set_json(&TestForm {
                hello: "world".to_owned(),
            })
            .to_http_parts();

        let form = Either::<Form<TestForm>, Json<TestForm>>::from_request(&req, &mut pl)
            .await
            .unwrap()
            .unwrap_right()
            .into_inner();
        assert_eq!(&form.hello, "world");
    }

    #[actix_rt::test]
    async fn test_either_extract_recursive_fallback() {
        let (req, mut pl) = TestRequest::default()
            .set_payload(Bytes::from_static(b"!@$%^&*()"))
            .to_http_parts();

        let payload = Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
            &req, &mut pl,
        )
        .await
        .unwrap()
        .unwrap_right();
        assert_eq!(&payload.as_ref(), &b"!@$%^&*()");
    }

    #[actix_rt::test]
    async fn test_either_extract_recursive_fallback_inner() {
        let (req, mut pl) = TestRequest::default()
            .set_json(&TestForm {
                hello: "world".to_owned(),
            })
            .to_http_parts();

        let form = Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
            &req, &mut pl,
        )
        .await
        .unwrap()
        .unwrap_left()
        .unwrap_right()
        .into_inner();
        assert_eq!(&form.hello, "world");
    }
}
<commit_msg>Static either extract future (#2184)<commit_after>//! For either helper, see [`Either`].

use std::{
    future::Future,
    mem,
    pin::Pin,
    task::{Context, Poll},
};

use bytes::Bytes;
use futures_core::ready;

use crate::{
    dev,
    web::{Form, Json},
    Error, FromRequest, HttpRequest, HttpResponse, Responder,
};

/// Combines two extractor or responder types into a single type.
///
/// Can be converted to and from an [`either::Either`].
///
/// # Extractor
/// Provides a mechanism for trying two extractors, a primary and a fallback. Useful for
/// "polymorphic payloads" where, for example, a form might be JSON or URL encoded.
///
/// It is important to note that this extractor, by necessity, buffers the entire request payload
/// as part of its implementation. Though, it does respect any `PayloadConfig` maximum size limits.
///
/// ```
/// use actix_web::{post, web, Either};
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Info {
///     name: String,
/// }
///
/// // handler that accepts form as JSON or form-urlencoded.
/// #[post("/")]
/// async fn index(form: Either<web::Json<Info>, web::Form<Info>>) -> String {
///     let name: String = match form {
///         Either::Left(json) => json.name.to_owned(),
///         Either::Right(form) => form.name.to_owned(),
///     };
///
///     format!("Welcome {}!", name)
/// }
/// ```
///
/// # Responder
/// It may be desireable to use a concrete type for a response with multiple branches. As long as
/// both types implement `Responder`, so will the `Either` type, enabling it to be used as a
/// handler's return type.
///
/// All properties of a response are determined by the Responder branch returned.
///
/// ```
/// use actix_web::{get, Either, Error, HttpResponse};
///
/// #[get("/")]
/// async fn index() -> Either<&'static str, Result<HttpResponse, Error>> {
///     if 1 == 2 {
///         // respond with Left variant
///         Either::Left("Bad data")
///     } else {
///         // respond with Right variant
///         Either::Right(
///             Ok(HttpResponse::Ok()
///                 .content_type(mime::TEXT_HTML)
///                 .body("<p>Hello!</p>"))
///         )
///     }
/// }
/// ```
#[derive(Debug, PartialEq)]
pub enum Either<L, R> {
    /// A value of type `L`.
    Left(L),

    /// A value of type `R`.
    Right(R),
}

impl<T> Either<Form<T>, Json<T>> {
    pub fn into_inner(self) -> T {
        match self {
            Either::Left(form) => form.into_inner(),
            Either::Right(form) => form.into_inner(),
        }
    }
}

impl<T> Either<Json<T>, Form<T>> {
    pub fn into_inner(self) -> T {
        match self {
            Either::Left(form) => form.into_inner(),
            Either::Right(form) => form.into_inner(),
        }
    }
}

impl<L, R> From<either::Either<L, R>> for Either<L, R> {
    fn from(val: either::Either<L, R>) -> Self {
        match val {
            either::Either::Left(l) => Either::Left(l),
            either::Either::Right(r) => Either::Right(r),
        }
    }
}

impl<L, R> From<Either<L, R>> for either::Either<L, R> {
    fn from(val: Either<L, R>) -> Self {
        match val {
            Either::Left(l) => either::Either::Left(l),
            Either::Right(r) => either::Either::Right(r),
        }
    }
}

#[cfg(test)]
impl<L, R> Either<L, R> {
    pub(self) fn unwrap_left(self) -> L {
        match self {
            Either::Left(data) => data,
            Either::Right(_) => {
                panic!("Cannot unwrap Left branch. Either contains an `R` type.")
            }
        }
    }

    pub(self) fn unwrap_right(self) -> R {
        match self {
            Either::Left(_) => {
                panic!("Cannot unwrap Right branch. Either contains an `L` type.")
            }
            Either::Right(data) => data,
        }
    }
}

/// See [here](#responder) for example of usage as a handler return type.
impl<L, R> Responder for Either<L, R>
where
    L: Responder,
    R: Responder,
{
    fn respond_to(self, req: &HttpRequest) -> HttpResponse {
        match self {
            Either::Left(a) => a.respond_to(req),
            Either::Right(b) => b.respond_to(req),
        }
    }
}

/// A composite error resulting from failure to extract an `Either<L, R>`.
///
/// The implementation of `Into<actix_web::Error>` will return the payload buffering error or the
/// error from the primary extractor. To access the fallback error, use a match clause.
#[derive(Debug)]
pub enum EitherExtractError<L, R> {
    /// Error from payload buffering, such as exceeding payload max size limit.
    Bytes(Error),

    /// Error from primary extractor.
    Extract(L, R),
}

impl<L, R> From<EitherExtractError<L, R>> for Error
where
    L: Into<Error>,
    R: Into<Error>,
{
    fn from(err: EitherExtractError<L, R>) -> Error {
        match err {
            EitherExtractError::Bytes(err) => err,
            EitherExtractError::Extract(a_err, _b_err) => a_err.into(),
        }
    }
}

/// See [here](#extractor) for example of usage as an extractor.
impl<L, R> FromRequest for Either<L, R>
where
    L: FromRequest + 'static,
    R: FromRequest + 'static,
{
    type Error = EitherExtractError<L::Error, R::Error>;
    type Future = EitherExtractFut<L, R>;
    type Config = ();

    fn from_request(req: &HttpRequest, payload: &mut dev::Payload) -> Self::Future {
        EitherExtractFut {
            req: req.clone(),
            state: EitherExtractState::Bytes {
                bytes: Bytes::from_request(req, payload),
            },
        }
    }
}

#[pin_project::pin_project]
pub struct EitherExtractFut<L, R>
where
    R: FromRequest,
    L: FromRequest,
{
    req: HttpRequest,
    #[pin]
    state: EitherExtractState<L, R>,
}

#[pin_project::pin_project(project = EitherExtractProj)]
pub enum EitherExtractState<L, R>
where
    L: FromRequest,
    R: FromRequest,
{
    Bytes {
        #[pin]
        bytes: <Bytes as FromRequest>::Future,
    },
    Left {
        #[pin]
        left: L::Future,
        fallback: Bytes,
    },
    Right {
        #[pin]
        right: R::Future,
        left_err: Option<L::Error>,
    },
}

impl<R, RF, RE, L, LF, LE> Future for EitherExtractFut<L, R>
where
    L: FromRequest<Future = LF, Error = LE>,
    R: FromRequest<Future = RF, Error = RE>,
    LF: Future<Output = Result<L, LE>> + 'static,
    RF: Future<Output = Result<R, RE>> + 'static,
    LE: Into<Error>,
    RE: Into<Error>,
{
    type Output = Result<Either<L, R>, EitherExtractError<LE, RE>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut this = self.project();
        let ready = loop {
            let next = match this.state.as_mut().project() {
                EitherExtractProj::Bytes { bytes } => {
                    let res = ready!(bytes.poll(cx));
                    match res {
                        Ok(bytes) => {
                            let fallback = bytes.clone();
                            let left =
                                L::from_request(&this.req, &mut payload_from_bytes(bytes));
                            EitherExtractState::Left { left, fallback }
                        }
                        Err(err) => break Err(EitherExtractError::Bytes(err)),
                    }
                }
                EitherExtractProj::Left { left, fallback } => {
                    let res = ready!(left.poll(cx));
                    match res {
                        Ok(extracted) => break Ok(Either::Left(extracted)),
                        Err(left_err) => {
                            let right = R::from_request(
                                &this.req,
                                &mut payload_from_bytes(mem::take(fallback)),
                            );
                            EitherExtractState::Right {
                                left_err: Some(left_err),
                                right,
                            }
                        }
                    }
                }
                EitherExtractProj::Right { right, left_err } => {
                    let res = ready!(right.poll(cx));
                    match res {
                        Ok(data) => break Ok(Either::Right(data)),
                        Err(err) => {
                            break Err(EitherExtractError::Extract(
                                left_err.take().unwrap(),
                                err,
                            ));
                        }
                    }
                }
            };
            this.state.set(next);
        };
        Poll::Ready(ready)
    }
}

fn payload_from_bytes(bytes: Bytes) -> dev::Payload {
    let (_, mut h1_payload) = actix_http::h1::Payload::create(true);
    h1_payload.unread_data(bytes);
    dev::Payload::from(h1_payload)
}

#[cfg(test)]
mod tests {
    use serde::{Deserialize, Serialize};

    use super::*;
    use crate::{
        test::TestRequest,
        web::{Form, Json},
    };

    #[derive(Debug, Clone, Serialize, Deserialize)]
    struct TestForm {
        hello: String,
    }

    #[actix_rt::test]
    async fn test_either_extract_first_try() {
        let (req, mut pl) = TestRequest::default()
            .set_form(&TestForm {
                hello: "world".to_owned(),
            })
            .to_http_parts();

        let form = Either::<Form<TestForm>, Json<TestForm>>::from_request(&req, &mut pl)
            .await
            .unwrap()
            .unwrap_left()
            .into_inner();
        assert_eq!(&form.hello, "world");
    }

    #[actix_rt::test]
    async fn test_either_extract_fallback() {
        let (req, mut pl) = TestRequest::default()
            .set_json(&TestForm {
                hello: "world".to_owned(),
            })
            .to_http_parts();

        let form = Either::<Form<TestForm>, Json<TestForm>>::from_request(&req, &mut pl)
            .await
            .unwrap()
            .unwrap_right()
            .into_inner();
        assert_eq!(&form.hello, "world");
    }

    #[actix_rt::test]
    async fn test_either_extract_recursive_fallback() {
        let (req, mut pl) = TestRequest::default()
            .set_payload(Bytes::from_static(b"!@$%^&*()"))
            .to_http_parts();

        let payload = Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
            &req, &mut pl,
        )
        .await
        .unwrap()
        .unwrap_right();
        assert_eq!(&payload.as_ref(), &b"!@$%^&*()");
    }

    #[actix_rt::test]
    async fn test_either_extract_recursive_fallback_inner() {
        let (req, mut pl) = TestRequest::default()
            .set_json(&TestForm {
                hello: "world".to_owned(),
            })
            .to_http_parts();

        let form = Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
            &req, &mut pl,
        )
        .await
        .unwrap()
        .unwrap_left()
        .unwrap_right()
        .into_inner();
        assert_eq!(&form.hello, "world");
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Error};
use std::hash::{Hash, Hasher};
use std::string::String;

use super::binding::{Binding, UniqueBinding};
use super::coerce::AsString;
use super::js_fn::JsFnStruct;
use super::js_obj::JsObjStruct;
use super::js_str::JsStrStruct;
use super::native_fn::NativeFn;

#[derive(Clone, Debug)]
pub struct JsVar {
    pub unique: UniqueBinding,
    pub binding: Binding,
    pub t: JsType,
}

impl Hash for JsVar {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.unique.hash(state);
    }
}

impl JsVar {
    pub fn new(t: JsType) -> JsVar {
        let mut var = JsVar {
            unique: UniqueBinding::dummy(),
            binding: Binding::anon(),
            t: t,
        };
        var.unique = UniqueBinding::mangle(&var.binding);
        var
    }

    pub fn bind(binding: &str, t: JsType) -> JsVar {
        let mut var = JsVar {
            unique: UniqueBinding::mangle_str(binding),
            binding: Binding::new(binding.to_owned()),
            t: t,
        };
        var.unique = UniqueBinding::mangle(&var.binding);
        var
    }

    pub fn deanonymize(&mut self, binding: &str) -> bool {
        if self.binding.is_anon() {
            self.unique = UniqueBinding::mangle_str(binding);
            self.binding = Binding::new(binding.to_owned());
            true
        } else {
            false
        }
    }

    pub fn rename(&mut self, binding: &str) -> bool {
        if self.binding.var_name() == binding {
            self.unique = UniqueBinding::mangle_str(binding);
            self.binding = Binding::new(binding.to_owned());
            true
        } else {
            false
        }
    }

    pub fn type_of(&self) -> String {
        self.t.type_of()
    }
}

impl Display for JsVar {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        if !self.binding.is_anon() {
            return write!(fmt, "{}", self.binding);
        }

        write!(fmt, "{}", self.t)
    }
}

impl PartialEq for JsVar {
    fn eq(&self, other: &Self) -> bool {
        self.unique == other.unique
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl Eq for JsVar {}

#[derive(Clone, Debug)]
pub enum JsPtrEnum {
    JsSym(String),
    JsStr(JsStrStruct),
    JsObj(JsObjStruct),
    JsFn(JsFnStruct),
    NativeFn(NativeFn),
}

impl Display for JsPtrEnum {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        match self {
            &JsPtrEnum::JsSym(ref s) => write!(fmt, "Symbol({})", s),
            &JsPtrEnum::JsStr(ref s) => write!(fmt, "\"{}\"", s),
            &JsPtrEnum::JsObj(ref o) => write!(fmt, "{}", o),
            &JsPtrEnum::JsFn(ref f) => write!(fmt, "{}", f),
            &JsPtrEnum::NativeFn(_) => write!(fmt, "[native code]"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum JsPtrTag {
    JsSym,
    JsStr,
    JsObj,
    JsFn { name: Option<String> },
    NativeFn { name: String },
}

impl JsPtrTag {
    pub fn eq_ptr_type(&self, other: &JsPtrEnum) -> bool {
        match (self, other) {
            (&JsPtrTag::JsSym, &JsPtrEnum::JsSym(_)) |
            (&JsPtrTag::JsStr, &JsPtrEnum::JsStr(_)) |
            (&JsPtrTag::JsObj, &JsPtrEnum::JsObj(_)) |
            (&JsPtrTag::JsFn{..},  &JsPtrEnum::JsFn(_)) |
            (&JsPtrTag::NativeFn{..}, &JsPtrEnum::NativeFn(_)) => true,
            _ => false
        }
    }

    fn type_of(&self) -> String {
        let s = match *self {
            JsPtrTag::JsSym => "symbol",
            JsPtrTag::JsStr => "string",
            JsPtrTag::JsObj => "object",
            JsPtrTag::JsFn{..} | JsPtrTag::NativeFn{..} => "function",
        };

        String::from(s)
    }
}

#[derive(Clone, Debug)]
pub enum JsType {
    JsUndef,
    JsNum(f64),
    JsBool(bool),
    JsPtr(JsPtrTag),
    JsNull, // null is not a ptr since it doesn't actually require heap allocation
}

impl JsType {
    fn type_of(&self) -> String {
        let s = match *self {
            JsType::JsUndef => "undefined",
            JsType::JsNum(_) => "number",
            JsType::JsBool(_) => "boolean",
            JsType::JsNull => "object",
            JsType::JsPtr(ref t) => return t.type_of(),
        };

        String::from(s)
    }
}

impl Display for JsType {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}", self.as_string())
    }
}

impl PartialEq for JsType {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&JsType::JsUndef, &JsType::JsUndef) => true,
            (&JsType::JsNum(x), &JsType::JsNum(y)) => x == y,
            (&JsType::JsBool(b1), &JsType::JsBool(b2)) => b1 == b2,
            (&JsType::JsNull, &JsType::JsNull) => true,
            (_, _) => false,
        }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl Eq for JsType {}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum JsKey {
    JsStr(JsStrStruct),
    JsSym(String),
}

impl Display for JsKey {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            JsKey::JsStr(ref s) => write!(fmt, "{}", s),
            JsKey::JsSym(ref s) => write!(fmt, "Symbol({})", s),
        }
    }
}
<commit_msg>Don't change UniqueBinding on vars when renaming them<commit_after>use std::fmt::{Display, Formatter, Error};
use std::hash::{Hash, Hasher};
use std::string::String;

use super::binding::{Binding, UniqueBinding};
use super::coerce::AsString;
use super::js_fn::JsFnStruct;
use super::js_obj::JsObjStruct;
use super::js_str::JsStrStruct;
use super::native_fn::NativeFn;

#[derive(Clone, Debug)]
pub struct JsVar {
    pub unique: UniqueBinding,
    pub binding: Binding,
    pub t: JsType,
}

impl Hash for JsVar {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.unique.hash(state);
    }
}

impl JsVar {
    pub fn new(t: JsType) -> JsVar {
        let mut var = JsVar {
            unique: UniqueBinding::dummy(),
            binding: Binding::anon(),
            t: t,
        };
        var.unique = UniqueBinding::mangle(&var.binding);
        var
    }

    pub fn bind(binding: &str, t: JsType) -> JsVar {
        let mut var = JsVar {
            unique: UniqueBinding::mangle_str(binding),
            binding: Binding::new(binding.to_owned()),
            t: t,
        };
        var.unique = UniqueBinding::mangle(&var.binding);
        var
    }

    pub fn deanonymize(&mut self, binding: &str) -> bool {
        if self.binding.is_anon() {
            self.unique = UniqueBinding::mangle_str(binding);
            self.binding = Binding::new(binding.to_owned());
            true
        } else {
            false
        }
    }

    pub fn rename(&mut self, binding: &str) -> bool {
        if self.binding.var_name() == binding {
            self.binding = Binding::new(binding.to_owned());
            true
        } else {
            false
        }
    }

    pub fn type_of(&self) -> String {
        self.t.type_of()
    }
}

impl Display for JsVar {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        if !self.binding.is_anon() {
            return write!(fmt, "{}", self.binding);
        }

        write!(fmt, "{}", self.t)
    }
}

impl PartialEq for JsVar {
    fn eq(&self, other: &Self) -> bool {
        self.unique == other.unique
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl Eq for JsVar {}

#[derive(Clone, Debug)]
pub enum JsPtrEnum {
    JsSym(String),
    JsStr(JsStrStruct),
    JsObj(JsObjStruct),
    JsFn(JsFnStruct),
    NativeFn(NativeFn),
}

impl Display for JsPtrEnum {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        match self {
            &JsPtrEnum::JsSym(ref s) => write!(fmt, "Symbol({})", s),
            &JsPtrEnum::JsStr(ref s) => write!(fmt, "\"{}\"", s),
            &JsPtrEnum::JsObj(ref o) => write!(fmt, "{}", o),
            &JsPtrEnum::JsFn(ref f) => write!(fmt, "{}", f),
            &JsPtrEnum::NativeFn(_) => write!(fmt, "[native code]"),
        }
    }
}

#[derive(Clone, Debug)]
pub enum JsPtrTag {
    JsSym,
    JsStr,
    JsObj,
    JsFn { name: Option<String> },
    NativeFn { name: String },
}

impl JsPtrTag {
    pub fn eq_ptr_type(&self, other: &JsPtrEnum) -> bool {
        match (self, other) {
            (&JsPtrTag::JsSym, &JsPtrEnum::JsSym(_)) |
            (&JsPtrTag::JsStr, &JsPtrEnum::JsStr(_)) |
            (&JsPtrTag::JsObj, &JsPtrEnum::JsObj(_)) |
            (&JsPtrTag::JsFn{..},  &JsPtrEnum::JsFn(_)) |
            (&JsPtrTag::NativeFn{..}, &JsPtrEnum::NativeFn(_)) => true,
            _ => false
        }
    }

    fn type_of(&self) -> String {
        let s = match *self {
            JsPtrTag::JsSym => "symbol",
            JsPtrTag::JsStr => "string",
            JsPtrTag::JsObj => "object",
            JsPtrTag::JsFn{..} | JsPtrTag::NativeFn{..} => "function",
        };

        String::from(s)
    }
}

#[derive(Clone, Debug)]
pub enum JsType {
    JsUndef,
    JsNum(f64),
    JsBool(bool),
    JsPtr(JsPtrTag),
    JsNull, // null is not a ptr since it doesn't actually require heap allocation
}

impl JsType {
    fn type_of(&self) -> String {
        let s = match *self {
            JsType::JsUndef => "undefined",
            JsType::JsNum(_) => "number",
            JsType::JsBool(_) => "boolean",
            JsType::JsNull => "object",
            JsType::JsPtr(ref t) => return t.type_of(),
        };

        String::from(s)
    }
}

impl Display for JsType {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        write!(fmt, "{}", self.as_string())
    }
}

impl PartialEq for JsType {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&JsType::JsUndef, &JsType::JsUndef) => true,
            (&JsType::JsNum(x), &JsType::JsNum(y)) => x == y,
            (&JsType::JsBool(b1), &JsType::JsBool(b2)) => b1 == b2,
            (&JsType::JsNull, &JsType::JsNull) => true,
            (_, _) => false,
        }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}

impl Eq for JsType {}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum JsKey {
    JsStr(JsStrStruct),
    JsSym(String),
}

impl Display for JsKey {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        match *self {
            JsKey::JsStr(ref s) => write!(fmt, "{}", s),
            JsKey::JsSym(ref s) => write!(fmt, "Symbol({})", s),
        }
    }
}
<|endoftext|>