<commit_before>//! Primitives for non-blocking SSDP message receiving.

use std::io;
use std::result::Result;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError, RecvError, Iter};
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{UdpSocket, SocketAddr};
use std::time::Duration;

use SSDPResult;
use net::packet::PacketReceiver;

/// Trait for constructing an object from some serialized SSDP message.
pub trait FromRawSSDP: Sized {
    fn raw_ssdp(bytes: &[u8]) -> SSDPResult<Self>;
}

/// Iterator for an `SSDPReceiver`.
pub struct SSDPIter<T> {
    recv: SSDPReceiver<T>,
}

impl<T> SSDPIter<T> {
    fn new(recv: SSDPReceiver<T>) -> SSDPIter<T> {
        SSDPIter { recv: recv }
    }
}

impl<T> Iterator for SSDPIter<T> {
    type Item = (T, SocketAddr);

    fn next(&mut self) -> Option<Self::Item> {
        self.recv.recv().ok()
    }
}

/// A non-blocking SSDP message receiver.
pub struct SSDPReceiver<T> {
    recvr: Receiver<(T, SocketAddr)>,
    socks: Vec<UdpSocket>,
    addrs: Vec<SocketAddr>,
    kill: Arc<AtomicBool>,
}

impl<T> SSDPReceiver<T>
    where T: FromRawSSDP + Send + 'static
{
    /// Construct a receiver that receives bytes from a number of UdpSockets and
    /// tries to construct an object T from them. If a duration is provided, the
    /// channel will be shutdown after the specified duration.
    ///
    /// Due to implementation details, none of the UdpSockets should be bound to
    /// the default route, 0.0.0.0, address.
    pub fn new(socks: Vec<UdpSocket>, time: Option<Duration>) -> io::Result<SSDPReceiver<T>> {
        let (send, recv) = mpsc::channel();

        let mut send_socks = try!(clone_socks(&socks[..]));
        let recv_addrs = try!(clone_addrs(&socks[..]));

        let self_kill = Arc::new(AtomicBool::new(false));

        // Ensure `receive_packets` times out in the event the timeout packet is not received
        for sock in &mut send_socks {
            try!(sock.set_read_timeout(time));
        }

        // Spawn Receiver Threads
        spawn_receivers(send_socks, self_kill.clone(), send);

        // Spawn Single Kill Timer
        let spawn_result = maybe_spawn_timer(time, self_kill.clone(), &socks[..]);

        // If Timer Failed To Spawn, Kill Our Receivers
        if let Err(e) = spawn_result {
            syncronize_kill(&*self_kill, &socks[..], &recv_addrs[..]);

            return Err(e);
        }

        Ok(SSDPReceiver {
            recvr: recv,
            socks: socks,
            addrs: recv_addrs,
            kill: self_kill,
        })
    }
}

/// Attempt to clone all `UdpSocket`'s into a new vector.
fn clone_socks(socks: &[UdpSocket]) -> io::Result<Vec<UdpSocket>> {
    let mut clone_socks = Vec::with_capacity(socks.len());

    for sock in socks.iter() {
        clone_socks.push(try!(sock.try_clone()));
    }

    Ok(clone_socks)
}

/// Attempt to copy all `SocketAddr`'s from the `UdpSocket`'s into a new vector.
fn clone_addrs(socks: &[UdpSocket]) -> io::Result<Vec<SocketAddr>> {
    let mut clone_addrs = Vec::with_capacity(socks.len());

    for sock in socks.iter() {
        clone_addrs.push(try!(sock.local_addr()));
    }

    Ok(clone_addrs)
}

/// Spawn a number of receiver threads that will receive packets, forward the
/// bytes on to T, and send successfully constructed objects through the sender.
fn spawn_receivers<T>(socks: Vec<UdpSocket>, kill_flag: Arc<AtomicBool>, sender: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send + 'static
{
    for sock in socks {
        let pckt_recv = PacketReceiver::new(sock);
        let kill_flag = kill_flag.clone();
        let sender = sender.clone();

        thread::spawn(move || {
            receive_packets(pckt_recv, kill_flag, sender);
        });
    }
}

/// Spawn a timer if a duration was passed in and link the timer with the given sockets.
///
/// If some of the sockets or socket addresses could not be cloned, an error is returned.
fn maybe_spawn_timer(time: Option<Duration>, kill: Arc<AtomicBool>, socks: &[UdpSocket]) -> io::Result<()> {
    if let Some(n) = time {
        let timer_socks = try!(clone_socks(socks));
        let timer_addrs = try!(clone_addrs(socks));

        thread::spawn(move || {
            kill_timer(n, kill, timer_socks, timer_addrs);
        });
    };

    Ok(())
}

impl<T> SSDPReceiver<T> {
    /// Non-blocking method that attempts to read a value from the receiver.
    pub fn try_recv(&self) -> Result<(T, SocketAddr), TryRecvError> {
        self.recvr.try_recv()
    }

    /// Blocking method that reads a value from the receiver until one is available.
    pub fn recv(&self) -> Result<(T, SocketAddr), RecvError> {
        self.recvr.recv()
    }
}

impl<'a, T> IntoIterator for &'a SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<T> IntoIterator for SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = SSDPIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        SSDPIter::new(self)
    }
}

impl<T> Drop for SSDPReceiver<T> {
    fn drop(&mut self) {
        syncronize_kill(&*self.kill, &self.socks[..], &self.addrs[..]);
    }
}

/// Receives bytes and attempts to construct a T which will be sent through the
/// supplied channel.
///
/// This should almost always be run in it's own thread.
fn receive_packets<T>(recv: PacketReceiver, kill: Arc<AtomicBool>, send: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send
{
    // TODO: Add logging to this function. Maybe forward sender IP Address along
    // so that we can do some checks when we parse the http.
    loop {
        trace!("Waiting on packet at {}...", recv);
        let (msg_bytes, addr) = match recv.recv_pckt() {
            Ok((bytes, addr)) => (bytes, addr),
            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
                // We have waited for at least the desired timeout (or possibly longer)
                trace!("Receiver at {} timed out", recv);
                return;
            },
            Err(_) => {
                continue;
            }
        };

        trace!("Received packet with {} bytes", msg_bytes.len());

        // Check If We Were Unblocked Intentionally
        if kill.load(Ordering::Acquire) {
            // With acquire, there is a chance that the code below could
            // be moved up and our unblock message could be processed. This
            // should not affect execution but keep in mind for logging
            // purposes.
            trace!("Receiver at {} timed out", recv);
            return;
        }

        // Unwrap Will Cause A Panic If Receiver Hung Up Which Is Desired
        match T::raw_ssdp(&msg_bytes[..]) {
            Ok(n) => send.send((n, addr)).unwrap(),
            Err(_) => {
                continue;
            }
        };
    }
}

/// Sleeps the current thread for the specified duration, after which, it will activate
/// the kill flag and send a message on all `UdpSocket`'s to unblock whatever threads are
/// blocking on them so that they can see that the kill flag has been activated.
///
/// This should be run in it's own thread.
fn kill_timer(time: Duration, kill: Arc<AtomicBool>, socks: Vec<UdpSocket>, addrs: Vec<SocketAddr>) {
    thread::sleep(time);

    syncronize_kill(&*kill, &socks[..], &addrs[..]);
}

#[allow(unused)]
/// Sets the kill flag and sends a one byte message through the `UdpSocket`'s,
/// making sure that the operations are sequentially consistent (not re-ordered).
fn syncronize_kill(kill: &AtomicBool, socks: &[UdpSocket], local_addrs: &[SocketAddr]) {
    kill.store(true, Ordering::SeqCst);

    for (sock, addr) in socks.iter().zip(local_addrs.iter()) {
        sock.send_to(&[0], addr);
    }
}
<commit_msg>Fix socket timeouts on Windows<commit_after>//! Primitives for non-blocking SSDP message receiving.

use std::io;
use std::result::Result;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError, RecvError, Iter};
use std::sync::atomic::{AtomicBool, Ordering};
use std::net::{UdpSocket, SocketAddr};
use std::time::Duration;

use SSDPResult;
use net::packet::PacketReceiver;

/// Trait for constructing an object from some serialized SSDP message.
pub trait FromRawSSDP: Sized {
    fn raw_ssdp(bytes: &[u8]) -> SSDPResult<Self>;
}

/// Iterator for an `SSDPReceiver`.
pub struct SSDPIter<T> {
    recv: SSDPReceiver<T>,
}

impl<T> SSDPIter<T> {
    fn new(recv: SSDPReceiver<T>) -> SSDPIter<T> {
        SSDPIter { recv: recv }
    }
}

impl<T> Iterator for SSDPIter<T> {
    type Item = (T, SocketAddr);

    fn next(&mut self) -> Option<Self::Item> {
        self.recv.recv().ok()
    }
}

/// A non-blocking SSDP message receiver.
pub struct SSDPReceiver<T> {
    recvr: Receiver<(T, SocketAddr)>,
    socks: Vec<UdpSocket>,
    addrs: Vec<SocketAddr>,
    kill: Arc<AtomicBool>,
}

