<commit_before>//! Common definitions for wayland
//!
//! This crate hosts common type and traits used to represent wayland messages
//! and routines in the `wayland-client` and `wayland-server` crates.
//!
//! This notably includes the `Interface` trait, which can exhaustively describe
//! any wayland interface. Its implementations are intended to be generated by the
//! `wayland-scanner` crate.
//!
//! The principal user-facing definition provided by this crate is the `Implementation`
//! trait, which as a user of `wayland-client` or `wayland-server` you will be using
//! to define objects able to handle the messages your program receives. Note that
//! this trait is auto-implemented for closures with appropriate signature, for
//! convenience.

#![warn(missing_docs)]

#[macro_use]
extern crate nix;

use std::os::raw::c_void;
use wayland_sys::common as syscom;

pub mod debug;
pub mod filter;
pub mod map;
pub mod socket;
pub mod user_data;
pub mod wire;

pub use smallvec::smallvec;

/// A group of messages
///
/// This represents a group of message that can be serialized on the protocol wire.
/// Typically the set of events or requests of a single interface.
///
/// Implementations of this trait are supposed to be
/// generated using the `wayland-scanner` crate.
pub trait MessageGroup: Sized {
    /// Wire representation of this MessageGroup
    const MESSAGES: &'static [wire::MessageDesc];
    /// The wrapper type for ObjectMap allowing the mapping of Object and
    /// NewId arguments to the object map during parsing.
    type Map;
    /// The opcode of this message
    fn opcode(&self) -> u16;
    /// Whether this message is a destructor
    ///
    /// If it is, once send or receive the associated object cannot be used any more.
    fn is_destructor(&self) -> bool;
    /// The minimal object version for which this message exists
    fn since(&self) -> u32;
    /// Retrieve the child `Object` associated with this message if any
    fn child<Meta: self::map::ObjectMetadata>(
        opcode: u16,
        version: u32,
        meta: &Meta,
    ) -> Option<crate::map::Object<Meta>>;
    /// Construct a message from its raw representation
    fn from_raw(msg: wire::Message, map: &mut Self::Map) -> Result<Self, ()>;
    /// Turn this message into its raw representation
    fn into_raw(self, send_id: u32) -> wire::Message;
    /// Construct a message of this group from its C representation
    ///
    /// # Safety
    ///
    /// The pointers provided to this function must all be valid pointers from
    /// `libwayland-client`
    unsafe fn from_raw_c(
        obj: *mut c_void,
        opcode: u32,
        args: *const syscom::wl_argument,
    ) -> Result<Self, ()>;
    /// Build a C representation of this message
    ///
    /// It can only be accessed from the provided closure, and this consumes
    /// the message.
    fn as_raw_c_in<F, T>(self, f: F) -> T
    where
        F: FnOnce(u32, &mut [syscom::wl_argument]) -> T;
}

/// The description of a wayland interface
///
/// Implementations of this trait are supposed to be
/// generated using the `wayland-scanner` crate.
pub trait Interface: 'static {
    /// Set of requests associated to this interface
    ///
    /// Requests are messages from the client to the server
    type Request: MessageGroup + 'static;
    /// Set of events associated to this interface
    ///
    /// Events are messages from the server to the client
    type Event: MessageGroup + 'static;
    /// Name of this interface
    const NAME: &'static str;
    /// Maximum supported version of this interface
    ///
    /// This is the maximum version supported by the protocol specification currently
    /// used by this library, and should not be used as-is in your code, as a version
    /// change can subtly change the behavior of some objects.
    ///
    /// Server are supposed to be able to handle all versions from 1 to the one they
    /// advertise through the registry, and clients can choose any version among the
    /// ones the server supports.
    const VERSION: u32;
    /// Pointer to the C representation of this interface
    fn c_interface() -> *const syscom::wl_interface;
}

/// An empty enum representing a MessageGroup with no messages
pub enum NoMessage {}

#[cfg_attr(tarpaulin, skip)]
impl MessageGroup for NoMessage {
    const MESSAGES: &'static [wire::MessageDesc] = &[];
    type Map = ();
    fn is_destructor(&self) -> bool {
        match *self {}
    }
    fn opcode(&self) -> u16 {
        match *self {}
    }
    fn since(&self) -> u32 {
        match *self {}
    }
    fn child<M: self::map::ObjectMetadata>(_: u16, _: u32, _: &M) -> Option<crate::map::Object<M>> {
        None
    }
    fn from_raw(_: wire::Message, _: &mut ()) -> Result<Self, ()> {
        Err(())
    }
    fn into_raw(self, _: u32) -> wire::Message {
        match self {}
    }
    unsafe fn from_raw_c(
        _obj: *mut c_void,
        _opcode: u32,
        _args: *const syscom::wl_argument,
    ) -> Result<Self, ()> {
        Err(())
    }
    fn as_raw_c_in<F, T>(self, _f: F) -> T
    where
        F: FnOnce(u32, &mut [syscom::wl_argument]) -> T,
    {
        match self {}
    }
}

/// Stores a value in a threadafe container that
/// only lets you access it from its owning thread
///
/// If the ThreadGuard is dropped from the wrong thread,
/// the underlying value will be leaked.
pub struct ThreadGuard<T: ?Sized> {
    thread: std::thread::ThreadId,
    val: std::mem::ManuallyDrop<T>,
}

impl<T> ThreadGuard<T> {
    /// Create a new ThreadGuard wrapper
    pub fn new(val: T) -> ThreadGuard<T> {
        ThreadGuard { val: std::mem::ManuallyDrop::new(val), thread: std::thread::current().id() }
    }
}

impl<T: ?Sized> ThreadGuard<T> {
    /// Access the underlying value
    ///
    /// Panics if done on the wrong thread
    pub fn get(&self) -> &T {
        self.try_get().expect("Attempted to access a ThreadGuard contents from the wrong thread.")
    }

    /// Mutably access the underlying value
    ///
    /// Panics if done on the wrong thread
    pub fn get_mut(&mut self) -> &mut T {
        self.try_get_mut()
            .expect("Attempted to access a ThreadGuard contents from the wrong thread.")
    }

    /// Try to access the underlying value
    ///
    /// Returns `None` if done on the wrong thread
    pub fn try_get(&self) -> Option<&T> {
        if self.thread == ::std::thread::current().id() {
            Some(&self.val)
        } else {
            None
        }
    }

    /// Try to mutably access the underlying value
    ///
    /// Returns `None` if done on the wrong thread
    pub fn try_get_mut(&mut self) -> Option<&mut T> {
        if self.thread == ::std::thread::current().id() {
            Some(&mut self.val)
        } else {
            None
        }
    }
}

impl<T: ?Sized> Drop for ThreadGuard<T> {
    fn drop(&mut self) {
        // We can only actually perform the drop if we are on the right thread
        // otherwise it may be racy, so we just leak the value
        if self.thread == ::std::thread::current().id() {
            unsafe { std::mem::ManuallyDrop::drop(&mut self.val) }
        }
    }
}

unsafe impl<T: ?Sized> Send for ThreadGuard<T> {}
unsafe impl<T: ?Sized> Sync for ThreadGuard<T> {}
<commit_msg>fix tarpaulin attributes<commit_after>//! Common definitions for wayland
//!
//! This crate hosts common type and traits used to represent wayland messages
//! and routines in the `wayland-client` and `wayland-server` crates.
//!
//! This notably includes the `Interface` trait, which can exhaustively describe
//! any wayland interface. Its implementations are intended to be generated by the
//! `wayland-scanner` crate.
//!
//! The principal user-facing definition provided by this crate is the `Implementation`
//! trait, which as a user of `wayland-client` or `wayland-server` you will be using
//! to define objects able to handle the messages your program receives. Note that
//! this trait is auto-implemented for closures with appropriate signature, for
//! convenience.

#![warn(missing_docs)]

#[macro_use]
extern crate nix;

use std::os::raw::c_void;
use wayland_sys::common as syscom;

pub mod debug;
pub mod filter;
pub mod map;
pub mod socket;
pub mod user_data;
pub mod wire;

pub use smallvec::smallvec;

/// A group of messages
///
/// This represents a group of message that can be serialized on the protocol wire.
/// Typically the set of events or requests of a single interface.
///
/// Implementations of this trait are supposed to be
/// generated using the `wayland-scanner` crate.
pub trait MessageGroup: Sized {
    /// Wire representation of this MessageGroup
    const MESSAGES: &'static [wire::MessageDesc];
    /// The wrapper type for ObjectMap allowing the mapping of Object and
    /// NewId arguments to the object map during parsing.
    type Map;
    /// The opcode of this message
    fn opcode(&self) -> u16;
    /// Whether this message is a destructor
    ///
    /// If it is, once send or receive the associated object cannot be used any more.
    fn is_destructor(&self) -> bool;
    /// The minimal object version for which this message exists
    fn since(&self) -> u32;
    /// Retrieve the child `Object` associated with this message if any
    fn child<Meta: self::map::ObjectMetadata>(
        opcode: u16,
        version: u32,
        meta: &Meta,
    ) -> Option<crate::map::Object<Meta>>;
    /// Construct a message from its raw representation
    fn from_raw(msg: wire::Message, map: &mut Self::Map) -> Result<Self, ()>;
    /// Turn this message into its raw representation
    fn into_raw(self, send_id: u32) -> wire::Message;
    /// Construct a message of this group from its C representation
    ///
    /// # Safety
    ///
    /// The pointers provided to this function must all be valid pointers from
    /// `libwayland-client`
    unsafe fn from_raw_c(
        obj: *mut c_void,
        opcode: u32,
        args: *const syscom::wl_argument,
    ) -> Result<Self, ()>;
    /// Build a C representation of this message
    ///
    /// It can only be accessed from the provided closure, and this consumes
    /// the message.
    fn as_raw_c_in<F, T>(self, f: F) -> T
    where
        F: FnOnce(u32, &mut [syscom::wl_argument]) -> T;
}

/// The description of a wayland interface
///
/// Implementations of this trait are supposed to be
/// generated using the `wayland-scanner` crate.
pub trait Interface: 'static {
    /// Set of requests associated to this interface
    ///
    /// Requests are messages from the client to the server
    type Request: MessageGroup + 'static;
    /// Set of events associated to this interface
    ///
    /// Events are messages from the server to the client
    type Event: MessageGroup + 'static;
    /// Name of this interface
    const NAME: &'static str;
    /// Maximum supported version of this interface
    ///
    /// This is the maximum version supported by the protocol specification currently
    /// used by this library, and should not be used as-is in your code, as a version
    /// change can subtly change the behavior of some objects.
    ///
    /// Server are supposed to be able to handle all versions from 1 to the one they
    /// advertise through the registry, and clients can choose any version among the
    /// ones the server supports.
    const VERSION: u32;
    /// Pointer to the C representation of this interface
    fn c_interface() -> *const syscom::wl_interface;
}

/// An empty enum representing a MessageGroup with no messages
pub enum NoMessage {}