impl<T> SSDPReceiver<T>
    where T: FromRawSSDP + Send + 'static
{
    /// Construct a receiver that receives bytes from a number of UdpSockets and
    /// tries to construct an object T from them. If a duration is provided, the
    /// channel will be shutdown after the specified duration.
    ///
    /// Due to implementation details, none of the UdpSockets should be bound to
    /// the default route, 0.0.0.0, address.
    pub fn new(socks: Vec<UdpSocket>, time: Option<Duration>) -> io::Result<SSDPReceiver<T>> {
        let (send, recv) = mpsc::channel();

        let mut send_socks = try!(clone_socks(&socks[..]));
        let recv_addrs = try!(clone_addrs(&socks[..]));

        let self_kill = Arc::new(AtomicBool::new(false));

        // Ensure `receive_packets` times out in the event the timeout packet is not received
        for sock in &mut send_socks {
            try!(sock.set_read_timeout(time));
        }

        // Spawn Receiver Threads
        spawn_receivers(send_socks, self_kill.clone(), send);

        // Spawn Single Kill Timer
        let spawn_result = maybe_spawn_timer(time, self_kill.clone(), &socks[..]);

        // If Timer Failed To Spawn, Kill Our Receivers
        if let Err(e) = spawn_result {
            syncronize_kill(&*self_kill, &socks[..], &recv_addrs[..]);

            return Err(e);
        }

        Ok(SSDPReceiver {
            recvr: recv,
            socks: socks,
            addrs: recv_addrs,
            kill: self_kill,
        })
    }
}

/// Attempt to clone all `UdpSocket`'s into a new vector.
fn clone_socks(socks: &[UdpSocket]) -> io::Result<Vec<UdpSocket>> {
    let mut clone_socks = Vec::with_capacity(socks.len());

    for sock in socks.iter() {
        clone_socks.push(try!(sock.try_clone()));
    }

    Ok(clone_socks)
}

/// Attempt to copy all `SocketAddr`'s from the `UdpSocket`'s into a new vector.
fn clone_addrs(socks: &[UdpSocket]) -> io::Result<Vec<SocketAddr>> {
    let mut clone_addrs = Vec::with_capacity(socks.len());

    for sock in socks.iter() {
        clone_addrs.push(try!(sock.local_addr()));
    }

    Ok(clone_addrs)
}

/// Spawn a number of receiver threads that will receive packets, forward the
/// bytes on to T, and send successfully constructed objects through the sender.
fn spawn_receivers<T>(socks: Vec<UdpSocket>, kill_flag: Arc<AtomicBool>, sender: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send + 'static
{
    for sock in socks {
        let pckt_recv = PacketReceiver::new(sock);
        let kill_flag = kill_flag.clone();
        let sender = sender.clone();

        thread::spawn(move || {
            receive_packets(pckt_recv, kill_flag, sender);
        });
    }
}

/// Spawn a timer if a duration was passed in and link the timer with the given sockets.
///
/// If some of the sockets or socket addresses could not be cloned, an error is returned.
fn maybe_spawn_timer(time: Option<Duration>, kill: Arc<AtomicBool>, socks: &[UdpSocket]) -> io::Result<()> {
    if let Some(n) = time {
        let timer_socks = try!(clone_socks(socks));
        let timer_addrs = try!(clone_addrs(socks));

        thread::spawn(move || {
            kill_timer(n, kill, timer_socks, timer_addrs);
        });
    };

    Ok(())
}

impl<T> SSDPReceiver<T> {
    /// Non-blocking method that attempts to read a value from the receiver.
    pub fn try_recv(&self) -> Result<(T, SocketAddr), TryRecvError> {
        self.recvr.try_recv()
    }

    /// Blocking method that reads a value from the receiver until one is available.
    pub fn recv(&self) -> Result<(T, SocketAddr), RecvError> {
        self.recvr.recv()
    }
}

impl<'a, T> IntoIterator for &'a SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<'a, T> IntoIterator for &'a mut SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = Iter<'a, (T, SocketAddr)>;

    fn into_iter(self) -> Self::IntoIter {
        self.recvr.iter()
    }
}

impl<T> IntoIterator for SSDPReceiver<T> {
    type Item = (T, SocketAddr);
    type IntoIter = SSDPIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        SSDPIter::new(self)
    }
}

impl<T> Drop for SSDPReceiver<T> {
    fn drop(&mut self) {
        syncronize_kill(&*self.kill, &self.socks[..], &self.addrs[..]);
    }
}

/// Receives bytes and attempts to construct a T which will be sent through the
/// supplied channel.
///
/// This should almost always be run in it's own thread.
fn receive_packets<T>(recv: PacketReceiver, kill: Arc<AtomicBool>, send: Sender<(T, SocketAddr)>)
    where T: FromRawSSDP + Send
{
    // TODO: Add logging to this function. Maybe forward sender IP Address along
    // so that we can do some checks when we parse the http.
    loop {
        trace!("Waiting on packet at {}...", recv);
        let (msg_bytes, addr) = match recv.recv_pckt() {
            Ok((bytes, addr)) => (bytes, addr),
            // Unix returns WouldBlock on timeout while Windows returns TimedOut
            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock ||
                            err.kind() == io::ErrorKind::TimedOut => {
                // We have waited for at least the desired timeout (or possibly longer)
                trace!("Receiver at {} timed out", recv);
                return;
            },
            Err(_) => {
                continue;
            }
        };

        trace!("Received packet with {} bytes", msg_bytes.len());

        // Check If We Were Unblocked Intentionally
        if kill.load(Ordering::Acquire) {
            // With acquire, there is a chance that the code below could
            // be moved up and our unblock message could be processed. This
            // should not affect execution but keep in mind for logging
            // purposes.
            trace!("Receiver at {} timed out", recv);
            return;
        }

        // Unwrap Will Cause A Panic If Receiver Hung Up Which Is Desired
        match T::raw_ssdp(&msg_bytes[..]) {
            Ok(n) => send.send((n, addr)).unwrap(),
            Err(_) => {
                continue;
            }
        };
    }
}

/// Sleeps the current thread for the specified duration, after which, it will activate
/// the kill flag and send a message on all `UdpSocket`'s to unblock whatever threads are
/// blocking on them so that they can see that the kill flag has been activated.
///
/// This should be run in it's own thread.
fn kill_timer(time: Duration, kill: Arc<AtomicBool>, socks: Vec<UdpSocket>, addrs: Vec<SocketAddr>) {
    thread::sleep(time);

    syncronize_kill(&*kill, &socks[..], &addrs[..]);
}

#[allow(unused)]
/// Sets the kill flag and sends a one byte message through the `UdpSocket`'s,
/// making sure that the operations are sequentially consistent (not re-ordered).
fn syncronize_kill(kill: &AtomicBool, socks: &[UdpSocket], local_addrs: &[SocketAddr]) {
    kill.store(true, Ordering::SeqCst);

    for (sock, addr) in socks.iter().zip(local_addrs.iter()) {
        sock.send_to(&[0], addr);
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::rc::Rc;

use futures::Future;
use http::{Method, StatusCode};
use smallvec::SmallVec;

use error::Error;
use handler::{AsyncResult, FromRequest, Handler, Responder};
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::Middleware;
use pred;
use route::Route;

/// *Resource* is an entry in route table which corresponds to requested URL.
///
/// Resource in turn has at least one route.
/// Route consists of an object that implements `Handler` trait (handler)
/// and list of predicates (objects that implement `Predicate` trait).
/// Route uses builder-like pattern for configuration.
/// During request handling, resource object iterate through all routes
/// and check all predicates for specific route, if request matches all
/// predicates route route considered matched and route handler get called.
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::{App, HttpResponse, http};
///
/// fn main() {
///     let app = App::new()
///         .resource(
///             "/", |r| r.method(http::Method::GET).f(|r| HttpResponse::Ok()))
///         .finish();
/// }
pub struct ResourceHandler<S = ()> {
    name: String,
    state: PhantomData<S>,
    routes: SmallVec<[Route<S>; 3]>,
    middlewares: Rc<Vec<Box<Middleware<S>>>>,
}

impl<S> Default for ResourceHandler<S> {
    fn default() -> Self {
        ResourceHandler {
            name: String::new(),
            state: PhantomData,
            routes: SmallVec::new(),
            middlewares: Rc::new(Vec::new()),
        }
    }
}

impl<S> ResourceHandler<S> {
    pub(crate) fn default_not_found() -> Self {
        ResourceHandler {
            name: String::new(),
            state: PhantomData,
            routes: SmallVec::new(),
            middlewares: Rc::new(Vec::new()),
        }
    }

    /// Set resource name
    pub fn name<T: Into<String>>(&mut self, name: T) {
        self.name = name.into();
    }

    pub(crate) fn get_name(&self) -> &str {
        &self.name
    }
}

impl<S: 'static> ResourceHandler<S> {
    /// Register a new route and return mutable reference to *Route* object.
    /// *Route* is used for route configuration, i.e. adding predicates,
    /// setting up handler.
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// use actix_web::*;
    ///
    /// fn main() {
    ///     let app = App::new()
    ///         .resource("/", |r| {
    ///             r.route()
    ///                 .filter(pred::Any(pred::Get()).or(pred::Put()))
    ///                 .filter(pred::Header("Content-Type", "text/plain"))
    ///                 .f(|r| HttpResponse::Ok())
    ///         })
    ///         .finish();
    /// }
    /// ```
    pub fn route(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap()
    }

    /// Register a new `GET` route.
    pub fn get(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Get())
    }

    /// Register a new `POST` route.
    pub fn post(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Post())
    }

    /// Register a new `PUT` route.
    pub fn put(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Put())
    }

    /// Register a new `DELETE` route.
    pub fn delete(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Delete())
    }

    /// Register a new `HEAD` route.
    pub fn head(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Head())
    }

    /// Register a new route and add method check to route.
    ///
    /// This is shortcut for:
    ///
    /// ```rust,ignore
    /// Application::resource("/", |r| r.route().filter(pred::Get()).f(index)
    /// ```
    pub fn method(&mut self, method: Method) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Method(method))
    }

    /// Register a new route and add handler object.
    ///
    /// This is shortcut for:
    ///
    /// ```rust,ignore
    /// Application::resource("/", |r| r.route().h(handler)
    /// ```
    pub fn h<H: Handler<S>>(&mut self, handler: H) {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().h(handler)
    }

    /// Register a new route and add handler function.
    ///
    /// This is shortcut for:
    ///
    /// ```rust,ignore
    /// Application::resource("/", |r| r.route().f(index)
    /// ```
    pub fn f<F, R>(&mut self, handler: F)
    where
        F: Fn(HttpRequest<S>) -> R + 'static,
        R: Responder + 'static,
    {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().f(handler)
    }

    /// Register a new route and add handler.
    ///
    /// This is shortcut for:
    ///
    /// ```rust,ignore
    /// Application::resource("/", |r| r.route().with(index)
    /// ```
    pub fn with<T, F, R>(&mut self, handler: F)
    where
        F: Fn(T) -> R + 'static,
        R: Responder + 'static,
        T: FromRequest<S> + 'static,
    {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().with(handler);
    }

    /// Register a new route and add async handler.
    ///
    /// This is shortcut for:
    ///
    /// ```rust,ignore
    /// Application::resource("/", |r| r.route().with_async(index)
    /// ```
    pub fn with_async<T, F, R, I, E>(&mut self, handler: F)
    where
        F: Fn(T) -> R + 'static,
        R: Future<Item = I, Error = E> + 'static,
        I: Responder + 'static,
        E: Into<Error> + 'static,
        T: FromRequest<S> + 'static,
    {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().with_async(handler);
    }

    /// Register a resource middleware
    ///
    /// This is similar to `App's` middlewares, but
    /// middlewares get invoked on resource level.
    ///
    /// *Note* `Middleware::finish()` fires right after response get
    /// prepared. It does not wait until body get sent to peer.
    pub fn middleware<M: Middleware<S>>(&mut self, mw: M) {
        Rc::get_mut(&mut self.middlewares)
            .unwrap()
            .push(Box::new(mw));
    }

    pub(crate) fn handle(
        &mut self, mut req: HttpRequest<S>, default: Option<&mut ResourceHandler<S>>,
    ) -> AsyncResult<HttpResponse> {
        for route in &mut self.routes {
            if route.check(&mut req) {
                return if self.middlewares.is_empty() {
                    route.handle(req)
                } else {
                    route.compose(req, Rc::clone(&self.middlewares))
                };
            }
        }
        if let Some(resource) = default {
            resource.handle(req, None)
        } else {
            AsyncResult::ok(HttpResponse::new(StatusCode::NOT_FOUND))
        }
    }
}
<commit_msg>Fix some ResourceHandler docs<commit_after>use std::marker::PhantomData;
use std::rc::Rc;

use futures::Future;
use http::{Method, StatusCode};
use smallvec::SmallVec;

use error::Error;
use handler::{AsyncResult, FromRequest, Handler, Responder};
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::Middleware;
use pred;
use route::Route;

/// *Resource* is an entry in route table which corresponds to requested URL.
///
/// Resource in turn has at least one route.
/// Route consists of an object that implements `Handler` trait (handler)
/// and list of predicates (objects that implement `Predicate` trait).
/// Route uses builder-like pattern for configuration.
/// During request handling, resource object iterate through all routes
/// and check all predicates for specific route, if request matches all
/// predicates route route considered matched and route handler get called.
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::{App, HttpResponse, http};
///
/// fn main() {
///     let app = App::new()
///         .resource(
///             "/", |r| r.method(http::Method::GET).f(|r| HttpResponse::Ok()))
///         .finish();
/// }
pub struct ResourceHandler<S = ()> {
    name: String,
    state: PhantomData<S>,
    routes: SmallVec<[Route<S>; 3]>,
    middlewares: Rc<Vec<Box<Middleware<S>>>>,
}

impl<S> Default for ResourceHandler<S> {
    fn default() -> Self {
        ResourceHandler {
            name: String::new(),
            state: PhantomData,
            routes: SmallVec::new(),
            middlewares: Rc::new(Vec::new()),
        }
    }
}

impl<S> ResourceHandler<S> {
    pub(crate) fn default_not_found() -> Self {
        ResourceHandler {
            name: String::new(),
            state: PhantomData,
            routes: SmallVec::new(),
            middlewares: Rc::new(Vec::new()),
        }
    }

    /// Set resource name
    pub fn name<T: Into<String>>(&mut self, name: T) {
        self.name = name.into();
    }

    pub(crate) fn get_name(&self) -> &str {
        &self.name
    }
}

impl<S: 'static> ResourceHandler<S> {
    /// Register a new route and return mutable reference to *Route* object.
    /// *Route* is used for route configuration, i.e. adding predicates,
    /// setting up handler.
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// use actix_web::*;
    ///
    /// fn main() {
    ///     let app = App::new()
    ///         .resource("/", |r| {
    ///             r.route()
    ///                 .filter(pred::Any(pred::Get()).or(pred::Put()))
    ///                 .filter(pred::Header("Content-Type", "text/plain"))
    ///                 .f(|r| HttpResponse::Ok())
    ///         })
    ///         .finish();
    /// }
    /// ```
    pub fn route(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap()
    }

    /// Register a new `GET` route.
    pub fn get(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Get())
    }

    /// Register a new `POST` route.
    pub fn post(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Post())
    }

    /// Register a new `PUT` route.
    pub fn put(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Put())
    }

    /// Register a new `DELETE` route.
    pub fn delete(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Delete())
    }

    /// Register a new `HEAD` route.
    pub fn head(&mut self) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Head())
    }

    /// Register a new route and add method check to route.
    ///
    /// This is shortcut for:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # use actix_web::*;
    /// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() }
    /// App::new().resource("/", |r| r.route().filter(pred::Get()).f(index));
    /// ```
    pub fn method(&mut self, method: Method) -> &mut Route<S> {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().filter(pred::Method(method))
    }

    /// Register a new route and add handler object.
    ///
    /// This is shortcut for:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # use actix_web::*;
    /// # fn handler(req: HttpRequest) -> HttpResponse { unimplemented!() }
    /// App::new().resource("/", |r| r.route().h(handler));
    /// ```
    pub fn h<H: Handler<S>>(&mut self, handler: H) {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().h(handler)
    }

    /// Register a new route and add handler function.
    ///
    /// This is shortcut for:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # use actix_web::*;
    /// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() }
    /// App::new().resource("/", |r| r.route().f(index));
    /// ```
    pub fn f<F, R>(&mut self, handler: F)
    where
        F: Fn(HttpRequest<S>) -> R + 'static,
        R: Responder + 'static,
    {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().f(handler)
    }

    /// Register a new route and add handler.
    ///
    /// This is shortcut for:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # use actix_web::*;
    /// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() }
    /// App::new().resource("/", |r| r.route().with(index));
    /// ```
    pub fn with<T, F, R>(&mut self, handler: F)
    where
        F: Fn(T) -> R + 'static,
        R: Responder + 'static,
        T: FromRequest<S> + 'static,
    {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().with(handler);
    }

    /// Register a new route and add async handler.
    ///
    /// This is shortcut for:
    ///
    /// ```rust
    /// # extern crate actix_web;
    /// # extern crate futures;
    /// # use actix_web::*;
    /// # use futures::future::Future;
    /// # fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
    /// #     unimplemented!()
    /// # }
    /// App::new().resource("/", |r| r.route().with_async(index));
    /// ```
    pub fn with_async<T, F, R, I, E>(&mut self, handler: F)
    where
        F: Fn(T) -> R + 'static,
        R: Future<Item = I, Error = E> + 'static,
        I: Responder + 'static,
        E: Into<Error> + 'static,
        T: FromRequest<S> + 'static,
    {
        self.routes.push(Route::default());
        self.routes.last_mut().unwrap().with_async(handler);
    }

    /// Register a resource middleware
    ///
    /// This is similar to `App's` middlewares, but
    /// middlewares get invoked on resource level.
    ///
    /// *Note* `Middleware::finish()` fires right after response get
    /// prepared. It does not wait until body get sent to peer.
    pub fn middleware<M: Middleware<S>>(&mut self, mw: M) {
        Rc::get_mut(&mut self.middlewares)
            .unwrap()
            .push(Box::new(mw));
    }

    pub(crate) fn handle(
        &mut self, mut req: HttpRequest<S>, default: Option<&mut ResourceHandler<S>>,
    ) -> AsyncResult<HttpResponse> {
        for route in &mut self.routes {
            if route.check(&mut req) {
                return if self.middlewares.is_empty() {
                    route.handle(req)
                } else {
                    route.compose(req, Rc::clone(&self.middlewares))
                };
            }
        }
        if let Some(resource) = default {
            resource.handle(req, None)
        } else {
            AsyncResult::ok(HttpResponse::new(StatusCode::NOT_FOUND))
        }
    }
}
<|endoftext|>