#[cfg(not(tarpaulin_include))]
impl MessageGroup for NoMessage {
    const MESSAGES: &'static [wire::MessageDesc] = &[];
    type Map = ();
    fn is_destructor(&self) -> bool {
        match *self {}
    }
    fn opcode(&self) -> u16 {
        match *self {}
    }
    fn since(&self) -> u32 {
        match *self {}
    }
    fn child<M: self::map::ObjectMetadata>(_: u16, _: u32, _: &M) -> Option<crate::map::Object<M>> {
        None
    }
    fn from_raw(_: wire::Message, _: &mut ()) -> Result<Self, ()> {
        Err(())
    }
    fn into_raw(self, _: u32) -> wire::Message {
        match self {}
    }
    unsafe fn from_raw_c(
        _obj: *mut c_void,
        _opcode: u32,
        _args: *const syscom::wl_argument,
    ) -> Result<Self, ()> {
        Err(())
    }
    fn as_raw_c_in<F, T>(self, _f: F) -> T
    where
        F: FnOnce(u32, &mut [syscom::wl_argument]) -> T,
    {
        match self {}
    }
}

/// Stores a value in a threadafe container that
/// only lets you access it from its owning thread
///
/// If the ThreadGuard is dropped from the wrong thread,
/// the underlying value will be leaked.
pub struct ThreadGuard<T: ?Sized> {
    thread: std::thread::ThreadId,
    val: std::mem::ManuallyDrop<T>,
}

impl<T> ThreadGuard<T> {
    /// Create a new ThreadGuard wrapper
    pub fn new(val: T) -> ThreadGuard<T> {
        ThreadGuard { val: std::mem::ManuallyDrop::new(val), thread: std::thread::current().id() }
    }
}

impl<T: ?Sized> ThreadGuard<T> {
    /// Access the underlying value
    ///
    /// Panics if done on the wrong thread
    pub fn get(&self) -> &T {
        self.try_get().expect("Attempted to access a ThreadGuard contents from the wrong thread.")
    }

    /// Mutably access the underlying value
    ///
    /// Panics if done on the wrong thread
    pub fn get_mut(&mut self) -> &mut T {
        self.try_get_mut()
            .expect("Attempted to access a ThreadGuard contents from the wrong thread.")
    }

    /// Try to access the underlying value
    ///
    /// Returns `None` if done on the wrong thread
    pub fn try_get(&self) -> Option<&T> {
        if self.thread == ::std::thread::current().id() {
            Some(&self.val)
        } else {
            None
        }
    }

    /// Try to mutably access the underlying value
    ///
    /// Returns `None` if done on the wrong thread
    pub fn try_get_mut(&mut self) -> Option<&mut T> {
        if self.thread == ::std::thread::current().id() {
            Some(&mut self.val)
        } else {
            None
        }
    }
}

impl<T: ?Sized> Drop for ThreadGuard<T> {
    fn drop(&mut self) {
        // We can only actually perform the drop if we are on the right thread
        // otherwise it may be racy, so we just leak the value
        if self.thread == ::std::thread::current().id() {
            unsafe { std::mem::ManuallyDrop::drop(&mut self.val) }
        }
    }
}

unsafe impl<T: ?Sized> Send for ThreadGuard<T> {}
unsafe impl<T: ?Sized> Sync for ThreadGuard<T> {}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Virtual tables/ORM for reports produced by the `CorTeX` backend

#![allow(missing_docs, unused_imports)]
/// Table declaration for the return type for aggregate report queries
table! {
  aggregate_reports (report_name) {
    report_name -> Nullable<Text>,
    task_count -> BigInt,
    message_count -> BigInt,
  }
}

#[derive(Debug, Clone, PartialEq, Eq, QueryableByName)]
#[table_name = "aggregate_reports"]
/// The return struct of aggregate reports targeting task and log message counts
pub struct AggregateReport {
  /// the category, per `LaTeXML` convention
  pub report_name: Option<String>,
  /// number of tasks with messages under this category (in implied severity - strictly)
  pub task_count: i64,
  /// number of messages under this category (in implied severity - strictly)
  pub message_count: i64,
}

/// Table declaration of the return type for "task details" report queries
table! {
  task_detail_reports (id) {
    id -> BigInt,
    entry -> Text,
    details -> Text,
  }
}

#[derive(Debug, Clone, PartialEq, Eq, QueryableByName)]
#[table_name = "task_detail_reports"]
/// The return struct of "task details" reports
pub struct TaskDetailReport {
  /// the task id
  pub id: i64,
  /// the task entry path
  pub entry: String,
  /// the details for the queried log (severity, category,what) selection
  pub details: String,
}
<commit_msg>move table doc inside diesel declaration<commit_after>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Virtual tables/ORM for reports produced by the `CorTeX` backend

#![allow(missing_docs, unused_imports)]
table! {
  /// Table declaration for the return type for aggregate report queries
  aggregate_reports (report_name) {
    report_name -> Nullable<Text>,
    task_count -> BigInt,
    message_count -> BigInt,
  }
}

#[derive(Debug, Clone, PartialEq, Eq, QueryableByName)]
#[table_name = "aggregate_reports"]
/// The return struct of aggregate reports targeting task and log message counts
pub struct AggregateReport {
  /// the category, per `LaTeXML` convention
  pub report_name: Option<String>,
  /// number of tasks with messages under this category (in implied severity - strictly)
  pub task_count: i64,
  /// number of messages under this category (in implied severity - strictly)
  pub message_count: i64,
}

table! {
  /// Table declaration of the return type for "task details" report queries
  task_detail_reports (id) {
    id -> BigInt,
    entry -> Text,
    details -> Text,
  }
}

#[derive(Debug, Clone, PartialEq, Eq, QueryableByName)]
#[table_name = "task_detail_reports"]
/// The return struct of "task details" reports
pub struct TaskDetailReport {
  /// the task id
  pub id: i64,
  /// the task entry path
  pub entry: String,
  /// the details for the queried log (severity, category,what) selection
  pub details: String,
}
<|endoftext|>


<commit_before>use std::{io, time};
use std::net::Shutdown;
use std::time::Duration;

use actix::{fut, Actor, ActorFuture, Context,
            Handler, Message, ActorResponse, Supervised};
use actix::registry::ArbiterService;
use actix::fut::WrapFuture;
use actix::actors::{Connector, ConnectorError, Connect as ResolveConnect};

use http::{Uri, HttpTryFrom, Error as HttpError};
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};

#[cfg(feature="alpn")]
use openssl::ssl::{SslMethod, SslConnector, Error as OpensslError};
#[cfg(feature="alpn")]
use tokio_openssl::SslConnectorExt;
#[cfg(feature="alpn")]
use futures::Future;

#[cfg(all(feature="tls", not(feature="alpn")))]
use native_tls::{TlsConnector, Error as TlsError};
#[cfg(all(feature="tls", not(feature="alpn")))]
use tokio_tls::TlsConnectorExt;
#[cfg(all(feature="tls", not(feature="alpn")))]
use futures::Future;

use {HAS_OPENSSL, HAS_TLS};
use server::IoStream;

#[derive(Debug)]
/// `Connect` type represents message that can be send to `ClientConnector`
/// with connection request.
pub struct Connect {
    pub uri: Uri,
    pub conn_timeout: Duration,
}

impl Connect {
    /// Create `Connect` message for specified `Uri`
    pub fn new<U>(uri: U) -> Result<Connect, HttpError> where Uri: HttpTryFrom<U> {
        Ok(Connect {
            uri: Uri::try_from(uri).map_err(|e| e.into())?,
            conn_timeout: Duration::from_secs(1)
        })
    }
}

impl Message for Connect {
    type Result = Result<Connection, ClientConnectorError>;
}

/// A set of errors that can occur during connecting to a http host
#[derive(Fail, Debug)]
pub enum ClientConnectorError {
    /// Invalid url
    #[fail(display="Invalid url")]
    InvalidUrl,

    /// SSL feature is not enabled
    #[fail(display="SSL is not supported")]
    SslIsNotSupported,

    /// SSL error
    #[cfg(feature="alpn")]
    #[fail(display="{}", _0)]
    SslError(#[cause] OpensslError),

    /// SSL error
    #[cfg(all(feature="tls", not(feature="alpn")))]
    #[fail(display="{}", _0)]
    SslError(#[cause] TlsError),

    /// Connection error
    #[fail(display = "{}", _0)]
    Connector(#[cause] ConnectorError),

    /// Connecting took too long
    #[fail(display = "Timeout out while establishing connection")]
    Timeout,

    /// Connector has been disconnected
    #[fail(display = "Internal error: connector has been disconnected")]
    Disconnected,

    /// Connection io error
    #[fail(display = "{}", _0)]
    IoError(#[cause] io::Error),
}

impl From<ConnectorError> for ClientConnectorError {
    fn from(err: ConnectorError) -> ClientConnectorError {
        ClientConnectorError::Connector(err)
    }
}

pub struct ClientConnector {
    #[cfg(all(feature="alpn"))]
    connector: SslConnector,
    #[cfg(all(feature="tls", not(feature="alpn")))]
    connector: TlsConnector,
}

impl Actor for ClientConnector {
    type Context = Context<ClientConnector>;
}

impl Supervised for ClientConnector {}

impl ArbiterService for ClientConnector {}

impl Default for ClientConnector {
    fn default() -> ClientConnector {
        #[cfg(all(feature="alpn"))]
        {
            let builder = SslConnector::builder(SslMethod::tls()).unwrap();
            ClientConnector {
                connector: builder.build()
            }
        }
        #[cfg(all(feature="tls", not(feature="alpn")))]
        {
            let builder = TlsConnector::builder().unwrap();
            ClientConnector {
                connector: builder.build().unwrap()
            }
        }

        #[cfg(not(any(feature="alpn", feature="tls")))]
        ClientConnector {}
    }
}

impl ClientConnector {

    #[cfg(feature="alpn")]
    /// Create `ClientConnector` actor with custom `SslConnector` instance.
    ///
    /// By default `ClientConnector` uses very simple ssl configuration.
    /// With `with_connector` method it is possible to use custom `SslConnector`
    /// object.
    ///
    /// ```rust
    /// # #![cfg(feature="alpn")]
    /// # extern crate actix;
    /// # extern crate actix_web;
    /// # extern crate futures;
    /// # use futures::Future;
    /// # use std::io::Write;
    /// extern crate openssl;
    /// use actix::prelude::*;
    /// use actix_web::client::{Connect, ClientConnector};
    ///
    /// use openssl::ssl::{SslMethod, SslConnector};
    ///
    /// fn main() {
    ///     let sys = System::new("test");
    ///
    ///     // Start `ClientConnector` with custom `SslConnector`
    ///     let ssl_conn = SslConnector::builder(SslMethod::tls()).unwrap().build();
    ///     let conn: Address<_> = ClientConnector::with_connector(ssl_conn).start();
    ///
    ///     Arbiter::handle().spawn({
    ///         conn.send(
    ///             Connect::new("https://www.rust-lang.org").unwrap()) // <- connect to host
    ///                 .map_err(|_| ())
    ///                 .and_then(|res| {
    ///                     if let Ok(mut stream) = res {
    ///                         stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    ///                     }
    /// #                   Arbiter::system().do_send(actix::msgs::SystemExit(0));
    ///                     Ok(())
    ///                 })
    ///     });
    ///
    ///     sys.run();
    /// }
    /// ```
    pub fn with_connector(connector: SslConnector) -> ClientConnector {
        ClientConnector { connector }
    }
}

impl Handler<Connect> for ClientConnector {
    type Result = ActorResponse<ClientConnector, Connection, ClientConnectorError>;

    fn handle(&mut self, msg: Connect, _: &mut Self::Context) -> Self::Result {
        let uri = &msg.uri;
        let conn_timeout = msg.conn_timeout;

        // host name is required
        if uri.host().is_none() {
            return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl))
        }

        // supported protocols
        let proto = match uri.scheme_part() {
            Some(scheme) => match Protocol::from(scheme.as_str()) {
                Some(proto) => proto,
                None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
            },
            None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
        };

        // check ssl availability
        if proto.is_secure() && !HAS_OPENSSL && !HAS_TLS {
            return ActorResponse::reply(Err(ClientConnectorError::SslIsNotSupported))
        }

        let host = uri.host().unwrap().to_owned();
        let port = uri.port().unwrap_or_else(|| proto.port());

        ActorResponse::async(
            Connector::from_registry()
                .send(ResolveConnect::host_and_port(&host, port)
                      .timeout(conn_timeout))
                .into_actor(self)
                .map_err(|_, _, _| ClientConnectorError::Disconnected)
                .and_then(move |res, _act, _| {
                    #[cfg(feature="alpn")]
                    match res {
                        Err(err) => fut::Either::B(fut::err(err.into())),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::Either::A(
                                    _act.connector.connect_async(&host, stream)
                                        .map_err(ClientConnectorError::SslError)
                                        .map(|stream| Connection{stream: Box::new(stream)})
                                        .into_actor(_act))
                            } else {
                                fut::Either::B(fut::ok(Connection{stream: Box::new(stream)}))
                            }
                        }
                    }

                    #[cfg(all(feature="tls", not(feature="alpn")))]
                    match res {
                        Err(err) => fut::Either::B(fut::err(err.into())),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::Either::A(
                                    _act.connector.connect_async(&host, stream)
                                        .map_err(ClientConnectorError::SslError)
                                        .map(|stream| Connection{stream: Box::new(stream)})
                                        .into_actor(_act))
                            } else {
                                fut::Either::B(fut::ok(Connection{stream: Box::new(stream)}))
                            }
                        }
                    }

                    #[cfg(not(any(feature="alpn", feature="tls")))]
                    match res {
                        Err(err) => fut::err(err.into()),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::err(ClientConnectorError::SslIsNotSupported)
                            } else {
                                fut::ok(Connection{stream: Box::new(stream)})
                            }
                        }
                    }
                }))
    }
}