<commit_before>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
///  of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///      will assume that the data from the `Reader` has the specified encoding
///      and will just pass-through.
///  - `Content-Length`: If you define this header to `N`, only the first `N` bytes
///      of the `Reader` will be read. If the `Reader` reaches `EOF` before `N` bytes have
///      been read, `0`s will be sent. Also, this header may not be passed to the final
///      output.
///
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<uint>,
}

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl ::std::from_str::FromStr for TransferEncoding {
    fn from_str(input: &str) -> Option<TransferEncoding> {
        use std::ascii::StrAsciiExt;

        if input.eq_ignore_ascii_case("identity") {
            return Some(Identity);
        } else if input.eq_ignore_ascii_case("chunked") {
            return Some(Chunked);
        }

        None
    }
}

/// Builds a Date: header with the current date.
// TODO: this is optimisable
fn build_date_header() -> Header {
    use time;
    let date = time::now_utc().strftime("%a, %d %b %Y %H:%M:%S GMT");
    from_str(format!("Date: {}", date).as_slice()).unwrap()
}

fn write_message_header<W: Writer>(mut writer: W, http_version: &HTTPVersion,
                                   status_code: &StatusCode, headers: &[Header])
    -> IoResult<()>
{
    // writing status line
    try!(write!(writer, "HTTP/{} {} {}\r\n",
        http_version,
        status_code.as_uint(),
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(write!(writer, "{}: {}\r\n", header.field, header.value));
    }

    // separator between header and data
    try!(write!(writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<uint>)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= HTTPVersion(1, 0) {
        return Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.as_slice())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value);

            // sorting elements by most priority
            parse.sort_by(|a, b| b.val1().partial_cmp(&a.val1()).unwrap_or(Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.val1() <= 0.0 { continue }

                match from_str::<TransferEncoding>(value.val0()) {
                    Some(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().filtered(|val| **val < chunks_threshold).is_none() {
        return Chunked;
    }

    // Identity by default
    Identity
}

impl<R: Reader> Response<R> {
    #[experimental]
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<uint>) -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::new(),
            data_length: data_length,
        };

        for h in headers.move_iter() {
            response.add_header(h)
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    #[experimental]
    pub fn add_header(&mut self, header: Header) {
        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match from_str::<uint>(header.value.as_slice()) {
                Some(val) => self.data_length = Some(val),
                None => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header)
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[unstable]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.add_header(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[unstable]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    #[unstable]
    pub fn raw_print<W: Writer>(mut self, mut writer: W, http_version: HTTPVersion,
                                request_headers: &[Header], do_not_send_body: bool)
                                -> IoResult<()>
    {
        let transfer_encoding = choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length);

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.unshift(build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                from_str("Server: tiny-http (Rust)").unwrap()
            );
        }

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body ||
            match self.status_code.as_uint() {
                // sattus code 1xx, 204 and 304 MUST not include a body
                100..199 | 204 | 304 => true,
                _ => false
            };

        // preparing headers for transfer
        match transfer_encoding {
            Chunked => {
                self.headers.push(
                    from_str("Transfer-Encoding: chunked").unwrap()
                )
            },

            Identity => {
                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    from_str(format!("Content-Length: {}", data_length).as_slice()).unwrap()
                )
            }
        };

        // sending headers
        try!(write_message_header(writer.by_ref(), &http_version,
            &self.status_code, self.headers.as_slice()));

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {

                Chunked => {
                    use util::ChunksEncoder;

                    let mut writer = ChunksEncoder::new(writer);
                    try!(util::copy(&mut self.reader, &mut writer));
                },

                Identity => {
                    use util::EqualReader;

                    assert!(self.data_length.is_some());
                    let data_length = self.data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) =
                            EqualReader::new(self.reader.by_ref(), data_length);
                        try!(util::copy(&mut equ_reader, &mut writer));
                    }
                }

            }
        }

        Ok(())
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    #[experimental]
    pub fn from_file(mut file: File) -> Response<File> {
        let file_size = file.stat().ok().map(|v| v.size as uint);

        Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            file_size
        )
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len)
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len)
        )
    }
}

impl Response<NullReader> {
    /// Builds an empty `Response` with the given status code.
    #[experimental]
    pub fn new_empty(status_code: StatusCode) -> Response<NullReader> {
        Response::new(
            status_code,
            Vec::new(),
            NullReader,
            Some(0)
        )
    }
}
<commit_msg>Add dummy implementation for additional_headers in response<commit_after>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response whose purpose is to be given to a `Request`.
///
/// Some headers cannot be changed. Trying to define the value
///  of one of these will have no effect:
///
///  - `Accept-Ranges`
///  - `Connection`
///  - `Content-Range`
///  - `Trailer`
///  - `Transfer-Encoding`
///  - `Upgrade`
///
/// Some headers have special behaviors:
///
///  - `Content-Encoding`: If you define this header, the library
///      will assume that the data from the `Reader` has the specified encoding
///      and will just pass-through.
///  - `Content-Length`: If you define this header to `N`, only the first `N` bytes
///      of the `Reader` will be read. If the `Reader` reaches `EOF` before `N` bytes have
///      been read, `0`s will be sent. Also, this header may not be passed to the final
///      output.
///
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    data_length: Option<uint>,
}

/// Transfer encoding to use when sending the message.
/// Note that only *supported* encoding are listed here.
enum TransferEncoding {
    Identity,
    Chunked,
}

impl ::std::from_str::FromStr for TransferEncoding {
    fn from_str(input: &str) -> Option<TransferEncoding> {
        use std::ascii::StrAsciiExt;

        if input.eq_ignore_ascii_case("identity") {
            return Some(Identity);
        } else if input.eq_ignore_ascii_case("chunked") {
            return Some(Chunked);
        }

        None
    }
}

/// Builds a Date: header with the current date.
// TODO: this is optimisable
fn build_date_header() -> Header {
    use time;
    let date = time::now_utc().strftime("%a, %d %b %Y %H:%M:%S GMT");
    from_str(format!("Date: {}", date).as_slice()).unwrap()
}

fn write_message_header<W: Writer>(mut writer: W, http_version: &HTTPVersion,
                                   status_code: &StatusCode, headers: &[Header])
    -> IoResult<()>
{
    // writing status line
    try!(write!(writer, "HTTP/{} {} {}\r\n",
        http_version,
        status_code.as_uint(),
        status_code.get_default_reason_phrase()
    ));

    // writing headers
    for header in headers.iter() {
        try!(write!(writer, "{}: {}\r\n", header.field, header.value));
    }

    // separator between header and data
    try!(write!(writer, "\r\n"));

    Ok(())
}

fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
                            entity_length: &Option<uint>)
    -> TransferEncoding
{
    use util;

    // HTTP 1.0 doesn't support other encoding
    if *http_version <= HTTPVersion(1, 0) {
        return Identity;
    }

    // parsing the request's TE header
    let user_request = request_headers.iter()
        // finding TE
        .find(|h| h.field.equiv(&"TE"))

        // getting its value
        .map(|h| h.value.as_slice())

        // getting the corresponding TransferEncoding
        .and_then(|value| {
            // getting list of requested elements
            let mut parse = util::parse_header_value(value);

            // sorting elements by most priority
            parse.sort_by(|a, b| b.val1().partial_cmp(&a.val1()).unwrap_or(Equal));

            // trying to parse each requested encoding
            for value in parse.iter() {
                // q=0 are ignored
                if value.val1() <= 0.0 { continue }

                match from_str::<TransferEncoding>(value.val0()) {
                    Some(te) => return Some(te),
                    _ => ()     // unrecognized/unsupported encoding
                };
            }

            // encoding not found
            None
        });

    //
    if user_request.is_some() {
        return user_request.unwrap();
    }

    // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
    let chunks_threshold = 32768;
    if entity_length.as_ref().filtered(|val| **val < chunks_threshold).is_none() {
        return Chunked;
    }

    // Identity by default
    Identity
}