#[derive(PartialEq, Hash, Debug, Clone, Copy)]
enum Protocol {
    Http,
    Https,
    Ws,
    Wss,
}

impl Protocol {
    fn from(s: &str) -> Option<Protocol> {
        match s {
            "http" => Some(Protocol::Http),
            "https" => Some(Protocol::Https),
            "ws" => Some(Protocol::Ws),
            "wss" => Some(Protocol::Wss),
            _ => None,
        }
    }

    fn is_secure(&self) -> bool {
        match *self {
            Protocol::Https | Protocol::Wss => true,
            _ => false,
        }
    }

    fn port(&self) -> u16 {
        match *self {
            Protocol::Http | Protocol::Ws => 80,
            Protocol::Https | Protocol::Wss => 443
        }
    }
}

pub struct Connection {
    stream: Box<IoStream>,
}

impl Connection {
    pub fn stream(&mut self) -> &mut IoStream {
        &mut *self.stream
    }

    pub fn from_stream<T: IoStream>(io: T) -> Connection {
        Connection{stream: Box::new(io)}
    }
}

impl IoStream for Connection {
    fn shutdown(&mut self, how: Shutdown) -> io::Result<()> {
        IoStream::shutdown(&mut *self.stream, how)
    }

    #[inline]
    fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
        IoStream::set_nodelay(&mut *self.stream, nodelay)
    }

    #[inline]
    fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
        IoStream::set_linger(&mut *self.stream, dur)
    }
}

impl io::Read for Connection {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream.read(buf)
    }
}

impl AsyncRead for Connection {}

impl io::Write for Connection {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stream.write(buf)
    }

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

impl AsyncWrite for Connection {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.stream.shutdown()
    }
}
<commit_msg>map connector timeout error<commit_after>use std::{io, time};
use std::net::Shutdown;
use std::time::Duration;

use actix::{fut, Actor, ActorFuture, Context,
            Handler, Message, ActorResponse, Supervised};
use actix::registry::ArbiterService;
use actix::fut::WrapFuture;
use actix::actors::{Connector, ConnectorError, Connect as ResolveConnect};

use http::{Uri, HttpTryFrom, Error as HttpError};
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};

#[cfg(feature="alpn")]
use openssl::ssl::{SslMethod, SslConnector, Error as OpensslError};
#[cfg(feature="alpn")]
use tokio_openssl::SslConnectorExt;
#[cfg(feature="alpn")]
use futures::Future;

#[cfg(all(feature="tls", not(feature="alpn")))]
use native_tls::{TlsConnector, Error as TlsError};
#[cfg(all(feature="tls", not(feature="alpn")))]
use tokio_tls::TlsConnectorExt;
#[cfg(all(feature="tls", not(feature="alpn")))]
use futures::Future;

use {HAS_OPENSSL, HAS_TLS};
use server::IoStream;

#[derive(Debug)]
/// `Connect` type represents message that can be send to `ClientConnector`
/// with connection request.
pub struct Connect {
    pub uri: Uri,
    pub conn_timeout: Duration,
}

impl Connect {
    /// Create `Connect` message for specified `Uri`
    pub fn new<U>(uri: U) -> Result<Connect, HttpError> where Uri: HttpTryFrom<U> {
        Ok(Connect {
            uri: Uri::try_from(uri).map_err(|e| e.into())?,
            conn_timeout: Duration::from_secs(1)
        })
    }
}

impl Message for Connect {
    type Result = Result<Connection, ClientConnectorError>;
}

/// A set of errors that can occur during connecting to a http host
#[derive(Fail, Debug)]
pub enum ClientConnectorError {
    /// Invalid url
    #[fail(display="Invalid url")]
    InvalidUrl,

    /// SSL feature is not enabled
    #[fail(display="SSL is not supported")]
    SslIsNotSupported,

    /// SSL error
    #[cfg(feature="alpn")]
    #[fail(display="{}", _0)]
    SslError(#[cause] OpensslError),

    /// SSL error
    #[cfg(all(feature="tls", not(feature="alpn")))]
    #[fail(display="{}", _0)]
    SslError(#[cause] TlsError),

    /// Connection error
    #[fail(display = "{}", _0)]
    Connector(#[cause] ConnectorError),

    /// Connecting took too long
    #[fail(display = "Timeout out while establishing connection")]
    Timeout,

    /// Connector has been disconnected
    #[fail(display = "Internal error: connector has been disconnected")]
    Disconnected,

    /// Connection io error
    #[fail(display = "{}", _0)]
    IoError(#[cause] io::Error),
}

impl From<ConnectorError> for ClientConnectorError {
    fn from(err: ConnectorError) -> ClientConnectorError {
        match err {
            ConnectorError::Timeout => ClientConnectorError::Timeout,
            _ => ClientConnectorError::Connector(err)
        }
    }
}

pub struct ClientConnector {
    #[cfg(all(feature="alpn"))]
    connector: SslConnector,
    #[cfg(all(feature="tls", not(feature="alpn")))]
    connector: TlsConnector,
}

impl Actor for ClientConnector {
    type Context = Context<ClientConnector>;
}

impl Supervised for ClientConnector {}

impl ArbiterService for ClientConnector {}

impl Default for ClientConnector {
    fn default() -> ClientConnector {
        #[cfg(all(feature="alpn"))]
        {
            let builder = SslConnector::builder(SslMethod::tls()).unwrap();
            ClientConnector {
                connector: builder.build()
            }
        }
        #[cfg(all(feature="tls", not(feature="alpn")))]
        {
            let builder = TlsConnector::builder().unwrap();
            ClientConnector {
                connector: builder.build().unwrap()
            }
        }

        #[cfg(not(any(feature="alpn", feature="tls")))]
        ClientConnector {}
    }
}

impl ClientConnector {

    #[cfg(feature="alpn")]
    /// Create `ClientConnector` actor with custom `SslConnector` instance.
    ///
    /// By default `ClientConnector` uses very simple ssl configuration.
    /// With `with_connector` method it is possible to use custom `SslConnector`
    /// object.
    ///
    /// ```rust
    /// # #![cfg(feature="alpn")]
    /// # extern crate actix;
    /// # extern crate actix_web;
    /// # extern crate futures;
    /// # use futures::Future;
    /// # use std::io::Write;
    /// extern crate openssl;
    /// use actix::prelude::*;
    /// use actix_web::client::{Connect, ClientConnector};
    ///
    /// use openssl::ssl::{SslMethod, SslConnector};
    ///
    /// fn main() {
    ///     let sys = System::new("test");
    ///
    ///     // Start `ClientConnector` with custom `SslConnector`
    ///     let ssl_conn = SslConnector::builder(SslMethod::tls()).unwrap().build();
    ///     let conn: Address<_> = ClientConnector::with_connector(ssl_conn).start();
    ///
    ///     Arbiter::handle().spawn({
    ///         conn.send(
    ///             Connect::new("https://www.rust-lang.org").unwrap()) // <- connect to host
    ///                 .map_err(|_| ())
    ///                 .and_then(|res| {
    ///                     if let Ok(mut stream) = res {
    ///                         stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    ///                     }
    /// #                   Arbiter::system().do_send(actix::msgs::SystemExit(0));
    ///                     Ok(())
    ///                 })
    ///     });
    ///
    ///     sys.run();
    /// }
    /// ```
    pub fn with_connector(connector: SslConnector) -> ClientConnector {
        ClientConnector { connector }
    }
}

impl Handler<Connect> for ClientConnector {
    type Result = ActorResponse<ClientConnector, Connection, ClientConnectorError>;

    fn handle(&mut self, msg: Connect, _: &mut Self::Context) -> Self::Result {
        let uri = &msg.uri;
        let conn_timeout = msg.conn_timeout;

        // host name is required
        if uri.host().is_none() {
            return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl))
        }

        // supported protocols
        let proto = match uri.scheme_part() {
            Some(scheme) => match Protocol::from(scheme.as_str()) {
                Some(proto) => proto,
                None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
            },
            None => return ActorResponse::reply(Err(ClientConnectorError::InvalidUrl)),
        };

        // check ssl availability
        if proto.is_secure() && !HAS_OPENSSL && !HAS_TLS {
            return ActorResponse::reply(Err(ClientConnectorError::SslIsNotSupported))
        }

        let host = uri.host().unwrap().to_owned();
        let port = uri.port().unwrap_or_else(|| proto.port());

        ActorResponse::async(
            Connector::from_registry()
                .send(ResolveConnect::host_and_port(&host, port)
                      .timeout(conn_timeout))
                .into_actor(self)
                .map_err(|_, _, _| ClientConnectorError::Disconnected)
                .and_then(move |res, _act, _| {
                    #[cfg(feature="alpn")]
                    match res {
                        Err(err) => fut::Either::B(fut::err(err.into())),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::Either::A(
                                    _act.connector.connect_async(&host, stream)
                                        .map_err(ClientConnectorError::SslError)
                                        .map(|stream| Connection{stream: Box::new(stream)})
                                        .into_actor(_act))
                            } else {
                                fut::Either::B(fut::ok(Connection{stream: Box::new(stream)}))
                            }
                        }
                    }

                    #[cfg(all(feature="tls", not(feature="alpn")))]
                    match res {
                        Err(err) => fut::Either::B(fut::err(err.into())),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::Either::A(
                                    _act.connector.connect_async(&host, stream)
                                        .map_err(ClientConnectorError::SslError)
                                        .map(|stream| Connection{stream: Box::new(stream)})
                                        .into_actor(_act))
                            } else {
                                fut::Either::B(fut::ok(Connection{stream: Box::new(stream)}))
                            }
                        }
                    }

                    #[cfg(not(any(feature="alpn", feature="tls")))]
                    match res {
                        Err(err) => fut::err(err.into()),
                        Ok(stream) => {
                            if proto.is_secure() {
                                fut::err(ClientConnectorError::SslIsNotSupported)
                            } else {
                                fut::ok(Connection{stream: Box::new(stream)})
                            }
                        }
                    }
                }))
    }
}