impl<R: Reader> Response<R> {
    #[experimental]
    pub fn new(status_code: StatusCode, headers: Vec<Header>,
               data: R, data_length: Option<uint>,
               additional_headers: Option<Receiver<Header>>)
                -> Response<R>
    {
        let mut response = Response {
            reader: data,
            status_code: status_code,
            headers: Vec::new(),
            data_length: data_length,
        };

        for h in headers.move_iter() {
            response.add_header(h)
        }

        // dummy implementation
        if additional_headers.is_some() {
            for h in additional_headers.unwrap().iter() {
                response.add_header(h)
            }
        }

        response
    }

    /// Adds a header to the list.
    /// Does all the checks.
    #[experimental]
    pub fn add_header(&mut self, header: Header) {
        // ignoring forbidden headers
        if header.field.equiv(&"Accept-Ranges") ||
           header.field.equiv(&"Connection") ||
           header.field.equiv(&"Content-Range") ||
           header.field.equiv(&"Trailer") ||
           header.field.equiv(&"Transfer-Encoding") ||
           header.field.equiv(&"Upgrade")
        {
            return;
        }

        // if the header is Content-Length, setting the data length
        if header.field.equiv(&"Content-Length") {
            match from_str::<uint>(header.value.as_slice()) {
                Some(val) => self.data_length = Some(val),
                None => ()      // wrong value for content-length
            };

            return;
        }

        self.headers.push(header)
    }

    /// Returns the same request, but with an additional header.
    ///
    /// Some headers cannot be modified and some other have a
    ///  special behavior. See the documentation above.
    #[unstable]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.add_header(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[unstable]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Prints the HTTP response to a writer.
    ///
    /// This function is the one used to send the response to the client's socket.
    /// Therefore you shouldn't expect anything pretty-printed or even readable.
    ///
    /// The HTTP version and headers passed as arguments are used to
    ///  decide which features (most notably, encoding) to use.
    ///
    /// Note: does not flush the writer.
    #[unstable]
    pub fn raw_print<W: Writer>(mut self, mut writer: W, http_version: HTTPVersion,
                                request_headers: &[Header], do_not_send_body: bool)
                                -> IoResult<()>
    {
        let transfer_encoding = choose_transfer_encoding(request_headers,
                                    &http_version, &self.data_length);

        // add `Date` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
            self.headers.unshift(build_date_header());
        }

        // add `Server` if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                from_str("Server: tiny-http (Rust)").unwrap()
            );
        }

        // checking whether to ignore the body of the response
        let do_not_send_body = do_not_send_body ||
            match self.status_code.as_uint() {
                // sattus code 1xx, 204 and 304 MUST not include a body
                100..199 | 204 | 304 => true,
                _ => false
            };

        // preparing headers for transfer
        match transfer_encoding {
            Chunked => {
                self.headers.push(
                    from_str("Transfer-Encoding: chunked").unwrap()
                )
            },

            Identity => {
                assert!(self.data_length.is_some());
                let data_length = self.data_length.unwrap();

                self.headers.push(
                    from_str(format!("Content-Length: {}", data_length).as_slice()).unwrap()
                )
            }
        };

        // sending headers
        try!(write_message_header(writer.by_ref(), &http_version,
            &self.status_code, self.headers.as_slice()));

        // sending the body
        if !do_not_send_body {
            match transfer_encoding {

                Chunked => {
                    use util::ChunksEncoder;

                    let mut writer = ChunksEncoder::new(writer);
                    try!(util::copy(&mut self.reader, &mut writer));
                },

                Identity => {
                    use util::EqualReader;

                    assert!(self.data_length.is_some());
                    let data_length = self.data_length.unwrap();

                    if data_length >= 1 {
                        let (mut equ_reader, _) =
                            EqualReader::new(self.reader.by_ref(), data_length);
                        try!(util::copy(&mut equ_reader, &mut writer));
                    }
                }

            }
        }

        Ok(())
    }
}

impl Response<File> {
    /// Builds a new `Response` from a `File`.
    ///
    /// The `Content-Type` will **not** be automatically detected,
    ///  you must set it yourself.
    #[experimental]
    pub fn from_file(mut file: File) -> Response<File> {
        let file_size = file.stat().ok().map(|v| v.size as uint);

        Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            file_size,
            None,
        )
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len),
            None,
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len),
            None,
        )
    }
}

impl Response<NullReader> {
    /// Builds an empty `Response` with the given status code.
    #[experimental]
    pub fn new_empty(status_code: StatusCode) -> Response<NullReader> {
        Response::new(
            status_code,
            Vec::new(),
            NullReader,
            Some(0),
            None,
        )
    }
}
<|endoftext|>


<commit_before>#![crate_name = "sdl2"]
#![crate_type = "lib"]

#![feature(optin_builtin_traits, core)]

extern crate libc;
#[macro_use]
extern crate bitflags;
extern crate sdl2_sys as sys;

pub use sdl::*;

pub mod keycode;
pub mod scancode;

pub mod clipboard;
pub mod cpuinfo;
#[macro_use] pub mod macros;
pub mod event;
pub mod filesystem;
pub mod gesture;
pub mod touch;
pub mod joystick;
pub mod controller;
pub mod haptic;
pub mod keyboard;
pub mod mouse;
pub mod rect;
pub mod surface;
pub mod pixels;
pub mod video;
pub mod timer;
pub mod render;
pub mod rwops;
pub mod sdl;
pub mod audio;
pub mod version;
pub mod messagebox;
<commit_msg>Reintroduce std_misc when testing<commit_after>#![crate_name = "sdl2"]
#![crate_type = "lib"]

#![feature(optin_builtin_traits, core)]
#![cfg_attr(test, feature(std_misc))]

extern crate libc;
#[macro_use]
extern crate bitflags;
extern crate sdl2_sys as sys;

pub use sdl::*;

pub mod keycode;
pub mod scancode;

pub mod clipboard;
pub mod cpuinfo;
#[macro_use] pub mod macros;
pub mod event;
pub mod filesystem;
pub mod gesture;
pub mod touch;
pub mod joystick;
pub mod controller;
pub mod haptic;
pub mod keyboard;
pub mod mouse;
pub mod rect;
pub mod surface;
pub mod pixels;
pub mod video;
pub mod timer;
pub mod render;
pub mod rwops;
pub mod sdl;
pub mod audio;
pub mod version;
pub mod messagebox;
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
use std::path::PathBuf;

use anyhow::{anyhow, bail, Result};
use config::Config;
use log::info;
use serde_derive::{Deserialize, Serialize};

use crate::platform::directories::*;

/// All settings which are used by both, the client and the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Shared {
    /// The directory that is used for all runtime information. \
    /// I.e. task logs, sockets, state dumps, etc.
    pub pueue_directory: PathBuf,
    /// If this is set to true, unix sockets will be used.
    /// Otherwise we default to TCP+TLS
    #[cfg(not(target_os = "windows"))]
    pub use_unix_socket: bool,
    /// The path to the unix socket.
    #[cfg(not(target_os = "windows"))]
    pub unix_socket_path: PathBuf,

    /// The TCP hostname/ip address.
    pub host: String,
    /// The TCP port.
    pub port: String,
    /// The path to the TLS certificate used by the daemon. \
    /// This is also used by the client to verify the daemon's identity.
    pub daemon_cert: PathBuf,
    /// The path to the TLS key used by the daemon.
    pub daemon_key: PathBuf,
    /// The path to the file containing the shared secret used to authenticate the client.
    pub shared_secret_path: PathBuf,
}

/// All settings which are used by the client
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Client {
    /// Whether the client should read the logs directly from disk or whether it should
    /// request the data from the daemon via socket.
    pub read_local_logs: bool,
    /// Whether the client should show a confirmation question on potential dangerous actions.
    pub show_confirmation_questions: bool,
    /// Whether aliases specified in `pueue_aliases.yml` should be expanded in the `pueue status`
    /// or shown in their short form.
    pub show_expanded_aliases: bool,
    /// The max amount of lines each task get's in the `pueue status` view.
    pub max_status_lines: Option<usize>,
}

/// All settings which are used by the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Daemon {
    /// How many parallel tasks a group should have by default
    pub default_parallel_tasks: usize,
    /// Whether a group should be paused as soon as a single task fails
    pub pause_group_on_failure: bool,
    /// Whether the daemon (and all groups) should be paused as soon as a single task fails
    pub pause_all_on_failure: bool,
    /// The callback that's called whenever a task finishes.
    pub callback: Option<String>,
    /// This shouldn't be manipulated manually if the daemon is running.
    /// This represents all known groups and their amount of parallel tasks.
    pub groups: BTreeMap<String, usize>,
}

/// The parent settings struct. \
/// This contains all other setting structs.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
    pub client: Client,
    pub daemon: Daemon,
    pub shared: Shared,
}