#[derive(PartialEq, Hash, Debug, Clone, Copy)]
enum Protocol {
    Http,
    Https,
    Ws,
    Wss,
}

impl Protocol {
    fn from(s: &str) -> Option<Protocol> {
        match s {
            "http" => Some(Protocol::Http),
            "https" => Some(Protocol::Https),
            "ws" => Some(Protocol::Ws),
            "wss" => Some(Protocol::Wss),
            _ => None,
        }
    }

    fn is_secure(&self) -> bool {
        match *self {
            Protocol::Https | Protocol::Wss => true,
            _ => false,
        }
    }

    fn port(&self) -> u16 {
        match *self {
            Protocol::Http | Protocol::Ws => 80,
            Protocol::Https | Protocol::Wss => 443
        }
    }
}

pub struct Connection {
    stream: Box<IoStream>,
}

impl Connection {
    pub fn stream(&mut self) -> &mut IoStream {
        &mut *self.stream
    }

    pub fn from_stream<T: IoStream>(io: T) -> Connection {
        Connection{stream: Box::new(io)}
    }
}

impl IoStream for Connection {
    fn shutdown(&mut self, how: Shutdown) -> io::Result<()> {
        IoStream::shutdown(&mut *self.stream, how)
    }

    #[inline]
    fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()> {
        IoStream::set_nodelay(&mut *self.stream, nodelay)
    }

    #[inline]
    fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()> {
        IoStream::set_linger(&mut *self.stream, dur)
    }
}

impl io::Read for Connection {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream.read(buf)
    }
}

impl AsyncRead for Connection {}

impl io::Write for Connection {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.stream.write(buf)
    }

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

impl AsyncWrite for Connection {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.stream.shutdown()
    }
}
<|endoftext|>


<commit_before>//! Enumeration of all supported IRCv3 capability extensions.

/// List of all supported IRCv3 capability extensions from the
/// [IRCv3 specifications](http://ircv3.net/irc/).
#[derive(Debug, PartialEq)]
pub enum Capability {
    /// [multi-prefix](http://ircv3.net/specs/extensions/multi-prefix-3.1.html)
    MultiPrefix,
    /// [account-notify](http://ircv3.net/specs/extensions/account-notify-3.1.html)
    AccountNotify,
    /// [away-notify](http://ircv3.net/specs/extensions/away-notify-3.1.html)
    AwayNotify,
    /// [extended-join](http://ircv3.net/specs/extensions/extended-join-3.1.html)
    ExtendedJoin,
    /// [monitor](http://ircv3.net/specs/core/monitor-3.2.html)
    Monitor,
    /// [account-tag](http://ircv3.net/specs/extensions/account-tag-3.2.html)
    AccountTag,
    /// [cap-notify](http://ircv3.net/specs/extensions/cap-notify-3.2.html)
    CapNotify,
    /// [chghost](http://ircv3.net/specs/extensions/chghost-3.2.html)
    ChgHost,
    /// [echo-message](http://ircv3.net/specs/extensions/echo-message-3.2.html)
    EchoMessage,
    /// [invite-notify](http://ircv3.net/specs/extensions/invite-notify-3.2.html)
    InviteNotify,
    /// [server-time](http://ircv3.net/specs/extensions/server-time-3.2.html)
    ServerTime,
    /// [userhost-in-names](http://ircv3.net/specs/extensions/userhost-in-names-3.2.html)
    UserhostInNames,
}

/// List of IRCv3 capability negotiation versions.
pub enum NegotiationVersion {
    /// [IRCv3.1](http://ircv3.net/specs/core/capability-negotiation-3.1.html)
    V301,
    /// [IRCv3.2](http://ircv3.net/specs/core/capability-negotiation-3.2.html)
    V302,
}

impl AsRef<str> for Capability {
    fn as_ref(&self) -> &str {
        match *self {
            Capability::MultiPrefix => "multi-prefix",
            Capability::AccountNotify => "account-notify",
            Capability::AwayNotify => "away-notify",
            Capability::ExtendedJoin => "extended-join",
            Capability::Monitor => "monitor",
            Capability::AccountTag => "account-tag",
            Capability::CapNotify => "cap-notify",
            Capability::ChgHost => "chghost",
            Capability::EchoMessage => "echo-message",
            Capability::InviteNotify => "invite-notify",
            Capability::ServerTime => "server-time",
            Capability::UserhostInNames => "userhost-in-names",
        }
    }
}

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

    #[test]
    fn to_str() {
        assert_eq!(MultiPrefix.as_ref(), "multi-prefix");
        assert_eq!(AccountNotify.as_ref(), "account-notify");
        assert_eq!(AwayNotify.as_ref(), "away-notify");
        assert_eq!(ExtendedJoin.as_ref(), "extended-join");
        assert_eq!(Monitor.as_ref(), "monitor");
        assert_eq!(AccountTag.as_ref(), "account-tag");
        assert_eq!(CapNotify.as_ref(), "cap-notify");
        assert_eq!(ChgHost.as_ref(), "chghost");
        assert_eq!(EchoMessage.as_ref(), "echo-message");
        assert_eq!(InviteNotify.as_ref(), "invite-notify");
        assert_eq!(ServerTime.as_ref(), "server-time");
        assert_eq!(UserhostInNames.as_ref(), "userhost-in-names");
    }
}
<commit_msg>Added custom capability for requesting additional extensions.<commit_after>//! Enumeration of all supported IRCv3 capability extensions.

/// List of all supported IRCv3 capability extensions from the
/// [IRCv3 specifications](http://ircv3.net/irc/).
#[derive(Debug, PartialEq)]
pub enum Capability {
    /// [multi-prefix](http://ircv3.net/specs/extensions/multi-prefix-3.1.html)
    MultiPrefix,
    /// [account-notify](http://ircv3.net/specs/extensions/account-notify-3.1.html)
    AccountNotify,
    /// [away-notify](http://ircv3.net/specs/extensions/away-notify-3.1.html)
    AwayNotify,
    /// [extended-join](http://ircv3.net/specs/extensions/extended-join-3.1.html)
    ExtendedJoin,
    /// [monitor](http://ircv3.net/specs/core/monitor-3.2.html)
    Monitor,
    /// [account-tag](http://ircv3.net/specs/extensions/account-tag-3.2.html)
    AccountTag,
    /// [cap-notify](http://ircv3.net/specs/extensions/cap-notify-3.2.html)
    CapNotify,
    /// [chghost](http://ircv3.net/specs/extensions/chghost-3.2.html)
    ChgHost,
    /// [echo-message](http://ircv3.net/specs/extensions/echo-message-3.2.html)
    EchoMessage,
    /// [invite-notify](http://ircv3.net/specs/extensions/invite-notify-3.2.html)
    InviteNotify,
    /// [server-time](http://ircv3.net/specs/extensions/server-time-3.2.html)
    ServerTime,
    /// [userhost-in-names](http://ircv3.net/specs/extensions/userhost-in-names-3.2.html)
    UserhostInNames,
    /// Custom IRCv3 capability extensions
    Custom(&'static str),
}

/// List of IRCv3 capability negotiation versions.
pub enum NegotiationVersion {
    /// [IRCv3.1](http://ircv3.net/specs/core/capability-negotiation-3.1.html)
    V301,
    /// [IRCv3.2](http://ircv3.net/specs/core/capability-negotiation-3.2.html)
    V302,
}

impl AsRef<str> for Capability {
    fn as_ref(&self) -> &str {
        match *self {
            Capability::MultiPrefix => "multi-prefix",
            Capability::AccountNotify => "account-notify",
            Capability::AwayNotify => "away-notify",
            Capability::ExtendedJoin => "extended-join",
            Capability::Monitor => "monitor",
            Capability::AccountTag => "account-tag",
            Capability::CapNotify => "cap-notify",
            Capability::ChgHost => "chghost",
            Capability::EchoMessage => "echo-message",
            Capability::InviteNotify => "invite-notify",
            Capability::ServerTime => "server-time",
            Capability::UserhostInNames => "userhost-in-names",
            Capability::Custom(s) => s,
        }
    }
}

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

    #[test]
    fn to_str() {
        assert_eq!(MultiPrefix.as_ref(), "multi-prefix");
        assert_eq!(AccountNotify.as_ref(), "account-notify");
        assert_eq!(AwayNotify.as_ref(), "away-notify");
        assert_eq!(ExtendedJoin.as_ref(), "extended-join");
        assert_eq!(Monitor.as_ref(), "monitor");
        assert_eq!(AccountTag.as_ref(), "account-tag");
        assert_eq!(CapNotify.as_ref(), "cap-notify");
        assert_eq!(ChgHost.as_ref(), "chghost");
        assert_eq!(EchoMessage.as_ref(), "echo-message");
        assert_eq!(InviteNotify.as_ref(), "invite-notify");
        assert_eq!(ServerTime.as_ref(), "server-time");
        assert_eq!(UserhostInNames.as_ref(), "userhost-in-names");
        assert_eq!(Custom("example").as_ref(), "example");
    }
}
<|endoftext|>


<commit_before>
extern crate ndarray;
pub extern crate rayon;

use rayon::par_iter::ParallelIterator;

pub mod prelude {
    pub use NdarrayIntoParallelIterator;
    #[doc(no_inline)]
    pub use rayon::prelude::{ParallelIterator};
}

pub trait NdarrayIntoParallelIterator {
    type Iter: ParallelIterator<Item=Self::Item>;
    type Item: Send;
    fn into_par_iter(self) -> Self::Iter;
}

pub use par::Parallel;

mod par;
<commit_msg>parallel: Add doc<commit_after>//! Parallelization features for ndarray.
//!
//! The array views and references to owned arrays all implement
//! `IntoParallelIterator`; the default parallel iterators (each element by
//! reference or mutable reference) have no ordering guarantee in their parallel
//! implementations.
//!
//! `.axis_iter()` and `.axis_iter_mut()` also have parallel counterparts.
//!
//! # Examples
//!
//! Compute the exponential of each element in an array, parallelized.
//!
//! ```
//! extern crate ndarray;
//! extern crate ndarray_parallel;
//!
//! use ndarray::Array2;
//! use ndarray_parallel::prelude::*;
//!
//! fn main() {
//!     let mut a = Array2::<f64>::zeros((128, 128));
//!     a.par_iter_mut().for_each(|x| *x = x.exp());
//! }
//! ```
//!
//! Use the parallel `.axis_iter()` to compute the sum of each row.
//!
//! ```
//! extern crate ndarray;
//! extern crate ndarray_parallel;
//!
//! use ndarray::Array;
//! use ndarray::Axis;
//! use ndarray_parallel::prelude::*;
//!
//! fn main() {
//!     let a = Array::linspace(0., 63., 64).into_shape((4, 16)).unwrap();
//!     let mut sums = Vec::new();
//!     a.axis_iter(Axis(0))
//!      .into_par_iter()
//!      .map(|row| row.scalar_sum())
//!      .collect_into(&mut sums);
//!
//!     assert_eq!(sums, [120., 376., 632., 888.]);
//! }
//! ```

extern crate ndarray;
pub extern crate rayon;

use rayon::par_iter::ParallelIterator;

pub mod prelude {
    pub use NdarrayIntoParallelIterator;
    #[doc(no_inline)]
    pub use rayon::prelude::{ParallelIterator};
}

pub trait NdarrayIntoParallelIterator {
    type Iter: ParallelIterator<Item=Self::Item>;
    type Item: Send;
    fn into_par_iter(self) -> Self::Iter;
}

pub use par::Parallel;

mod par;
<|endoftext|>


<commit_before>extern crate askama;
extern crate proc_macro;
extern crate syn;

use proc_macro::TokenStream;

fn get_path_from_attrs(attrs: &[syn::Attribute]) -> String {
    let attr = attrs.iter().find(|a| a.name() == "template").unwrap();
    if let syn::MetaItem::List(_, ref inner) = attr.value {
        if let syn::NestedMetaItem::MetaItem(ref item) = inner[0] {
            if let &syn::MetaItem::NameValue(ref key, ref val) = item {
                assert_eq!(key.as_ref(), "path");
                if let &syn::Lit::Str(ref s, _) = val {
                    return s.clone();
                }
            }
        }
    }
    panic!("template path not found in struct attributes");
}

#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    let ast = syn::parse_derive_input(&source).unwrap();
    let _ctx = match ast.body {
        syn::Body::Struct(ref data) => data,
        _ => panic!("#[derive(Template)] can only be used with structs"),
    };

    let path = get_path_from_attrs(&ast.attrs);
    askama::build_template(&path, &ast).parse().unwrap()
}
<commit_msg>Simplify derive_template() function<commit_after>extern crate askama;
extern crate proc_macro;
extern crate syn;

use proc_macro::TokenStream;

fn get_path_from_attrs(attrs: &[syn::Attribute]) -> String {
    let attr = attrs.iter().find(|a| a.name() == "template").unwrap();
    if let syn::MetaItem::List(_, ref inner) = attr.value {
        if let syn::NestedMetaItem::MetaItem(ref item) = inner[0] {
            if let &syn::MetaItem::NameValue(ref key, ref val) = item {
                assert_eq!(key.as_ref(), "path");
                if let &syn::Lit::Str(ref s, _) = val {
                    return s.clone();
                }
            }
        }
    }
    panic!("template path not found in struct attributes");
}

#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
    let ast = syn::parse_derive_input(&input.to_string()).unwrap();
    match ast.body {
        syn::Body::Struct(ref data) => data,
        _ => panic!("#[derive(Template)] can only be used with structs"),
    };
    let path = get_path_from_attrs(&ast.attrs);
    askama::build_template(&path, &ast).parse().unwrap()
}
<|endoftext|>


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

//!
//! A token tree represents the results of applying the tokenizer to an input string. It can output its contents as a series of tokens,
//! which makes it suitable for repeatedly performing pattern matches. Matching against an already tokenized string produces a tree of
//! matches.
//!

use std::ops::Range;

use super::countable::*;
use super::tokenizer::*;
use super::symbol_reader::*;
use super::symbol_range_dfa::*;

///
/// An annotated stream represents an original stream, with ranges tagged with tokens. This can be used to map between a
/// tokenized stream and the original characters.
///
pub struct AnnotatedStream<InputType, TokenType> {
    /// The original stream that was tokenized
    original: Vec<InputType>,

    /// The tokenized version and where in the original they appear, in order
    tokenized: Vec<(TokenType, Range<usize>)>
}

impl<InputSymbol: Clone+Ord+Countable, OutputSymbol: Clone+Ord+'static> AnnotatedStream<InputSymbol, OutputSymbol> {
    ///
    /// Given a stream and a DFA, tokenizes the stream and annotates it with the appropriate tokens
    ///
    pub fn from_tokenizer<Reader: SymbolReader<InputSymbol>>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, reader: &mut Reader) -> AnnotatedStream<InputSymbol, OutputSymbol> {
        // Capture the contents of the original reader (we store them in the result)
        let     original = reader.to_vec();
        let mut tokens   = vec![];

        {
            // Create a new reader to read our captured symbols
            let token_reader  = original.read_symbols();
            let mut tokenizer = Tokenizer::new_prepared(token_reader, dfa);

            // Start tokenizing
            let mut pos: usize = 0;

            loop {
                // Tokenize the next symbol
                let next_token  = tokenizer.next_symbol();
                let final_pos   = tokenizer.get_source_position();

                if let Some(output) = next_token {
                    // Got a token
                    tokens.push((output, pos..final_pos));

                    // Next token begins after this one
                    pos = final_pos;
                } else if !tokenizer.at_end_of_reader() {
                    // Skip tokens that don't form a match (returned none + not at the end of the reader)
                    // Try again in case there are further tokens
                    pos += 1;
                    tokenizer.skip_input();
                } else {
                    // Reached the end of the input
                    break;
                }
            }
        }

        // Annotated stream is ready
        AnnotatedStream { original: original, tokenized: tokens }
    }

    ///
    /// Reads the original stream for the original input for this stream
    ///
    pub fn read_input<'a>(&'a self) -> Box<SymbolReader<InputSymbol> + 'a> {
        Box::new(self.original.read_symbols())
    }

    ///
    /// Reads the tokenized output stream (only for the symbols that were recognised)
    ///
    pub fn read_output<'a>(&'a self) -> Box<SymbolReader<OutputSymbol> + 'a> {
        let full_output  = self.tokenized.read_symbols();
        let only_symbols = full_output.map_symbols(|(token, _)| token);

        Box::new(only_symbols)
    }

    ///
    /// Reads the annotated stream as a series of tokens
    ///
    pub fn read_tokens<'a>(&'a self) -> Box<SymbolReader<Token<'a, InputSymbol, OutputSymbol>> + 'a> {
        let full_output = self.tokenized.read_symbols();
        let with_tokens = full_output.map_symbols(move |(output, location)| {
            Token {
                location: location.clone(),
                matched:  &self.original[location],
                output:   output
            }
        });

        Box::new(with_tokens)
    }

    ///
    /// Finds the index into the tokenized list of the token corresponding to the specified position (None if there is none)
    ///
    fn find_token_index(&self, position: usize) -> Option<usize> {
        // Try to find the specified position: assumes the tokens are in order (which they are if we generated this stream from left to right)
        let found = self.tokenized.binary_search_by(|&(_, ref location)| location.start.cmp(&position));

        // We're only searching on the start position: if we don't find it exactly, then the token might be in the preceding index
        match found {
            Ok(index) => Some(index),

            Err(index) => {
                if index == 0 {
                    None
                } else {
                    if self.tokenized[index-1].1.end > position {
                        Some(index-1)
                    } else {
                        None
                    }
                }
            }
        }
    }

    ///
    /// Finds the token at the specified position in this stream
    ///
    pub fn find_token<'a>(&'a self, position: usize) -> Option<Token<'a, InputSymbol, OutputSymbol>> {
        let found_index = self.find_token_index(position);

        // Build a token for this location
        found_index.map(move |index| {
            let (ref output, ref location) = self.tokenized[index];

            Token {
                location: location.clone(),
                output:   output.clone(),
                matched:  &self.original[location.clone()]
            }
        })
    }
}

///
/// A token represents an individual item in an annotated stream
///
#[derive(Eq, PartialEq, Clone)]
pub struct Token<'a, InputSymbol: 'a, OutputSymbol> {
    /// Where this token appears in the output
    pub location: Range<usize>,

    /// The input symbols that were matched for this token
    pub matched: &'a [InputSymbol],

    /// The output symbol that was matched for this token
    pub output: OutputSymbol
}

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

    #[test]
    fn can_annotate_stream() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            Digit,
            Whitespace
        }

        let mut token_matcher = TokenMatcher::new();
        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(0), TestToken::Digit);
        token_matcher.add_pattern(" ".repeat_forever(0), TestToken::Whitespace);

        let dfa   = token_matcher.prepare_to_match();
        let input = "12 42 13";

        let annotated = AnnotatedStream::from_tokenizer(&dfa, &mut input.read_symbols());

        let annotated_input  = annotated.read_input().to_vec();
        let annotated_output = annotated.read_output().to_vec();
        let annotated_tokens = annotated.read_tokens().to_vec();

        assert!(annotated_input == vec!['1', '2', ' ', '4', '2', ' ', '1', '3']);
        assert!(annotated_output == vec![TestToken::Digit, TestToken::Whitespace, TestToken::Digit, TestToken::Whitespace, TestToken::Digit]);

        assert!(annotated_tokens[0].location.start == 0);
        assert!(annotated_tokens[0].location.end == 2);
        assert!(annotated_tokens[0].output == TestToken::Digit);
        assert!(annotated_tokens[0].matched == &['1', '2']);
    }

    #[test]
    fn can_find_token() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            Digit,
            Whitespace
        }

        let mut token_matcher = TokenMatcher::new();
        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(0), TestToken::Digit);
        token_matcher.add_pattern(" ".repeat_forever(0), TestToken::Whitespace);

        let dfa   = token_matcher.prepare_to_match();
        let input = "12 42 13";

        let annotated = AnnotatedStream::from_tokenizer(&dfa, &mut input.read_symbols());

        let fortytwo = annotated.find_token(4).expect("No token");
        let whitespace = annotated.find_token(5).expect("No token");

        assert!(fortytwo.location.start == 3);
        assert!(fortytwo.location.end == 5);
        assert!(fortytwo.output == TestToken::Digit);
        assert!(fortytwo.matched == &['4', '2']);

        assert!(whitespace.location.start == 5);
        assert!(whitespace.location.end == 6);
        assert!(whitespace.output == TestToken::Whitespace);
        assert!(whitespace.matched == &[' ']);
    }
}
<commit_msg>Change the internal find so that we can return a ‘bad’ index if there is one<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A token tree represents the results of applying the tokenizer to an input string. It can output its contents as a series of tokens,
//! which makes it suitable for repeatedly performing pattern matches. Matching against an already tokenized string produces a tree of
//! matches.
//!