impl Settings {
    /// This function creates a new configuration instance and
    /// populates it with default values for every option. \
    /// If a local config file already exists, it is parsed and
    /// overrules the default option values.
    /// The default local config is located at "~/.config/pueue.yml".
    ///
    /// If `require_config` is `true`, an error will be thrown, if no configuration file can be found.
    /// This is utilized by the client, since only the daemon is allowed to touch the configuration
    /// file.
    pub fn new(require_config: bool, from_file: &Option<PathBuf>) -> Result<Settings> {
        let mut config = Settings::default_config()?;

        // Load the config from a very specific file path
        if let Some(path) = from_file {
            if !path.exists() || !path.is_file() {
                bail!("Couldn't find config at path {:?}", path);
            }
            info!("Using config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            config.merge(config_file)?;
        } else {
            // Load settings from the default config paths.
            parse_config(&mut config, require_config)?;
        }

        // Try to can deserialize the entire configuration
        Ok(config.try_into()?)
    }

    pub fn default_config() -> Result<Config> {
        let mut config = Config::new();
        let pueue_path = default_pueue_path()?;
        config.set_default("shared.pueue_directory", pueue_path.clone())?;
        #[cfg(not(target_os = "windows"))]
        config.set_default("shared.use_unix_socket", true)?;
        #[cfg(not(target_os = "windows"))]
        config.set_default("shared.unix_socket_path", get_unix_socket_path()?)?;

        config.set_default("shared.host", "127.0.0.1")?;
        config.set_default("shared.port", "6924")?;
        config.set_default("shared.tls_enabled", true)?;
        config.set_default(
            "shared.daemon_key",
            pueue_path.clone() + "/certs/daemon.key",
        )?;
        config.set_default(
            "shared.daemon_cert",
            pueue_path.clone() + "/certs/daemon.cert",
        )?;
        config.set_default("shared.shared_secret_path", pueue_path + "/shared_secret")?;

        // Client specific config
        config.set_default("client.read_local_logs", true)?;
        config.set_default("client.show_expanded_aliases", false)?;
        config.set_default("client.show_confirmation_questions", false)?;
        config.set_default("client.max_status_lines", None::<i64>)?;

        // Daemon specific config
        config.set_default("daemon.default_parallel_tasks", 1)?;
        config.set_default("daemon.pause_group_on_failure", false)?;
        config.set_default("daemon.pause_all_on_failure", false)?;
        config.set_default("daemon.callback", None::<String>)?;
        config.set_default("daemon.groups", HashMap::<String, i64>::new())?;

        Ok(config)
    }

    /// Try to read the config file without any default values.
    /// This is done by the daemon on startup.
    /// If the file can be read without any need for defaults, we don't have to persist it
    /// afterwards.
    pub fn read(require_config: bool, from_file: &Option<PathBuf>) -> Result<Settings> {
        let mut config = Config::new();

        // Load the config from a very specific file path
        if let Some(path) = from_file {
            if !path.exists() {
                bail!("Couldn't find config at path {:?}", path);
            }
            info!("Using config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            config.merge(config_file)?;
        } else {
            // Load settings from the default config paths.
            parse_config(&mut config, require_config)?;
        }

        // Try to can deserialize the entire configuration
        Ok(config.try_into()?)
    }

    /// Save the current configuration as a file to the given path. \
    /// If no path is given, the default configuration path will be used. \
    /// The file is then written to the main configuration directory of the respective OS.
    pub fn save(&self, path: &Option<PathBuf>) -> Result<()> {
        let config_path = if let Some(path) = path {
            path.clone()
        } else {
            default_config_directory()?.join("pueue.yml")
        };
        let config_dir = config_path
            .parent()
            .ok_or_else(|| anyhow!("Couldn't resolve config dir"))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = serde_yaml::to_string(self)?;
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

/// Get all possible configuration paths and check if there are
/// configuration files at those locations.
/// All configs will be merged by importance.
///
/// If `require_config` is `true`, an error will be thrown, if no configuration file can be found.
fn parse_config(settings: &mut Config, require_config: bool) -> Result<()> {
    let mut config_found = false;
    info!("Parsing config files");
    for directory in get_config_directories()?.into_iter() {
        let path = directory.join("pueue.yml");
        info!("Checking path: {:?}", &path);
        if path.exists() && path.is_file() {
            info!("Found config file at: {:?}", path);
            config_found = true;
            let config_file = config::File::with_name(path.to_str().unwrap());
            settings.merge(config_file)?;
        }
    }

    if require_config && !config_found {
        bail!("Couldn't find a configuration file. Did you start the daemon yet?");
    }

    Ok(())
}
<commit_msg>settings: add support dark_mode in settings<commit_after>use std::collections::{BTreeMap, HashMap};
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
use std::path::PathBuf;

use anyhow::{anyhow, bail, Result};
use config::Config;
use log::info;
use serde_derive::{Deserialize, Serialize};

use crate::platform::directories::*;

/// All settings which are used by both, the client and the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Shared {
    /// The directory that is used for all runtime information. \
    /// I.e. task logs, sockets, state dumps, etc.
    pub pueue_directory: PathBuf,
    /// If this is set to true, unix sockets will be used.
    /// Otherwise we default to TCP+TLS
    #[cfg(not(target_os = "windows"))]
    pub use_unix_socket: bool,
    /// The path to the unix socket.
    #[cfg(not(target_os = "windows"))]
    pub unix_socket_path: PathBuf,

    /// The TCP hostname/ip address.
    pub host: String,
    /// The TCP port.
    pub port: String,
    /// The path to the TLS certificate used by the daemon. \
    /// This is also used by the client to verify the daemon's identity.
    pub daemon_cert: PathBuf,
    /// The path to the TLS key used by the daemon.
    pub daemon_key: PathBuf,
    /// The path to the file containing the shared secret used to authenticate the client.
    pub shared_secret_path: PathBuf,
}

/// All settings which are used by the client
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Client {
    /// Whether the client should read the logs directly from disk or whether it should
    /// request the data from the daemon via socket.
    pub read_local_logs: bool,
    /// Whether the client should show a confirmation question on potential dangerous actions.
    pub show_confirmation_questions: bool,
    /// Whether aliases specified in `pueue_aliases.yml` should be expanded in the `pueue status`
    /// or shown in their short form.
    pub show_expanded_aliases: bool,
    /// Whether the client should use dark shades instead of regular colors.
    #[serde(default = "default_dark_mode")]
    pub dark_mode: bool,
    /// The max amount of lines each task get's in the `pueue status` view.
    pub max_status_lines: Option<usize>,
}

/// All settings which are used by the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Daemon {
    /// How many parallel tasks a group should have by default
    pub default_parallel_tasks: usize,
    /// Whether a group should be paused as soon as a single task fails
    pub pause_group_on_failure: bool,
    /// Whether the daemon (and all groups) should be paused as soon as a single task fails
    pub pause_all_on_failure: bool,
    /// The callback that's called whenever a task finishes.
    pub callback: Option<String>,
    /// This shouldn't be manipulated manually if the daemon is running.
    /// This represents all known groups and their amount of parallel tasks.
    pub groups: BTreeMap<String, usize>,
}

/// The parent settings struct. \
/// This contains all other setting structs.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
    pub client: Client,
    pub daemon: Daemon,
    pub shared: Shared,
}

impl Settings {
    /// This function creates a new configuration instance and
    /// populates it with default values for every option. \
    /// If a local config file already exists, it is parsed and
    /// overrules the default option values.
    /// The default local config is located at "~/.config/pueue.yml".
    ///
    /// If `require_config` is `true`, an error will be thrown, if no configuration file can be found.
    /// This is utilized by the client, since only the daemon is allowed to touch the configuration
    /// file.
    pub fn new(require_config: bool, from_file: &Option<PathBuf>) -> Result<Settings> {
        let mut config = Settings::default_config()?;

        // Load the config from a very specific file path
        if let Some(path) = from_file {
            if !path.exists() || !path.is_file() {
                bail!("Couldn't find config at path {:?}", path);
            }
            info!("Using config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            config.merge(config_file)?;
        } else {
            // Load settings from the default config paths.
            parse_config(&mut config, require_config)?;
        }

        // Try to can deserialize the entire configuration
        Ok(config.try_into()?)
    }

    pub fn default_config() -> Result<Config> {
        let mut config = Config::new();
        let pueue_path = default_pueue_path()?;
        config.set_default("shared.pueue_directory", pueue_path.clone())?;
        #[cfg(not(target_os = "windows"))]
        config.set_default("shared.use_unix_socket", true)?;
        #[cfg(not(target_os = "windows"))]
        config.set_default("shared.unix_socket_path", get_unix_socket_path()?)?;

        config.set_default("shared.host", "127.0.0.1")?;
        config.set_default("shared.port", "6924")?;
        config.set_default("shared.tls_enabled", true)?;
        config.set_default(
            "shared.daemon_key",
            pueue_path.clone() + "/certs/daemon.key",
        )?;
        config.set_default(
            "shared.daemon_cert",
            pueue_path.clone() + "/certs/daemon.cert",
        )?;
        config.set_default("shared.shared_secret_path", pueue_path + "/shared_secret")?;

        // Client specific config
        config.set_default("client.read_local_logs", true)?;
        config.set_default("client.show_expanded_aliases", false)?;
        config.set_default("client.show_confirmation_questions", false)?;
        config.set_default("client.dark_mode", false)?;
        config.set_default("client.max_status_lines", None::<i64>)?;

        // Daemon specific config
        config.set_default("daemon.default_parallel_tasks", 1)?;
        config.set_default("daemon.pause_group_on_failure", false)?;
        config.set_default("daemon.pause_all_on_failure", false)?;
        config.set_default("daemon.callback", None::<String>)?;
        config.set_default("daemon.groups", HashMap::<String, i64>::new())?;

        Ok(config)
    }

    /// Try to read the config file without any default values.
    /// This is done by the daemon on startup.
    /// If the file can be read without any need for defaults, we don't have to persist it
    /// afterwards.
    pub fn read(require_config: bool, from_file: &Option<PathBuf>) -> Result<Settings> {
        let mut config = Config::new();

        // Load the config from a very specific file path
        if let Some(path) = from_file {
            if !path.exists() {
                bail!("Couldn't find config at path {:?}", path);
            }
            info!("Using config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            config.merge(config_file)?;
        } else {
            // Load settings from the default config paths.
            parse_config(&mut config, require_config)?;
        }

        // Try to can deserialize the entire configuration
        Ok(config.try_into()?)
    }

    /// Save the current configuration as a file to the given path. \
    /// If no path is given, the default configuration path will be used. \
    /// The file is then written to the main configuration directory of the respective OS.
    pub fn save(&self, path: &Option<PathBuf>) -> Result<()> {
        let config_path = if let Some(path) = path {
            path.clone()
        } else {
            default_config_directory()?.join("pueue.yml")
        };
        let config_dir = config_path
            .parent()
            .ok_or_else(|| anyhow!("Couldn't resolve config dir"))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = serde_yaml::to_string(self)?;
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

/// Get all possible configuration paths and check if there are
/// configuration files at those locations.
/// All configs will be merged by importance.
///
/// If `require_config` is `true`, an error will be thrown, if no configuration file can be found.
fn parse_config(settings: &mut Config, require_config: bool) -> Result<()> {
    let mut config_found = false;
    info!("Parsing config files");
    for directory in get_config_directories()?.into_iter() {
        let path = directory.join("pueue.yml");
        info!("Checking path: {:?}", &path);
        if path.exists() && path.is_file() {
            info!("Found config file at: {:?}", path);
            config_found = true;
            let config_file = config::File::with_name(path.to_str().unwrap());
            settings.merge(config_file)?;
        }
    }

    if require_config && !config_found {
        bail!("Couldn't find a configuration file. Did you start the daemon yet?");
    }

    Ok(())
}

/// The default value for the `dark_mode` client settings.
/// Needed to keep backward compatibility between v0.11 and v0.12
fn default_dark_mode() -> bool {
    false
}
<|endoftext|>


<commit_before>// Copyright 2014-2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use imp_prelude::*;
use error::{ShapeError, ErrorKind, from_kind};

/// Stack arrays along the given axis.
///
/// ```
/// use ndarray::{arr2, Axis, stack};
///
/// let a = arr2(&[[2., 2.],
///                [3., 3.]]);
/// assert!(
///     stack(Axis(0), &[a.view(), a.view()])
///     == Ok(arr2(&[[2., 2.],
///                  [3., 3.],
///                  [2., 2.],
///                  [3., 3.]]))
/// );
/// ```
pub fn stack<'a, A, D>(axis: Axis, arrays: &[ArrayView<'a, A, D>])
    -> Result<OwnedArray<A, D>, ShapeError>
    where A: Copy,
          D: RemoveAxis
{
    if arrays.len() == 0 {
        return Err(from_kind(ErrorKind::Unsupported));
    }
    let mut res_dim = arrays[0].dim();
    if axis.axis() >= res_dim.ndim() {
        return Err(from_kind(ErrorKind::OutOfBounds));
    }
    let common_dim = res_dim.remove_axis(axis);
    if arrays.iter().any(|a| a.dim().remove_axis(axis) != common_dim) {
        return Err(from_kind(ErrorKind::IncompatibleShape));
    }

    let stacked_dim = arrays.iter()
                            .fold(0, |acc, a| acc + a.shape().axis(axis));
    res_dim.set_axis(axis, stacked_dim);

    // we can safely use uninitialized values here because they are Copy
    // and we will only ever write to them
    let size = res_dim.size();
    let mut v = Vec::with_capacity(size);
    unsafe {
        v.set_len(size);
    }
    let mut res = try!(OwnedArray::from_vec_dim(res_dim, v));

    {
        let mut assign_view = res.view_mut();
        for array in arrays {
            let len = array.shape().axis(axis);
            let (mut front, rest) = assign_view.split_at(axis, len);
            front.assign(array);
            assign_view = rest;
        }
    }
    Ok(res)
}

/// Stack arrays along the given axis.
///
/// Uses the [`stack`][1] function, calling `ArrayView::from(&a)` on each
/// argument `a`.
///
/// [1]: fn.stack.html
///
/// ***Panics*** if the `stack` function would return an error.
///
/// ```
/// #[macro_use(stack)]
/// extern crate ndarray;
///
/// use ndarray::{arr2, Axis, stack};
///
/// # fn main() {
///
/// let a = arr2(&[[2., 2.],
///                [3., 3.]]);
/// assert!(
///     stack![Axis(0), a, a]
///     == arr2(&[[2., 2.],
///               [3., 3.],
///               [2., 2.],
///               [3., 3.]])
/// );
/// # }
/// ```
#[macro_export]
macro_rules! stack {
    ($axis:expr, $( $array:expr ),+ ) => {
        ndarray::stack($axis, &[ $(ndarray::ArrayView::from(&$array) ),* ]).unwrap()
    }
}
<commit_msg>Document errors in stack()<commit_after>// Copyright 2014-2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use imp_prelude::*;
use error::{ShapeError, ErrorKind, from_kind};

/// Stack arrays along the given axis.
///
/// ***Errors*** if the arrays don't all have the same dimension
/// (may be made more flexible in the future).<br>
/// ***Errors*** if `arrays` is empty, if `axis` is out of bounds,
/// if the result is larger than is possible to represent.
///
/// ```
/// use ndarray::{arr2, Axis, stack};
///
/// let a = arr2(&[[2., 2.],
///                [3., 3.]]);
/// assert!(
///     stack(Axis(0), &[a.view(), a.view()])
///     == Ok(arr2(&[[2., 2.],
///                  [3., 3.],
///                  [2., 2.],
///                  [3., 3.]]))
/// );
/// ```
pub fn stack<'a, A, D>(axis: Axis, arrays: &[ArrayView<'a, A, D>])
    -> Result<OwnedArray<A, D>, ShapeError>
    where A: Copy,
          D: RemoveAxis
{
    if arrays.len() == 0 {
        return Err(from_kind(ErrorKind::Unsupported));
    }
    let mut res_dim = arrays[0].dim();
    if axis.axis() >= res_dim.ndim() {
        return Err(from_kind(ErrorKind::OutOfBounds));
    }
    let common_dim = res_dim.remove_axis(axis);
    if arrays.iter().any(|a| a.dim().remove_axis(axis) != common_dim) {
        return Err(from_kind(ErrorKind::IncompatibleShape));
    }

    let stacked_dim = arrays.iter()
                            .fold(0, |acc, a| acc + a.shape().axis(axis));
    res_dim.set_axis(axis, stacked_dim);

    // we can safely use uninitialized values here because they are Copy
    // and we will only ever write to them
    let size = res_dim.size();
    let mut v = Vec::with_capacity(size);
    unsafe {
        v.set_len(size);
    }
    let mut res = try!(OwnedArray::from_vec_dim(res_dim, v));

    {
        let mut assign_view = res.view_mut();
        for array in arrays {
            let len = array.shape().axis(axis);
            let (mut front, rest) = assign_view.split_at(axis, len);
            front.assign(array);
            assign_view = rest;
        }
    }
    Ok(res)
}

/// Stack arrays along the given axis.
///
/// Uses the [`stack`][1] function, calling `ArrayView::from(&a)` on each
/// argument `a`.
///
/// [1]: fn.stack.html
///
/// ***Panics*** if the `stack` function would return an error.
///
/// ```
/// #[macro_use(stack)]
/// extern crate ndarray;
///
/// use ndarray::{arr2, Axis, stack};
///
/// # fn main() {
///
/// let a = arr2(&[[2., 2.],
///                [3., 3.]]);
/// assert!(
///     stack![Axis(0), a, a]
///     == arr2(&[[2., 2.],
///               [3., 3.],
///               [2., 2.],
///               [3., 3.]])
/// );
/// # }
/// ```
#[macro_export]
macro_rules! stack {
    ($axis:expr, $( $array:expr ),+ ) => {
        ndarray::stack($axis, &[ $(ndarray::ArrayView::from(&$array) ),* ]).unwrap()
    }
}
<|endoftext|>


<commit_before>use std::{convert::TryFrom, mem::MaybeUninit};

use crate::pagecache::constants::PAGE_CONSOLIDATION_THRESHOLD;

#[derive(Debug, Clone, Copy)]
pub(crate) struct StackVec<T: Copy + Sized> {
    items: [MaybeUninit<T>; PAGE_CONSOLIDATION_THRESHOLD],
    len: u8,
}

impl<T: Copy> Default for StackVec<T> {
    fn default() -> StackVec<T> {
        StackVec {
            items: [MaybeUninit::uninit(); PAGE_CONSOLIDATION_THRESHOLD],
            len: 0,
        }
    }
}

impl<T: Copy + Sized> std::ops::Deref for StackVec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *const T = self.items.as_ptr() as *const T;
            std::slice::from_raw_parts(ptr, self.len as usize)
        }
    }
}