use std::ops::Range;

use super::countable::*;
use super::tokenizer::*;
use super::symbol_reader::*;
use super::symbol_range_dfa::*;

///
/// An annotated stream represents an original stream, with ranges tagged with tokens. This can be used to map between a
/// tokenized stream and the original characters.
///
pub struct AnnotatedStream<InputType, TokenType> {
    /// The original stream that was tokenized
    original: Vec<InputType>,

    /// The tokenized version and where in the original they appear, in order
    tokenized: Vec<(TokenType, Range<usize>)>
}

impl<InputSymbol: Clone+Ord+Countable, OutputSymbol: Clone+Ord+'static> AnnotatedStream<InputSymbol, OutputSymbol> {
    ///
    /// Given a stream and a DFA, tokenizes the stream and annotates it with the appropriate tokens
    ///
    pub fn from_tokenizer<Reader: SymbolReader<InputSymbol>>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, reader: &mut Reader) -> AnnotatedStream<InputSymbol, OutputSymbol> {
        // Capture the contents of the original reader (we store them in the result)
        let     original = reader.to_vec();
        let mut tokens   = vec![];

        {
            // Create a new reader to read our captured symbols
            let token_reader  = original.read_symbols();
            let mut tokenizer = Tokenizer::new_prepared(token_reader, dfa);

            // Start tokenizing
            let mut pos: usize = 0;

            loop {
                // Tokenize the next symbol
                let next_token  = tokenizer.next_symbol();
                let final_pos   = tokenizer.get_source_position();

                if let Some(output) = next_token {
                    // Got a token
                    tokens.push((output, pos..final_pos));

                    // Next token begins after this one
                    pos = final_pos;
                } else if !tokenizer.at_end_of_reader() {
                    // Skip tokens that don't form a match (returned none + not at the end of the reader)
                    // Try again in case there are further tokens
                    pos += 1;
                    tokenizer.skip_input();
                } else {
                    // Reached the end of the input
                    break;
                }
            }
        }

        // Annotated stream is ready
        AnnotatedStream { original: original, tokenized: tokens }
    }

    ///
    /// Reads the original stream for the original input for this stream
    ///
    pub fn read_input<'a>(&'a self) -> Box<SymbolReader<InputSymbol> + 'a> {
        Box::new(self.original.read_symbols())
    }

    ///
    /// Reads the tokenized output stream (only for the symbols that were recognised)
    ///
    pub fn read_output<'a>(&'a self) -> Box<SymbolReader<OutputSymbol> + 'a> {
        let full_output  = self.tokenized.read_symbols();
        let only_symbols = full_output.map_symbols(|(token, _)| token);

        Box::new(only_symbols)
    }

    ///
    /// Reads the annotated stream as a series of tokens
    ///
    pub fn read_tokens<'a>(&'a self) -> Box<SymbolReader<Token<'a, InputSymbol, OutputSymbol>> + 'a> {
        let full_output = self.tokenized.read_symbols();
        let with_tokens = full_output.map_symbols(move |(output, location)| {
            Token {
                location: location.clone(),
                matched:  &self.original[location],
                output:   output
            }
        });

        Box::new(with_tokens)
    }

    ///
    /// Finds the index into the tokenized list of the token corresponding to the specified position
    ///
    /// Returns Err(index_after) if there's no range corresponding to the position in this stream
    ///
    fn find_token_index(&self, position: usize) -> Result<usize, usize> {
        // Try to find the specified position: assumes the tokens are in order (which they are if we generated this stream from left to right)
        let found = self.tokenized.binary_search_by(|&(_, ref location)| location.start.cmp(&position));

        // We're only searching on the start position: if we don't find it exactly, then the token might be in the preceding index
        match found {
            Ok(index) => Ok(index),

            Err(index) => {
                if index == 0 {
                    Err(0)
                } else {
                    if self.tokenized[index-1].1.end > position {
                        Ok(index-1)
                    } else {
                        Err(index)
                    }
                }
            }
        }
    }

    ///
    /// Finds the token at the specified position in this stream
    ///
    pub fn find_token<'a>(&'a self, position: usize) -> Option<Token<'a, InputSymbol, OutputSymbol>> {
        let found_index = self.find_token_index(position).ok();

        // Build a token for this location
        found_index.map(move |index| {
            let (ref output, ref location) = self.tokenized[index];

            Token {
                location: location.clone(),
                output:   output.clone(),
                matched:  &self.original[location.clone()]
            }
        })
    }
}

///
/// A token represents an individual item in an annotated stream
///
#[derive(Eq, PartialEq, Clone)]
pub struct Token<'a, InputSymbol: 'a, OutputSymbol> {
    /// Where this token appears in the output
    pub location: Range<usize>,

    /// The input symbols that were matched for this token
    pub matched: &'a [InputSymbol],

    /// The output symbol that was matched for this token
    pub output: OutputSymbol
}

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

    #[test]
    fn can_annotate_stream() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            Digit,
            Whitespace
        }

        let mut token_matcher = TokenMatcher::new();
        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(0), TestToken::Digit);
        token_matcher.add_pattern(" ".repeat_forever(0), TestToken::Whitespace);

        let dfa   = token_matcher.prepare_to_match();
        let input = "12 42 13";

        let annotated = AnnotatedStream::from_tokenizer(&dfa, &mut input.read_symbols());

        let annotated_input  = annotated.read_input().to_vec();
        let annotated_output = annotated.read_output().to_vec();
        let annotated_tokens = annotated.read_tokens().to_vec();

        assert!(annotated_input == vec!['1', '2', ' ', '4', '2', ' ', '1', '3']);
        assert!(annotated_output == vec![TestToken::Digit, TestToken::Whitespace, TestToken::Digit, TestToken::Whitespace, TestToken::Digit]);

        assert!(annotated_tokens[0].location.start == 0);
        assert!(annotated_tokens[0].location.end == 2);
        assert!(annotated_tokens[0].output == TestToken::Digit);
        assert!(annotated_tokens[0].matched == &['1', '2']);
    }

    #[test]
    fn can_find_token() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            Digit,
            Whitespace
        }

        let mut token_matcher = TokenMatcher::new();
        token_matcher.add_pattern(MatchRange('0', '9').repeat_forever(0), TestToken::Digit);
        token_matcher.add_pattern(" ".repeat_forever(0), TestToken::Whitespace);

        let dfa   = token_matcher.prepare_to_match();
        let input = "12 42 13";

        let annotated = AnnotatedStream::from_tokenizer(&dfa, &mut input.read_symbols());

        let fortytwo = annotated.find_token(4).expect("No token");
        let whitespace = annotated.find_token(5).expect("No token");

        assert!(fortytwo.location.start == 3);
        assert!(fortytwo.location.end == 5);
        assert!(fortytwo.output == TestToken::Digit);
        assert!(fortytwo.matched == &['4', '2']);

        assert!(whitespace.location.start == 5);
        assert!(whitespace.location.end == 6);
        assert!(whitespace.output == TestToken::Whitespace);
        assert!(whitespace.matched == &[' ']);
    }
}
<|endoftext|>


<commit_before>extern crate askama;
#[macro_use]
extern crate criterion;

use askama::Template;
use criterion::Criterion;

criterion_main!(benches);
criterion_group!(benches, functions);

fn functions(c: &mut Criterion) {
    c.bench_function("Big table", |b| big_table(b, &100));
    c.bench_function("Teams", |b| teams(b));
}

fn big_table(b: &mut criterion::Bencher, size: &usize) {
    let mut table = Vec::with_capacity(*size);
    for _ in 0..*size {
        let mut inner = Vec::with_capacity(*size);
        for i in 0..*size {
            inner.push(i);
        }
        table.push(inner);
    }
    let ctx = BigTable { table };
    b.iter(|| ctx.render().unwrap());
}

#[derive(Template)]
#[template(path = "big-table.html")]
struct BigTable {
    table: Vec<Vec<usize>>,
}

fn teams(b: &mut criterion::Bencher) {
    let teams = Teams {
        year: 2015,
        teams: vec![
            Team {
                name: "Jiangsu".into(),
                score: 43,
            },
            Team {
                name: "Beijing".into(),
                score: 27,
            },
            Team {
                name: "Guangzhou".into(),
                score: 22,
            },
            Team {
                name: "Shandong".into(),
                score: 12,
            },
        ],
    };
    b.iter(|| teams.render().unwrap());
}

#[derive(Template)]
#[template(path = "teams.html")]
struct Teams {
    year: u16,
    teams: Vec<Team>,
}

struct Team {
    name: String,
    score: u8,
}
<commit_msg>Add bench for escaping<commit_after>extern crate askama;
#[macro_use]
extern crate criterion;

use askama::Template;
use criterion::Criterion;

criterion_main!(benches);
criterion_group!(benches, functions);

fn functions(c: &mut Criterion) {
    c.bench_function("Big table", |b| big_table(b, &100));
    c.bench_function("Teams", teams);
    c.bench_function("Escaping", escaping);
}

fn big_table(b: &mut criterion::Bencher, size: &usize) {
    let mut table = Vec::with_capacity(*size);
    for _ in 0..*size {
        let mut inner = Vec::with_capacity(*size);
        for i in 0..*size {
            inner.push(i);
        }
        table.push(inner);
    }
    let ctx = BigTable { table };
    b.iter(|| ctx.render().unwrap());
}

#[derive(Template)]
#[template(path = "big-table.html")]
struct BigTable {
    table: Vec<Vec<usize>>,
}

fn teams(b: &mut criterion::Bencher) {
    let teams = Teams {
        year: 2015,
        teams: vec![
            Team {
                name: "Jiangsu".into(),
                score: 43,
            },
            Team {
                name: "Beijing".into(),
                score: 27,
            },
            Team {
                name: "Guangzhou".into(),
                score: 22,
            },
            Team {
                name: "Shandong".into(),
                score: 12,
            },
        ],
    };
    b.iter(|| teams.render().unwrap());
}

#[derive(Template)]
#[template(path = "teams.html")]
struct Teams {
    year: u16,
    teams: Vec<Team>,
}

struct Team {
    name: String,
    score: u8,
}