impl<T: Copy + Sized> std::ops::DerefMut for StackVec<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *mut T = self.items.as_mut_ptr() as *mut T;
            std::slice::from_raw_parts_mut(ptr, self.len as usize)
        }
    }
}

impl<T: Copy + Sized> StackVec<T> {
    pub(crate) fn single(item: T) -> StackVec<T> {
        let mut sv = Self::default();
        sv.push(item);
        sv
    }

    pub(crate) fn extend_from_slice(&mut self, other: &[T]) {
        assert!(
            self.len as usize + other.len() <= PAGE_CONSOLIDATION_THRESHOLD,
            "tried to extend_from_slice into StackVec past max capacity"
        );

        #[allow(unsafe_code)]
        unsafe {
            let src = other.as_ptr();
            let dst = self.items.as_mut_ptr().add(self.len as usize) as *mut T;
            std::ptr::copy(src, dst, other.len());
        }

        self.len += u8::try_from(other.len()).unwrap();
    }

    pub(crate) fn _insert(&mut self, idx: usize, item: T) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to insert into StackVec already at max capacity"
        );

        assert!(idx <= self.len());

        if idx != self.len as usize {
            let items = self.len as usize - idx;

            #[allow(unsafe_code)]
            unsafe {
                let src = self.items.as_ptr().add(idx);
                let dst = self.items.as_mut_ptr().add(idx + 1);
                std::ptr::copy(src, dst, items);
            }
        }

        self.len += 1;
        self.items[idx] = MaybeUninit::new(item);
    }

    pub(crate) fn push(&mut self, item: T) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to push into StackVec already at max capacity"
        );
        self.items[self.len as usize] = MaybeUninit::new(item);
        self.len += 1;
    }

    pub(crate) fn _pop(&mut self) -> Option<T> {
        if self.len > 0 {
            self.len -= 1;

            #[allow(unsafe_code)]
            unsafe {
                Some(self.items[self.len as usize].as_ptr().read())
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod qc {
    use quickcheck::{Arbitrary, Gen};
    use rand::Rng;

    use super::{StackVec, PAGE_CONSOLIDATION_THRESHOLD};

    #[derive(Clone, Debug)]
    enum Op {
        Extend(Vec<u8>),
        Insert(usize, u8),
        Push(u8),
        Pop,
    }

    impl Arbitrary for Op {
        fn arbitrary<G: Gen>(g: &mut G) -> Op {
            match g.gen_range(0, 4) {
                0 => {
                    let len = g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD);
                    let items = vec![g.gen(); len];
                    Op::Extend(items)
                }
                1 => Op::Insert(
                    g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD),
                    g.gen(),
                ),
                2 => Op::Push(g.gen()),
                3 => Op::Pop,
                _ => unreachable!(),
            }
        }
    }

    quickcheck::quickcheck! {
        fn qc_stackvec(ops: Vec<Op>) -> bool {
            let mut sv = StackVec::default();
            let mut v = vec![];

            for op in ops {
                match op {
                    Op::Extend(items) => {
                        if items.len() + v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.extend_from_slice(&items);
                            v.extend_from_slice(&items);
                        }
                    }
                    Op::Insert(at, item) => {
                        if at <= v.len() && v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.insert(at, item);
                            v.insert(at, item);
                        }
                    }
                    Op::Push(item) => {
                        if v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.push(item);
                            v.push(item);
                        }
                    }
                    Op::Pop => {
                        assert_eq!(sv.pop(), v.pop());
                    }
                }
                assert_eq!(&*sv, &*v);
            }

            true
        }
    }
}
<commit_msg>Update test for StackVec<commit_after>use std::{convert::TryFrom, mem::MaybeUninit};