fn escaping(b: &mut criterion::Bencher) {
    let string_long = r#"
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris consequat tellus sit
    amet ornare fermentum. Etiam nec erat ante. In at metus a orci mollis scelerisque.
    Sed eget ultrices turpis, at sollicitudin erat. Integer hendrerit nec magna quis
    venenatis. Vivamus non dolor hendrerit, vulputate velit sed, varius nunc. Quisque
    in pharetra mi. Sed ullamcorper nibh malesuada commodo porttitor. Ut scelerisque
    sodales felis quis dignissim. Morbi aliquam finibus justo, sit amet consectetur
    mauris efficitur sit amet. Donec posuere turpis felis, eu lacinia magna accumsan
    quis. Fusce egestas lacus vel fermentum tincidunt. Phasellus a nulla eget lectus
    placerat commodo at eget nisl. Fusce cursus dui quis purus accumsan auctor.
    Donec iaculis felis quis metus consectetur porttitor.

    Etiam nibh mi, accumsan quis purus sed, posuere fermentum lorem. In pulvinar porta
    maximus. Fusce tincidunt lacinia tellus sit amet tincidunt. Aliquam lacus est, pulvinar
    non metus a, facilisis ultrices quam. Nulla feugiat leo in cursus eleifend. Suspendisse
    eget nisi ac justo sagittis interdum id a ipsum. Nulla mauris justo, scelerisque ac
    rutrum vitae, consequat vel ex.

    Sed sollicitudin sem mauris, at rutrum nibh egestas vel. Ut eu nisi tellus. Praesent dignissim
    orci elementum, mattis turpis eget, maximus ante. Suspendisse luctus eu felis a tempor. Morbi
    ac risus vitae sem molestie ullamcorper. Curabitur ligula augue, sollicitudin quis maximus vel,
    facilisis sed nibh. Aenean auctor magna sem, id rutrum metus convallis quis. Nullam non arcu
    dictum, lobortis erat quis, rhoncus est. Suspendisse venenatis, mi sed venenatis vehicula,
    tortor dolor egestas lectus, et efficitur turpis odio non augue. Integer velit sapien, dictum
    non egestas vitae, hendrerit sed quam. Phasellus a nunc eu erat varius imperdiet. Etiam id
    sollicitudin turpis, vitae molestie orci. Quisque ornare magna quis metus rhoncus commodo.
    Phasellus non mauris velit.

    Etiam dictum tellus ipsum, nec varius quam ornare vel. Cras vehicula diam nec sollicitudin
    ultricies. Pellentesque rhoncus sagittis nisl id facilisis. Nunc viverra convallis risus ut
    luctus. Aliquam vestibulum efficitur massa, id tempus nisi posuere a. Aliquam scelerisque
    elit justo. Nullam a ante felis. Cras vitae lorem eu nisi feugiat hendrerit. Maecenas vitae
    suscipit leo, lacinia dignissim lacus. Sed eget volutpat mi. In eu bibendum neque. Pellentesque
    finibus velit a fermentum rhoncus. Maecenas leo purus, eleifend eu lacus a, condimentum sagittis
    justo.

"#;
    let string_short = "Lorem ipsum dolor sit amet,<foo>bar&foo\"bar\\foo/bar";
    let empty = "";
    let no_escape = "Lorem ipsum dolor sit amet,";
    let no_escape_long = r#"
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin scelerisque eu urna in aliquet.
Phasellus ac nulla a urna sagittis consequat id quis est. Nullam eu ex eget erat accumsan dictum
ac lobortis urna. Etiam fermentum ut quam at dignissim. Curabitur vestibulum luctus tellus, sit
amet lobortis augue tempor faucibus. Nullam sed felis eget odio elementum euismod in sit amet massa.
Vestibulum sagittis purus sit amet eros auctor, sit amet pharetra purus dapibus. Donec ornare metus
vel dictum porta. Etiam ut nisl nisi. Nullam rutrum porttitor mi. Donec aliquam ac ipsum eget
hendrerit. Cras faucibus, eros ut pharetra imperdiet, est tellus aliquet felis, eget convallis
lacus ipsum eget quam. Vivamus orci lorem, maximus ac mi eget, bibendum vulputate massa. In
vestibulum dui hendrerit, vestibulum lacus sit amet, posuere erat. Vivamus euismod massa diam,
vulputate euismod lectus vestibulum nec. Donec sit amet massa magna. Nunc ipsum nulla, euismod
quis lacus at, gravida maximus elit. Duis tristique, nisl nullam.
    "#;

    b.iter(|| {
        format!("{}", ::askama::MarkupDisplay::from(string_long));
        format!("{}", ::askama::MarkupDisplay::from(string_short));
        format!("{}", ::askama::MarkupDisplay::from(empty));
        format!("{}", ::askama::MarkupDisplay::from(no_escape));
        format!("{}", ::askama::MarkupDisplay::from(no_escape_long));
    });
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{TileOffset, TileRange, LayoutRect, LayoutSize, LayoutPoint};
use api::{DeviceUintSize, DeviceUintRect};
use euclid::{vec2, point2};
use prim_store::EdgeAaSegmentMask;

/// If repetitions are far enough apart that only one is within
/// the primitive rect, then we can simplify the parameters and
/// treat the primitive as not repeated.
/// This can let us avoid unnecessary work later to handle some
/// of the parameters.
pub fn simplify_repeated_primitive(
    stretch_size: &LayoutSize,
    tile_spacing: &mut LayoutSize,
    prim_rect: &mut LayoutRect,
) {
    let stride = *stretch_size + *tile_spacing;

    if stride.width >= prim_rect.size.width {
        tile_spacing.width = 0.0;
        prim_rect.size.width = f32::min(prim_rect.size.width, stretch_size.width);
    }
    if stride.height >= prim_rect.size.height {
        tile_spacing.height = 0.0;
        prim_rect.size.height = f32::min(prim_rect.size.height, stretch_size.height);
    }
}

pub fn for_each_repetition(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    stride: &LayoutSize,
    callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
) {
    assert!(stride.width > 0.0);
    assert!(stride.height > 0.0);

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let nx = if visible_rect.origin.x > prim_rect.origin.x {
        f32::floor((visible_rect.origin.x - prim_rect.origin.x) / stride.width)
    } else {
        0.0
    };

    let ny = if visible_rect.origin.y > prim_rect.origin.y {
        f32::floor((visible_rect.origin.y - prim_rect.origin.y) / stride.height)
    } else {
        0.0
    };

    let x0 = prim_rect.origin.x + nx * stride.width;
    let y0 = prim_rect.origin.y + ny * stride.height;

    let mut p = LayoutPoint::new(x0, y0);

    let x_most = visible_rect.max_x();
    let y_most = visible_rect.max_y();

    let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
    let y_count = f32::ceil((y_most - y0) / stride.height) as i32;

    for y in 0..y_count {
        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&p, edge_flags);

            p.x += stride.width;
        }

        p.x = x0;
        p.y += stride.height;
    }
}

pub fn for_each_tile(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    device_image_size: &DeviceUintSize,
    device_tile_size: u32,
    callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
) {
    // The image resource is tiled. We have to generate an image primitive
    // for each tile.
    // We need to do this because the image is broken up into smaller tiles in the texture
    // cache and the image shader is not able to work with this type of sparse representation.

    // The tiling logic works as follows:
    //
    //  ###################-+  -+
    //  #    |    |    |//# |   | image size
    //  #    |    |    |//# |   |
    //  #----+----+----+--#-+   |  -+
    //  #    |    |    |//# |   |   | regular tile size
    //  #    |    |    |//# |   |   |
    //  #----+----+----+--#-+   |  -+-+
    //  #////|////|////|//# |   |     | "leftover" height
    //  ################### |  -+  ---+
    //  #----+----+----+----+
    //
    // In the ascii diagram above, a large image is split into tiles of almost regular size.
    // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
    // the regular tiles and are handled separately in the code see leftover_width/height.
    // each generated segment corresponds to a tile in the texture cache, with the
    // assumption that the smaller tiles with leftover sizes are sized to fit their own
    // irregular size in the texture cache.

    // Because we can have very large virtual images we iterate over the visible portion of
    // the image in layer space intead of iterating over device tiles.

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let device_tile_size_f32 = device_tile_size as f32;

    // Ratio between (image space) tile size and image size .
    let tile_dw = device_tile_size_f32 / (device_image_size.width as f32);
    let tile_dh = device_tile_size_f32 / (device_image_size.height as f32);

    // size of regular tiles in layout space.
    let layer_tile_size = LayoutSize::new(
        tile_dw * prim_rect.size.width,
        tile_dh * prim_rect.size.height,
    );

    // The size in pixels of the tiles on the right and bottom edges, smaller
    // than the regular tile size if the image is not a multiple of the tile size.
    // Zero means the image size is a multiple of the tile size.
    let leftover_device_size = DeviceUintSize::new(
        device_image_size.width % device_tile_size,
        device_image_size.height % device_tile_size
    );

    // The size in layer space of the tiles on the right and bottom edges.
    let leftover_layer_size = LayoutSize::new(
        layer_tile_size.width * leftover_device_size.width as f32 / device_tile_size_f32,
        layer_tile_size.height * leftover_device_size.height as f32 / device_tile_size_f32,
    );

    // Offset of the row and column of tiles with leftover size.
    let leftover_offset = TileOffset::new(
        (device_image_size.width / device_tile_size) as u16,
        (device_image_size.height / device_tile_size) as u16,
    );

    // Number of culled out tiles to skip before the first visible tile.
    let t0 = TileOffset::new(
        if visible_rect.origin.x > prim_rect.origin.x {
            f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as u16
        } else {
            0
        },
        if visible_rect.origin.y > prim_rect.origin.y {
            f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as u16
        } else {
            0
        },
    );

    let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
    let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;

    for y in 0..y_count {

        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let tile_offset = t0 + vec2(x, y);

            let mut segment_rect = LayoutRect {
                origin: LayoutPoint::new(
                    prim_rect.origin.x + tile_offset.x as f32 * layer_tile_size.width,
                    prim_rect.origin.y + tile_offset.y as f32 * layer_tile_size.height,
                ),
                size: layer_tile_size,
            };

            if tile_offset.x == leftover_offset.x {
                segment_rect.size.width = leftover_layer_size.width;
            }

            if tile_offset.y == leftover_offset.y {
                segment_rect.size.height = leftover_layer_size.height;
            }

            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&segment_rect, tile_offset, edge_flags);
        }
    }
}

pub fn compute_tile_range(
    visible_area: &DeviceUintRect,
    tile_size: u16,
) -> TileRange {
    // Tile dimensions in normalized coordinates.
    let tw = 1. / (tile_size as f32);
    let th = 1. / (tile_size as f32);

    let t0 = point2(
        f32::floor(visible_area.origin.x as f32 * tw),
        f32::floor(visible_area.origin.y as f32 * th),
    ).cast::<u16>();

    let t1 = point2(
        f32::ceil(visible_area.max_x() as f32 * tw),
        f32::ceil(visible_area.max_y() as f32 * th),
    ).cast::<u16>();

    TileRange {
        origin: t0,
        size: (t1 - t0).to_size(),
    }
}