use crate::pagecache::constants::PAGE_CONSOLIDATION_THRESHOLD;

#[derive(Debug, Clone, Copy)]
pub(crate) struct StackVec<T: Copy + Sized> {
    items: [MaybeUninit<T>; PAGE_CONSOLIDATION_THRESHOLD],
    len: u8,
}

impl<T: Copy> Default for StackVec<T> {
    fn default() -> StackVec<T> {
        StackVec {
            items: [MaybeUninit::uninit(); PAGE_CONSOLIDATION_THRESHOLD],
            len: 0,
        }
    }
}

impl<T: Copy + Sized> std::ops::Deref for StackVec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *const T = self.items.as_ptr() as *const T;
            std::slice::from_raw_parts(ptr, self.len as usize)
        }
    }
}

impl<T: Copy + Sized> std::ops::DerefMut for StackVec<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *mut T = self.items.as_mut_ptr() as *mut T;
            std::slice::from_raw_parts_mut(ptr, self.len as usize)
        }
    }
}

impl<T: Copy + Sized> StackVec<T> {
    pub(crate) fn single(item: T) -> StackVec<T> {
        let mut sv = Self::default();
        sv.push(item);
        sv
    }

    pub(crate) fn extend_from_slice(&mut self, other: &[T]) {
        assert!(
            self.len as usize + other.len() <= PAGE_CONSOLIDATION_THRESHOLD,
            "tried to extend_from_slice into StackVec past max capacity"
        );

        #[allow(unsafe_code)]
        unsafe {
            let src = other.as_ptr();
            let dst = self.items.as_mut_ptr().add(self.len as usize) as *mut T;
            std::ptr::copy(src, dst, other.len());
        }

        self.len += u8::try_from(other.len()).unwrap();
    }

    pub(crate) fn _insert(&mut self, idx: usize, item: T) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to insert into StackVec already at max capacity"
        );

        assert!(idx <= self.len());

        if idx != self.len as usize {
            let items = self.len as usize - idx;

            #[allow(unsafe_code)]
            unsafe {
                let src = self.items.as_ptr().add(idx);
                let dst = self.items.as_mut_ptr().add(idx + 1);
                std::ptr::copy(src, dst, items);
            }
        }

        self.len += 1;
        self.items[idx] = MaybeUninit::new(item);
    }

    pub(crate) fn push(&mut self, item: T) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to push into StackVec already at max capacity"
        );
        self.items[self.len as usize] = MaybeUninit::new(item);
        self.len += 1;
    }

    pub(crate) fn _pop(&mut self) -> Option<T> {
        if self.len > 0 {
            self.len -= 1;

            #[allow(unsafe_code)]
            unsafe {
                Some(self.items[self.len as usize].as_ptr().read())
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod qc {
    use quickcheck::{Arbitrary, Gen};
    use rand::Rng;

    use super::{StackVec, PAGE_CONSOLIDATION_THRESHOLD};

    #[derive(Clone, Debug)]
    enum Op {
        Extend(Vec<u8>),
        Insert(usize, u8),
        Push(u8),
        Pop,
    }

    impl Arbitrary for Op {
        fn arbitrary<G: Gen>(g: &mut G) -> Op {
            match g.gen_range(0, 4) {
                0 => {
                    let len = g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD);
                    let items = vec![g.gen(); len];
                    Op::Extend(items)
                }
                1 => Op::Insert(
                    g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD),
                    g.gen(),
                ),
                2 => Op::Push(g.gen()),
                3 => Op::Pop,
                _ => unreachable!(),
            }
        }
    }

    quickcheck::quickcheck! {
        fn qc_stackvec(ops: Vec<Op>) -> bool {
            let mut sv = StackVec::default();
            let mut v = vec![];

            for op in ops {
                match op {
                    Op::Extend(items) => {
                        if items.len() + v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.extend_from_slice(&items);
                            v.extend_from_slice(&items);
                        }
                    }
                    Op::Insert(at, item) => {
                        if at <= v.len() && v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv._insert(at, item);
                            v.insert(at, item);
                        }
                    }
                    Op::Push(item) => {
                        if v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.push(item);
                            v.push(item);
                        }
                    }
                    Op::Pop => {
                        assert_eq!(sv._pop(), v.pop());
                    }
                }
                assert_eq!(&*sv, &*v);
            }

            true
        }
    }
}
<|endoftext|>