pub fn for_each_tile_in_range(
    range: &TileRange,
    callback: &mut FnMut(TileOffset),
) {
    for y in 0..range.size.height {
        for x in 0..range.size.width {
            callback(range.origin + vec2(x, y));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;
    use api::{LayoutRect, DeviceUintSize};
    use euclid::{rect, size2};

    // this checks some additional invariants
    fn checked_for_each_tile(
        prim_rect: &LayoutRect,
        visible_rect: &LayoutRect,
        device_image_size: &DeviceUintSize,
        device_tile_size: u32,
        callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
    ) {
        let mut coverage = LayoutRect::zero();
        let mut tiles = HashSet::new();
        for_each_tile(prim_rect,
                      visible_rect,
                      device_image_size,
                      device_tile_size,
                      &mut |tile_rect, tile_offset, tile_flags| {
                          // make sure we don't get sent duplicate tiles
                          assert!(!tiles.contains(&tile_offset));
                          tiles.insert(tile_offset);
                          coverage = coverage.union(tile_rect);
                          assert!(prim_rect.contains_rect(&tile_rect));
                          callback(tile_rect, tile_offset, tile_flags);
                      },
        );
        assert!(prim_rect.contains_rect(&coverage));
        assert!(coverage.contains_rect(&visible_rect.intersection(&prim_rect).unwrap_or(LayoutRect::zero())));
    }

    #[test]
    fn basic() {
        let mut count = 0;
        checked_for_each_tile(&rect(0., 0., 1000., 1000.),
            &rect(75., 75., 400., 400.),
            &size2(400, 400),
            36,
            &mut |_tile_rect, _tile_offset, _tile_flags| {
                count += 1;
            },
        );
        assert_eq!(count, 36);
    }

    #[test]
    fn empty() {
        let mut count = 0;
        checked_for_each_tile(&rect(0., 0., 74., 74.),
              &rect(75., 75., 400., 400.),
              &size2(400, 400),
              36,
              &mut |_tile_rect, _tile_offset, _tile_flags| {
                count += 1;
              },
        );
        assert_eq!(count, 0);
    }
}
<commit_msg>Auto merge of #3192 - jrmuizel:tile-area, r=gw3583<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{TileOffset, TileRange, LayoutRect, LayoutSize, LayoutPoint};
use api::{DeviceUintSize, DeviceUintRect};
use euclid::{vec2, point2};
use prim_store::EdgeAaSegmentMask;

/// If repetitions are far enough apart that only one is within
/// the primitive rect, then we can simplify the parameters and
/// treat the primitive as not repeated.
/// This can let us avoid unnecessary work later to handle some
/// of the parameters.
pub fn simplify_repeated_primitive(
    stretch_size: &LayoutSize,
    tile_spacing: &mut LayoutSize,
    prim_rect: &mut LayoutRect,
) {
    let stride = *stretch_size + *tile_spacing;

    if stride.width >= prim_rect.size.width {
        tile_spacing.width = 0.0;
        prim_rect.size.width = f32::min(prim_rect.size.width, stretch_size.width);
    }
    if stride.height >= prim_rect.size.height {
        tile_spacing.height = 0.0;
        prim_rect.size.height = f32::min(prim_rect.size.height, stretch_size.height);
    }
}

pub fn for_each_repetition(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    stride: &LayoutSize,
    callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
) {
    assert!(stride.width > 0.0);
    assert!(stride.height > 0.0);

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let nx = if visible_rect.origin.x > prim_rect.origin.x {
        f32::floor((visible_rect.origin.x - prim_rect.origin.x) / stride.width)
    } else {
        0.0
    };

    let ny = if visible_rect.origin.y > prim_rect.origin.y {
        f32::floor((visible_rect.origin.y - prim_rect.origin.y) / stride.height)
    } else {
        0.0
    };

    let x0 = prim_rect.origin.x + nx * stride.width;
    let y0 = prim_rect.origin.y + ny * stride.height;

    let mut p = LayoutPoint::new(x0, y0);

    let x_most = visible_rect.max_x();
    let y_most = visible_rect.max_y();

    let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
    let y_count = f32::ceil((y_most - y0) / stride.height) as i32;

    for y in 0..y_count {
        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&p, edge_flags);

            p.x += stride.width;
        }

        p.x = x0;
        p.y += stride.height;
    }
}

pub fn for_each_tile(
    prim_rect: &LayoutRect,
    visible_rect: &LayoutRect,
    device_image_size: &DeviceUintSize,
    device_tile_size: u32,
    callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
) {
    // The image resource is tiled. We have to generate an image primitive
    // for each tile.
    // We need to do this because the image is broken up into smaller tiles in the texture
    // cache and the image shader is not able to work with this type of sparse representation.

    // The tiling logic works as follows:
    //
    //  ###################-+  -+
    //  #    |    |    |//# |   | image size
    //  #    |    |    |//# |   |
    //  #----+----+----+--#-+   |  -+
    //  #    |    |    |//# |   |   | regular tile size
    //  #    |    |    |//# |   |   |
    //  #----+----+----+--#-+   |  -+-+
    //  #////|////|////|//# |   |     | "leftover" height
    //  ################### |  -+  ---+
    //  #----+----+----+----+
    //
    // In the ascii diagram above, a large image is split into tiles of almost regular size.
    // The tiles on the right and bottom edges (hatched in the diagram) are smaller than
    // the regular tiles and are handled separately in the code see leftover_width/height.
    // each generated segment corresponds to a tile in the texture cache, with the
    // assumption that the smaller tiles with leftover sizes are sized to fit their own
    // irregular size in the texture cache.

    // Because we can have very large virtual images we iterate over the visible portion of
    // the image in layer space intead of iterating over device tiles.

    let visible_rect = match prim_rect.intersection(&visible_rect) {
       Some(rect) => rect,
       None => return,
    };

    let device_tile_size_f32 = device_tile_size as f32;

    // Ratio between (image space) tile size and image size .
    let tile_dw = device_tile_size_f32 / (device_image_size.width as f32);
    let tile_dh = device_tile_size_f32 / (device_image_size.height as f32);

    // size of regular tiles in layout space.
    let layer_tile_size = LayoutSize::new(
        tile_dw * prim_rect.size.width,
        tile_dh * prim_rect.size.height,
    );

    // The size in pixels of the tiles on the right and bottom edges, smaller
    // than the regular tile size if the image is not a multiple of the tile size.
    // Zero means the image size is a multiple of the tile size.
    let leftover_device_size = DeviceUintSize::new(
        device_image_size.width % device_tile_size,
        device_image_size.height % device_tile_size
    );

    // The size in layer space of the tiles on the right and bottom edges.
    let leftover_layer_size = LayoutSize::new(
        layer_tile_size.width * leftover_device_size.width as f32 / device_tile_size_f32,
        layer_tile_size.height * leftover_device_size.height as f32 / device_tile_size_f32,
    );

    // Offset of the row and column of tiles with leftover size.
    let leftover_offset = TileOffset::new(
        (device_image_size.width / device_tile_size) as u16,
        (device_image_size.height / device_tile_size) as u16,
    );

    // Number of culled out tiles to skip before the first visible tile.
    let t0 = TileOffset::new(
        if visible_rect.origin.x > prim_rect.origin.x {
            f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as u16
        } else {
            0
        },
        if visible_rect.origin.y > prim_rect.origin.y {
            f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as u16
        } else {
            0
        },
    );

    let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
    let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;

    for y in 0..y_count {

        let mut row_flags = EdgeAaSegmentMask::empty();
        if y == 0 {
            row_flags |= EdgeAaSegmentMask::TOP;
        }
        if y == y_count - 1 {
            row_flags |= EdgeAaSegmentMask::BOTTOM;
        }

        for x in 0..x_count {
            let tile_offset = t0 + vec2(x, y);

            let mut segment_rect = LayoutRect {
                origin: LayoutPoint::new(
                    prim_rect.origin.x + tile_offset.x as f32 * layer_tile_size.width,
                    prim_rect.origin.y + tile_offset.y as f32 * layer_tile_size.height,
                ),
                size: layer_tile_size,
            };

            if tile_offset.x == leftover_offset.x {
                segment_rect.size.width = leftover_layer_size.width;
            }

            if tile_offset.y == leftover_offset.y {
                segment_rect.size.height = leftover_layer_size.height;
            }

            let mut edge_flags = row_flags;
            if x == 0 {
                edge_flags |= EdgeAaSegmentMask::LEFT;
            }
            if x == x_count - 1 {
                edge_flags |= EdgeAaSegmentMask::RIGHT;
            }

            callback(&segment_rect, tile_offset, edge_flags);
        }
    }
}

pub fn compute_tile_range(
    visible_area: &DeviceUintRect,
    tile_size: u16,
) -> TileRange {
    // Tile dimensions in normalized coordinates.
    let tw = 1. / (tile_size as f32);
    let th = 1. / (tile_size as f32);

    let t0 = point2(
        f32::floor(visible_area.origin.x as f32 * tw),
        f32::floor(visible_area.origin.y as f32 * th),
    ).try_cast::<u16>().unwrap_or_else(|| panic!("compute_tile_range bad values {:?} {:?}", visible_area, tile_size));

    let t1 = point2(
        f32::ceil(visible_area.max_x() as f32 * tw),
        f32::ceil(visible_area.max_y() as f32 * th),
    ).try_cast::<u16>().unwrap_or_else(|| panic!("compute_tile_range bad values {:?} {:?}", visible_area, tile_size));

    TileRange {
        origin: t0,
        size: (t1 - t0).to_size(),
    }
}

pub fn for_each_tile_in_range(
    range: &TileRange,
    callback: &mut FnMut(TileOffset),
) {
    for y in 0..range.size.height {
        for x in 0..range.size.width {
            callback(range.origin + vec2(x, y));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;
    use api::{LayoutRect, DeviceUintSize};
    use euclid::{rect, size2};

    // this checks some additional invariants
    fn checked_for_each_tile(
        prim_rect: &LayoutRect,
        visible_rect: &LayoutRect,
        device_image_size: &DeviceUintSize,
        device_tile_size: u32,
        callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
    ) {
        let mut coverage = LayoutRect::zero();
        let mut tiles = HashSet::new();
        for_each_tile(prim_rect,
                      visible_rect,
                      device_image_size,
                      device_tile_size,
                      &mut |tile_rect, tile_offset, tile_flags| {
                          // make sure we don't get sent duplicate tiles
                          assert!(!tiles.contains(&tile_offset));
                          tiles.insert(tile_offset);
                          coverage = coverage.union(tile_rect);
                          assert!(prim_rect.contains_rect(&tile_rect));
                          callback(tile_rect, tile_offset, tile_flags);
                      },
        );
        assert!(prim_rect.contains_rect(&coverage));
        assert!(coverage.contains_rect(&visible_rect.intersection(&prim_rect).unwrap_or(LayoutRect::zero())));
    }

    #[test]
    fn basic() {
        let mut count = 0;
        checked_for_each_tile(&rect(0., 0., 1000., 1000.),
            &rect(75., 75., 400., 400.),
            &size2(400, 400),
            36,
            &mut |_tile_rect, _tile_offset, _tile_flags| {
                count += 1;
            },
        );
        assert_eq!(count, 36);
    }

    #[test]
    fn empty() {
        let mut count = 0;
        checked_for_each_tile(&rect(0., 0., 74., 74.),
              &rect(75., 75., 400., 400.),
              &size2(400, 400),
              36,
              &mut |_tile_rect, _tile_offset, _tile_flags| {
                count += 1;
              },
        );
        assert_eq!(count, 0);
    }
}
<|endoftext|>