<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 send_socks = try!(clone_socks(&socks[..]));
        let recv_addrs = try!(clone_addrs(&socks[..]));

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

        // 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(_) => {
                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.
            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>Foolproof the SSDPReceiver timeout mechanism On OS X it is possible to have addresses that cannot receive packets but can send them so set a socket read timeout just to be safe.<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),
            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);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Rouille 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::io;
use std::io::Cursor;
use std::io::Read;
use std::fs::File;
use rustc_serialize;

/// Contains a prototype of a response.
///
/// The response is only sent to the client when you return the `Response` object from your
/// request handler. This means that you are free to create as many `Response` objects as you want.
pub struct Response {
    /// The status code to return to the user.
    pub status_code: u16,

    /// List of headers to be returned in the response.
    ///
    /// Note that important headers such as `Connection` or `Content-Length` will be ignored
    /// from this list.
    // TODO: document precisely which headers
    pub headers: Vec<(String, String)>,

    /// An opaque type that contains the body of the response.
    pub data: ResponseBody,
}

impl Response {
    /// Returns true if the status code of this `Response` indicates success.
    ///
    /// This is the range [200-399].
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("hello world");
    /// assert!(response.success());
    /// ```
    #[inline]
    pub fn success(&self) -> bool {
        self.status_code >= 200 && self.status_code < 400
    }

    /// Shortcut for `!response.success()`.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::empty_400();
    /// assert!(response.error());
    /// ```
    #[inline]
    pub fn error(&self) -> bool {
        !self.success()
    }

    /// Builds a `Response` that redirects the user to another URL with a 303 status code.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::redirect("/foo");
    /// ```
    #[inline]
    pub fn redirect(target: &str) -> Response {
        Response {
            status_code: 303,
            headers: vec![("Location".to_owned(), target.to_owned())],
            data: ResponseBody::empty(),
        }
    }

    /// Builds a `Response` that outputs HTML.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("<p>hello <strong>world</strong></p>");
    /// ```
    #[inline]
    pub fn html<D>(content: D) -> Response where D: Into<Vec<u8>> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/html; charset=utf8".to_owned())],
            data: ResponseBody::from_data(content),
        }
    }

    /// Builds a `Response` that outputs plain text.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("hello world");
    /// ```
    #[inline]
    pub fn text<S>(text: S) -> Response where S: Into<String> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/plain; charset=utf8".to_owned())],
            data: ResponseBody::from_string(text),
        }
    }

    /// Builds a `Response` that outputs JSON.
    ///
    /// # Example
    ///
    /// ```ignore       // TODO: unignore after https://github.com/rust-lang/rust/issues/36863
    /// extern crate rustc_serialize;
    /// use rouille::Response;
    ///
    /// #[derive(RustcEncodable)]
    /// struct MyStruct {
    ///     field1: String,
    ///     field2: i32,
    /// }
    ///
    /// let response = Response::json(MyStruct { field1: "hello".to_owned(), field2: 5 });
    /// // The Response will contain something like `{ field1: "hello", field2: 5 }`
    /// ```
    #[inline]
    pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
        let data = rustc_serialize::json::encode(content).unwrap();

        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "application/json".to_owned())],
            data: ResponseBody::from_data(data),
        }
    }

    /// Builds a `Response` that returns a `401 Not Authorized` status
    /// and a `WWW-Authenticate` header.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::basic_http_auth_login_required("realm");
    /// ```
    #[inline]
    pub fn basic_http_auth_login_required(realm: &str) -> Response {
        // TODO: escape the realm
        Response {
            status_code: 401,
            headers: vec![("WWW-Authenticate".to_owned(), format!("Basic realm=\"{}\"", realm))],
            data: ResponseBody::empty(),
        }
    }

    /// Builds an empty `Response` with a 400 status code.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::empty_400();
    /// ```
    #[inline]
    pub fn empty_400() -> Response {
        Response {
            status_code: 400,
            headers: vec![],
            data: ResponseBody::empty()
        }
    }

    /// Builds an empty `Response` with a 404 status code.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::empty_404();
    /// ```
    #[inline]
    pub fn empty_404() -> Response {
        Response {
            status_code: 404,
            headers: vec![],
            data: ResponseBody::empty()
        }
    }

    /// Changes the status code of the response.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("hello world").with_status_code(500);
    /// ```
    #[inline]
    pub fn with_status_code(mut self, code: u16) -> Response {
        self.status_code = code;
        self
    }
}

/// An opaque type that represents the body of a response.
///
/// You can't access the inside of this struct, but you can build one by using one of the provided
/// constructors.
///
/// # Example
///
/// ```
/// use rouille::ResponseBody;
/// let body = ResponseBody::from_string("hello world");
/// ```
pub struct ResponseBody {
    data: Box<Read + Send>,
    data_length: Option<usize>,
}

impl ResponseBody {
    /// UNSTABLE. Extracts the content of the response. Do not use.
    #[doc(hidden)]
    #[inline]
    pub fn into_inner(self) -> (Box<Read + Send>, Option<usize>) {
        (self.data, self.data_length)
    }

    /// Builds a `ResponseBody` that doesn't return any data.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::ResponseBody;
    /// let body = ResponseBody::empty();
    /// ```
    #[inline]
    pub fn empty() -> ResponseBody {
        ResponseBody {
            data: Box::new(io::empty()),
            data_length: Some(0),
        }
    }

    /// Builds a new `ResponseBody` that will read the data from a `Read`.
    ///
    /// Note that this is suboptimal compared to other constructors because the length
    /// isn't known in advance.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use std::io;
    /// use std::io::Read;
    /// use rouille::ResponseBody;
    ///
    /// let body = ResponseBody::from_reader(io::stdin().take(128));
    /// ```
    #[inline]
    pub fn from_reader<R>(data: R) -> ResponseBody where R: Read + Send + 'static {
        ResponseBody {
            data: Box::new(data),
            data_length: None,
        }
    }

    /// Builds a new `ResponseBody` that returns the given data.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::ResponseBody;
    /// let body = ResponseBody::from_data(vec![12u8, 97, 34]);
    /// ```
    #[inline]
    pub fn from_data<D>(data: D) -> ResponseBody where D: Into<Vec<u8>> {
        let data = data.into();
        let len = data.len();

        ResponseBody {
            data: Box::new(Cursor::new(data)),
            data_length: Some(len),
        }
    }

    /// Builds a new `ResponseBody` that returns the content of the given file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use std::fs::File;
    /// use rouille::ResponseBody;
    ///
    /// let file = File::open("page.html").unwrap();
    /// let body = ResponseBody::from_file(file);
    /// ```
    #[inline]
    pub fn from_file(file: File) -> ResponseBody {
        let len = file.metadata().map(|metadata| metadata.len() as usize).ok();

        ResponseBody {
            data: Box::new(file),
            data_length: len,
        }
    }

    /// Builds a new `ResponseBody` that returns an UTF-8 string.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::ResponseBody;
    /// let body = ResponseBody::from_string("hello world");
    /// ```
    #[inline]
    pub fn from_string<S>(data: S) -> ResponseBody where S: Into<String> {
        ResponseBody::from_data(data.into().into_bytes())
    }
}
<commit_msg>Fix Response::json test<commit_after>// Copyright (c) 2016 The Rouille 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::io;
use std::io::Cursor;
use std::io::Read;
use std::fs::File;
use rustc_serialize;

/// Contains a prototype of a response.
///
/// The response is only sent to the client when you return the `Response` object from your
/// request handler. This means that you are free to create as many `Response` objects as you want.
pub struct Response {
    /// The status code to return to the user.
    pub status_code: u16,

    /// List of headers to be returned in the response.
    ///
    /// Note that important headers such as `Connection` or `Content-Length` will be ignored
    /// from this list.
    // TODO: document precisely which headers
    pub headers: Vec<(String, String)>,

    /// An opaque type that contains the body of the response.
    pub data: ResponseBody,
}

impl Response {
    /// Returns true if the status code of this `Response` indicates success.
    ///
    /// This is the range [200-399].
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("hello world");
    /// assert!(response.success());
    /// ```
    #[inline]
    pub fn success(&self) -> bool {
        self.status_code >= 200 && self.status_code < 400
    }

    /// Shortcut for `!response.success()`.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::empty_400();
    /// assert!(response.error());
    /// ```
    #[inline]
    pub fn error(&self) -> bool {
        !self.success()
    }

    /// Builds a `Response` that redirects the user to another URL with a 303 status code.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::redirect("/foo");
    /// ```
    #[inline]
    pub fn redirect(target: &str) -> Response {
        Response {
            status_code: 303,
            headers: vec![("Location".to_owned(), target.to_owned())],
            data: ResponseBody::empty(),
        }
    }

    /// Builds a `Response` that outputs HTML.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("<p>hello <strong>world</strong></p>");
    /// ```
    #[inline]
    pub fn html<D>(content: D) -> Response where D: Into<Vec<u8>> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/html; charset=utf8".to_owned())],
            data: ResponseBody::from_data(content),
        }
    }

    /// Builds a `Response` that outputs plain text.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("hello world");
    /// ```
    #[inline]
    pub fn text<S>(text: S) -> Response where S: Into<String> {
        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "text/plain; charset=utf8".to_owned())],
            data: ResponseBody::from_string(text),
        }
    }

    /// Builds a `Response` that outputs JSON.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate rustc_serialize;
    /// # #[macro_use] extern crate rouille;
    /// use rouille::Response;
    /// # fn main() {
    ///
    /// #[derive(RustcEncodable)]
    /// struct MyStruct {
    ///     field1: String,
    ///     field2: i32,
    /// }
    ///
    /// let response = Response::json(&MyStruct { field1: "hello".to_owned(), field2: 5 });
    /// // The Response will contain something like `{ field1: "hello", field2: 5 }`
    /// # }
    /// ```
    #[inline]
    pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
        let data = rustc_serialize::json::encode(content).unwrap();

        Response {
            status_code: 200,
            headers: vec![("Content-Type".to_owned(), "application/json".to_owned())],
            data: ResponseBody::from_data(data),
        }
    }

    /// Builds a `Response` that returns a `401 Not Authorized` status
    /// and a `WWW-Authenticate` header.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::basic_http_auth_login_required("realm");
    /// ```
    #[inline]
    pub fn basic_http_auth_login_required(realm: &str) -> Response {
        // TODO: escape the realm
        Response {
            status_code: 401,
            headers: vec![("WWW-Authenticate".to_owned(), format!("Basic realm=\"{}\"", realm))],
            data: ResponseBody::empty(),
        }
    }

    /// Builds an empty `Response` with a 400 status code.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::empty_400();
    /// ```
    #[inline]
    pub fn empty_400() -> Response {
        Response {
            status_code: 400,
            headers: vec![],
            data: ResponseBody::empty()
        }
    }

    /// Builds an empty `Response` with a 404 status code.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::empty_404();
    /// ```
    #[inline]
    pub fn empty_404() -> Response {
        Response {
            status_code: 404,
            headers: vec![],
            data: ResponseBody::empty()
        }
    }

    /// Changes the status code of the response.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::Response;
    /// let response = Response::text("hello world").with_status_code(500);
    /// ```
    #[inline]
    pub fn with_status_code(mut self, code: u16) -> Response {
        self.status_code = code;
        self
    }
}

/// An opaque type that represents the body of a response.
///
/// You can't access the inside of this struct, but you can build one by using one of the provided
/// constructors.
///
/// # Example
///
/// ```
/// use rouille::ResponseBody;
/// let body = ResponseBody::from_string("hello world");
/// ```
pub struct ResponseBody {
    data: Box<Read + Send>,
    data_length: Option<usize>,
}

impl ResponseBody {
    /// UNSTABLE. Extracts the content of the response. Do not use.
    #[doc(hidden)]
    #[inline]
    pub fn into_inner(self) -> (Box<Read + Send>, Option<usize>) {
        (self.data, self.data_length)
    }

    /// Builds a `ResponseBody` that doesn't return any data.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::ResponseBody;
    /// let body = ResponseBody::empty();
    /// ```
    #[inline]
    pub fn empty() -> ResponseBody {
        ResponseBody {
            data: Box::new(io::empty()),
            data_length: Some(0),
        }
    }

    /// Builds a new `ResponseBody` that will read the data from a `Read`.
    ///
    /// Note that this is suboptimal compared to other constructors because the length
    /// isn't known in advance.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use std::io;
    /// use std::io::Read;
    /// use rouille::ResponseBody;
    ///
    /// let body = ResponseBody::from_reader(io::stdin().take(128));
    /// ```
    #[inline]
    pub fn from_reader<R>(data: R) -> ResponseBody where R: Read + Send + 'static {
        ResponseBody {
            data: Box::new(data),
            data_length: None,
        }
    }

    /// Builds a new `ResponseBody` that returns the given data.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::ResponseBody;
    /// let body = ResponseBody::from_data(vec![12u8, 97, 34]);
    /// ```
    #[inline]
    pub fn from_data<D>(data: D) -> ResponseBody where D: Into<Vec<u8>> {
        let data = data.into();
        let len = data.len();

        ResponseBody {
            data: Box::new(Cursor::new(data)),
            data_length: Some(len),
        }
    }

    /// Builds a new `ResponseBody` that returns the content of the given file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use std::fs::File;
    /// use rouille::ResponseBody;
    ///
    /// let file = File::open("page.html").unwrap();
    /// let body = ResponseBody::from_file(file);
    /// ```
    #[inline]
    pub fn from_file(file: File) -> ResponseBody {
        let len = file.metadata().map(|metadata| metadata.len() as usize).ok();

        ResponseBody {
            data: Box::new(file),
            data_length: len,
        }
    }

    /// Builds a new `ResponseBody` that returns an UTF-8 string.
    ///
    /// # Example
    ///
    /// ```
    /// use rouille::ResponseBody;
    /// let body = ResponseBody::from_string("hello world");
    /// ```
    #[inline]
    pub fn from_string<S>(data: S) -> ResponseBody where S: Into<String> {
        ResponseBody::from_data(data.into().into_bytes())
    }
}
<|endoftext|>


<commit_before>//! Defines types and traits related to transposition tables.

use std::cmp::min;
use moves::{Move, MoveDigest};
use value::*;
use depth::*;
use search_node::SearchNode;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// For the majority of chess positions our evaluations will be more
/// or less inaccurate, and there is nothing we can do about it. But
/// sometimes we know that a given evaluation is probably inaccurate,
/// and we know the sign of the error. `BoundType` defines the
/// direction of such **known inaccuracies**.
///
/// # Constants:
///
/// * `BOUND_EXACT` means that the evaluation is exact (as far as we know).
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation (as far as we know).
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation (as far as we know).
///
/// * `BOUND_NONE` means that the real value can be anything.
pub type BoundType = u8;

pub const BOUND_NONE: BoundType = 0;
pub const BOUND_LOWER: BoundType = 0b01;
pub const BOUND_UPPER: BoundType = 0b10;
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// A trait for transposition tables.
///
/// Chess programs, during their brute-force search, encounter the
/// same positions again and again, but from different sequences of
/// moves, which is called a "transposition". When the search
/// encounters a transposition, it is beneficial to "remember" what
/// was determined last time the position was examined, rather than
/// redoing the entire search again. For this reason, chess programs
/// have a transposition table, which is a large hash table storing
/// information about positions previously searched, how deeply they
/// were searched, and what we concluded about them. To implement your
/// own transposition table, you must define a type that implements
/// the `HashTable` trait.
pub trait HashTable: Sync + Send {
    type Entry: HashTableEntry;

    /// Creates a new transposition table.
    ///
    /// `size_mb` is the desired size in Mbytes.
    fn new(size_mb: Option<usize>) -> Self;

    /// Signals that a new search is about to begin.
    fn new_search(&self);

    /// Stores data by key.
    ///
    /// After being stored, the data can be retrieved by `probe`. This
    /// is not guaranteed though, because the entry might have been
    /// overwritten in the meantime.
    fn store(&self, key: u64, data: Self::Entry);

    /// Probes for data by key.
    fn probe(&self, key: u64) -> Option<Self::Entry>;

    /// Removes all entries in the table.
    fn clear(&self);

    /// Extracts the principal variation for a given position.
    ///
    /// The principal variation (PV) is the sequence of moves that the
    /// engine considers best and therefore expects to be played.
    fn extract_pv<T: SearchNode>(&self, position: &T) -> Variation {
        let mut p = position.clone();
        let mut our_turn = true;
        let mut moves = Vec::with_capacity(32);
        let mut root_value = VALUE_UNKNOWN;
        let mut value = VALUE_MAX;
        let mut bound = BOUND_UPPER;
        let mut depth = DEPTH_MAX + 1;

        'move_extraction: while let Some(e) = self.probe(p.hash()) {
            depth = min(depth - 1, e.depth());

            if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
                // In half of the cases the value is from other side's perspective.
                if our_turn {
                    value = e.value();
                    bound = e.bound();
                } else {
                    value = -e.value();
                    bound = match e.bound() {
                        BOUND_UPPER => BOUND_LOWER,
                        BOUND_LOWER => BOUND_UPPER,
                        b => b,
                    };
                }
                assert!(value != VALUE_UNKNOWN);

                // Set the root value on the first iteration.
                if root_value == VALUE_UNKNOWN {
                    root_value = value;
                }

                // Consider adding current entry's hash move to the
                // PV. There are 2 conditions for this:
                //
                // 1) The depth limit has not been reached yet.
                // 2) The value has not diverged from the root value.
                if depth > 0 &&
                   match root_value {
                    v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                    v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                    v => v == value,
                } {
                    // Verify that the hash move is legal.
                    if let Some(m) = p.try_move_digest(e.move_digest()) {
                        if p.do_move(m) {
                            moves.push(m);

                            // Note: we continue expanding the PV only on best moves.
                            if e.bound() == BOUND_EXACT {
                                our_turn = !our_turn;
                                continue 'move_extraction;
                            }
                        }
                    }
                }
            }
            break 'move_extraction;
        }

        Variation {
            value: if root_value != VALUE_UNKNOWN {
                root_value
            } else {
                value
            },
            bound: bound,
            moves: moves,
        }
    }
}

/// A trait for transposition table entries.
pub trait HashTableEntry: Copy + Send {
    /// Creates a new instance.
    ///
    /// * `value` -- The value assigned to the position. Must be
    ///   between `VALUE_MIN` and `VALUE_MAX`.
    ///
    /// * `bound` -- The accuracy of the assigned value.
    ///
    /// * `depth` -- The search depth for the assigned value. Must be
    ///   between `DEPTH_MIN` and `DEPTH_MAX`.
    ///
    /// * `move_digest` -- Best or refutation move digest, or
    ///   `MoveDigest::invalid()` if no move is available.
    fn new(value: Value, bound: BoundType, depth: Depth, move_digest: MoveDigest) -> Self;

    /// Creates a new instance.
    ///
    /// The only difference between this function and `new` is that
    /// this function requires one additional parameter:
    ///
    /// * `static_eval` -- Position's static evaluation, or
    ///   `VALUE_UNKNOWN`.
    fn with_static_eval(value: Value,
                        bound: BoundType,
                        depth: Depth,
                        move_digest: MoveDigest,
                        static_eval: Value)
                        -> Self {
        let mut entry = Self::new(value, bound, depth, move_digest);
        entry.set_static_eval(static_eval);
        entry
    }

    /// Returns the value assigned to the position.
    fn value(&self) -> Value;

    /// Sets the value assigned to the position.
    fn set_value(&mut self, value: Value);

    /// Returns the accuracy of the assigned value.
    fn bound(&self) -> BoundType;

    /// Sets the accuracy of the assigned value.
    fn set_bound(&mut self, bound: BoundType);

    /// Returns the search depth for the assigned value.
    fn depth(&self) -> Depth;

    /// Sets the search depth for the assigned value.
    fn set_depth(&mut self, depth: Depth);

    /// Returns best or refutation move digest, or
    /// `MoveDigest::invalid()` if no move is available.
    fn move_digest(&self) -> MoveDigest;

    /// Sets best or refutation move digest.
    fn set_move_digest(&mut self, move_digest: MoveDigest);

    /// Returns position's static evaluation, or `VALUE_UNKNOWN`.
    fn static_eval(&self) -> Value;

    /// Sets position's static evaluation.
    ///
    /// **Important note:** This method does nothing if the underlying
    /// memory structure has no field allotted for static evaluation.
    fn set_static_eval(&mut self, static_eval: Value);

    /// Returns the relative importance of the entry.
    ///
    /// Transposition tables may use this method to improve their
    /// record replacement strategy. Normally, when possible, entries
    /// with lower `importance` will be replaced before entries with
    /// higher `importance`. Therefore this method should try to
    /// return higher values for entries that are move likely to save
    /// CPU work in the future. For example, positions analyzed to a
    /// higher depth are probably more "important" than those analyzed
    /// to a lower depth.
    #[inline]
    fn importance(&self) -> i16 {
        let depth = self.depth() as i16;
        match self.bound() {
            BOUND_EXACT => depth + 1,
            BOUND_NONE => DEPTH_MIN as i16 - 1,
            _ => depth,
        }
    }
}

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
#[derive(Clone, Debug)]
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}
<commit_msg>provide default implementations for static_eval and set_static_eval<commit_after>//! Defines types and traits related to transposition tables.

use std::cmp::min;
use moves::{Move, MoveDigest};
use value::*;
use depth::*;
use search_node::SearchNode;

/// `BOUND_EXACT`, `BOUND_LOWER`, `BOUND_UPPER`, or `BOUND_NONE`.
///
/// For the majority of chess positions our evaluations will be more
/// or less inaccurate, and there is nothing we can do about it. But
/// sometimes we know that a given evaluation is probably inaccurate,
/// and we know the sign of the error. `BoundType` defines the
/// direction of such **known inaccuracies**.
///
/// # Constants:
///
/// * `BOUND_EXACT` means that the evaluation is exact (as far as we know).
///
/// * `BOUND_LOWER` means that the real value is greater or equal to
///    the evaluation (as far as we know).
///
/// * `BOUND_UPPER` means that the real value is lesser or equal to
///   the evaluation (as far as we know).
///
/// * `BOUND_NONE` means that the real value can be anything.
pub type BoundType = u8;

pub const BOUND_NONE: BoundType = 0;
pub const BOUND_LOWER: BoundType = 0b01;
pub const BOUND_UPPER: BoundType = 0b10;
pub const BOUND_EXACT: BoundType = BOUND_UPPER | BOUND_LOWER;

/// A trait for transposition tables.
///
/// Chess programs, during their brute-force search, encounter the
/// same positions again and again, but from different sequences of
/// moves, which is called a "transposition". When the search
/// encounters a transposition, it is beneficial to "remember" what
/// was determined last time the position was examined, rather than
/// redoing the entire search again. For this reason, chess programs
/// have a transposition table, which is a large hash table storing
/// information about positions previously searched, how deeply they
/// were searched, and what we concluded about them. To implement your
/// own transposition table, you must define a type that implements
/// the `HashTable` trait.
pub trait HashTable: Sync + Send {
    type Entry: HashTableEntry;

    /// Creates a new transposition table.
    ///
    /// `size_mb` is the desired size in Mbytes.
    fn new(size_mb: Option<usize>) -> Self;

    /// Signals that a new search is about to begin.
    fn new_search(&self);

    /// Stores data by key.
    ///
    /// After being stored, the data can be retrieved by `probe`. This
    /// is not guaranteed though, because the entry might have been
    /// overwritten in the meantime.
    fn store(&self, key: u64, data: Self::Entry);

    /// Probes for data by key.
    fn probe(&self, key: u64) -> Option<Self::Entry>;

    /// Removes all entries in the table.
    fn clear(&self);

    /// Extracts the principal variation for a given position.
    ///
    /// The principal variation (PV) is the sequence of moves that the
    /// engine considers best and therefore expects to be played.
    fn extract_pv<T: SearchNode>(&self, position: &T) -> Variation {
        let mut p = position.clone();
        let mut our_turn = true;
        let mut moves = Vec::with_capacity(32);
        let mut root_value = VALUE_UNKNOWN;
        let mut value = VALUE_MAX;
        let mut bound = BOUND_UPPER;
        let mut depth = DEPTH_MAX + 1;

        'move_extraction: while let Some(e) = self.probe(p.hash()) {
            depth = min(depth - 1, e.depth());

            if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
                // In half of the cases the value is from other side's perspective.
                if our_turn {
                    value = e.value();
                    bound = e.bound();
                } else {
                    value = -e.value();
                    bound = match e.bound() {
                        BOUND_UPPER => BOUND_LOWER,
                        BOUND_LOWER => BOUND_UPPER,
                        b => b,
                    };
                }
                assert!(value != VALUE_UNKNOWN);

                // Set the root value on the first iteration.
                if root_value == VALUE_UNKNOWN {
                    root_value = value;
                }

                // Consider adding current entry's hash move to the
                // PV. There are 2 conditions for this:
                //
                // 1) The depth limit has not been reached yet.
                // 2) The value has not diverged from the root value.
                if depth > 0 &&
                   match root_value {
                    v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                    v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                    v => v == value,
                } {
                    // Verify that the hash move is legal.
                    if let Some(m) = p.try_move_digest(e.move_digest()) {
                        if p.do_move(m) {
                            moves.push(m);

                            // Note: we continue expanding the PV only on best moves.
                            if e.bound() == BOUND_EXACT {
                                our_turn = !our_turn;
                                continue 'move_extraction;
                            }
                        }
                    }
                }
            }
            break 'move_extraction;
        }

        Variation {
            value: if root_value != VALUE_UNKNOWN {
                root_value
            } else {
                value
            },
            bound: bound,
            moves: moves,
        }
    }
}

/// A trait for transposition table entries.
pub trait HashTableEntry: Copy + Send {
    /// Creates a new instance.
    ///
    /// * `value` -- The value assigned to the position. Must be
    ///   between `VALUE_MIN` and `VALUE_MAX`.
    ///
    /// * `bound` -- The accuracy of the assigned value.
    ///
    /// * `depth` -- The search depth for the assigned value. Must be
    ///   between `DEPTH_MIN` and `DEPTH_MAX`.
    ///
    /// * `move_digest` -- Best or refutation move digest, or
    ///   `MoveDigest::invalid()` if no move is available.
    fn new(value: Value, bound: BoundType, depth: Depth, move_digest: MoveDigest) -> Self;

    /// Creates a new instance.
    ///
    /// The only difference between this function and `new` is that
    /// this function requires one additional parameter:
    ///
    /// * `static_eval` -- Position's static evaluation, or
    ///   `VALUE_UNKNOWN`.
    ///
    /// **Important note:** `static_eval` will be ignored if the
    /// underlying memory structure has no field allotted for static
    /// evaluation.
    fn with_static_eval(value: Value,
                        bound: BoundType,
                        depth: Depth,
                        move_digest: MoveDigest,
                        static_eval: Value)
                        -> Self {
        let mut entry = Self::new(value, bound, depth, move_digest);
        entry.set_static_eval(static_eval);
        entry
    }

    /// Returns the value assigned to the position.
    fn value(&self) -> Value;

    /// Sets the value assigned to the position.
    fn set_value(&mut self, value: Value);

    /// Returns the accuracy of the assigned value.
    fn bound(&self) -> BoundType;

    /// Sets the accuracy of the assigned value.
    fn set_bound(&mut self, bound: BoundType);

    /// Returns the search depth for the assigned value.
    fn depth(&self) -> Depth;

    /// Sets the search depth for the assigned value.
    fn set_depth(&mut self, depth: Depth);

    /// Returns best or refutation move digest, or
    /// `MoveDigest::invalid()` if no move is available.
    fn move_digest(&self) -> MoveDigest;

    /// Sets best or refutation move digest.
    fn set_move_digest(&mut self, move_digest: MoveDigest);

    /// Returns position's static evaluation, or `VALUE_UNKNOWN`.
    fn static_eval(&self) -> Value {
        VALUE_UNKNOWN
    }

    /// Sets position's static evaluation.
    ///
    /// **Important note:** This method will do nothing if the
    /// underlying memory structure has no field allotted for static
    /// evaluation.
    #[allow(unused_variables)]
    fn set_static_eval(&mut self, static_eval: Value) {}

    /// Returns the relative importance of the entry.
    ///
    /// Transposition tables may use this method to improve their
    /// record replacement strategy. Normally, when possible, entries
    /// with lower `importance` will be replaced before entries with
    /// higher `importance`. Therefore this method should try to
    /// return higher values for entries that are move likely to save
    /// CPU work in the future. For example, positions analyzed to a
    /// higher depth are probably more "important" than those analyzed
    /// to a lower depth.
    #[inline]
    fn importance(&self) -> i16 {
        let depth = self.depth() as i16;
        match self.bound() {
            BOUND_EXACT => depth + 1,
            BOUND_NONE => DEPTH_MIN as i16 - 1,
            _ => depth,
        }
    }
}

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
#[derive(Clone, Debug)]
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}
<|endoftext|>


<commit_before>extern crate regex;

use regex::Regex;
use std::collections::HashSet;
use std::io::{self, Write};

use super::{Compile, Name, ParseError, Path, Statement, Template};
use self::runtime::RUNTIME;

mod runtime;

/// A program is the final result of Mustache AST to Ruby extension source
/// translation that is presented to the main compiler driver for output.
///
/// It contains all external rendering functions generated by the translator,
/// which are exposed to Ruby code after the extension is compiled.
#[derive(Debug)]
pub struct Program {
    global: Scope,
}

impl Program {
    fn new() -> Self {
        Program { global: Scope::new(Name::new("global")) }
    }

    fn merge(&mut self, scope: Scope) -> &mut Self {
        self.global.merge(scope);
        self
    }
}

impl Compile for Program {
    /// Writes the final translated source code to an output buffer.
    ///
    /// This emits fully-formed Ruby extension source code that may be input
    /// into a mkmf build process, creating a dynamically loadable shared
    /// object file.
    fn emit(&self, buf: &mut Write) -> io::Result<()> {
        // Emit runtime preamble.
        writeln!(buf, "{}", RUNTIME)?;

        // Emit string content declarations.
        for string in &self.global.strings {
            writeln!(buf, "{};", string.decl)?;
        }

        writeln!(buf, "")?;

        // Emit function declarations.
        for fun in &self.global.functions {
            writeln!(buf, "{};", fun.decl)?;
        }

        writeln!(buf, "")?;

        // Emit function definitions.
        for fun in &self.global.functions {
            fun.emit(buf)?
        }

        // Emit public render function.
        let renders: Vec<_> = self.global.functions.iter().filter_map(|f| f.invoke_if()).collect();
        writeln!(buf,
                 r#"static VALUE render(VALUE self, VALUE name, VALUE context) {{
                        const char *ptr = StringValuePtr(name);
                        const long length = RSTRING_LEN(name);
                        VALUE buf = rb_str_buf_new(0);
                        VALUE stack = rb_ary_new_from_args(1, context);
                        {}
                        else {{
                            rb_raise(rb_eArgError, "Template not found");
                        }}
                        return buf;
                    }}"#,
                 renders.join(" else "))?;

        // Emit initialize function.
        writeln!(buf, "static void initialize() {{")?;
        for string in &self.global.strings {
            string.emit(buf)?;
        }
        writeln!(buf, "}}")
    }
}

/// A store for functions created by the translation process of an input
/// template to source code output.
///
/// Scopes have name generators that are used in function naming, providing a
/// stable name that other scopes may rely on for partial template function
/// calls.
///
/// After each template is translated into a scope they are merged into a
/// Program's global scope for final output.
#[derive(Debug)]
struct Scope {
    name: Name,
    functions: Vec<Function>,
    strings: Vec<StaticString>,
}

impl Scope {
    fn new(name: Name) -> Self {
        Scope {
            name: name,
            functions: Vec::new(),
            strings: Vec::new(),
        }
    }

    /// Combines this scope's function definitions with another's.
    fn merge(&mut self, mut other: Scope) -> &mut Self {
        self.functions.append(&mut other.functions);
        self.strings.append(&mut other.strings);
        self
    }

    /// Advances the scope's name generator to the next unique identifier. This
    /// should be called before descending another level in the recursive
    /// tree translation process.
    fn next(&mut self) -> &mut Self {
        self.name.next();
        self
    }

    /// Adds a function to this scope.
    fn register(&mut self, fun: Function) {
        self.functions.push(fun);
    }

    /// Adds a constant string value to this scope.
    fn content(&mut self, string: StaticString) {
        self.strings.push(string);
    }

    /// Returns the template path used to generate function names in this
    /// scope (e.g. "includes/header").
    fn base_name(&self) -> String {
        self.name.base.clone()
    }
}

#[derive(Debug)]
struct StaticString {
    name: String,
    decl: String,
    value: String,
    length: usize,
}

impl StaticString {
    /// Writes the raw content string global to the buffer.
    fn emit(&self, buf: &mut Write) -> io::Result<()> {
        writeln!(buf, "{{")?;
        writeln!(buf, "static const char* content = \"{}\";", self.value)?;
        writeln!(buf,
                 "{} = rb_str_new_static(content, {});",
                 self.name,
                 self.length)?;
        writeln!(buf, "rb_global_variable(&{});", self.name)?;
        writeln!(buf, "}}")
    }
}

#[derive(Debug)]
struct Function {
    name: String,
    decl: String,
    body: Vec<String>,
    export: Option<String>,
}

impl Function {
    /// Writes the function definition to the buffer.
    fn emit(&self, buf: &mut Write) -> io::Result<()> {
        writeln!(buf, "{} {{", self.decl)?;
        for node in &self.body {
            writeln!(buf, "{}", node)?;
        }
        writeln!(buf, "}}\n")
    }

    /// Builds a conditional statement to call the function if the template
    /// name matches the function's exported name, like "includes/header".
    fn invoke_if(&self) -> Option<String> {
        if self.export.is_none() {
            return None;
        }

        let export = self.export.as_ref().unwrap();
        Some(format!("if (length == {len} && strncmp(ptr, \"{path}\", {len}) == 0) {{
                          {fun}(buf, stack);
                      }}",
                     len = export.len(),
                     path = export,
                     fun = self.name))
    }
}

/// Recursively walks the AST, translating Mustache statement tree nodes into
/// the corresponding Ruby extension source code.
///
/// Sections are extracted into top-level functions paired with a function
/// call at the location the section appeared in the template. Partials are
/// similarly translated into a function call which is expected to be provided
/// by another template in the final tree.
fn transform(scope: &mut Scope, node: &Statement) -> Option<String> {
    match *node {
        Statement::Program(ref block) => {
            let id = scope.name.id();

            // Build private render function.
            let children = block.statements
                .iter()
                .filter_map(|stmt| transform(scope.next(), stmt))
                .collect();

            let render = Function {
                name: format!("render_{}", id),
                decl: format!("static void render_{}(VALUE buf, VALUE stack)", id),
                body: children,
                export: Some(scope.base_name()),
            };

            scope.register(render);
            None
        }
        Statement::Section(ref path, ref block) => {
            let children = block.statements
                .iter()
                .filter_map(|stmt| transform(scope.next(), stmt))
                .collect();

            let fun = Function {
                name: format!("section_{}", scope.name),
                decl: format!("static void section_{}(VALUE buf, VALUE stack)", scope.name),
                body: children,
                export: None,
            };

            let call = format!("{{ {} section(buf, stack, &path, {}); }}",
                               path_ary(path),
                               fun.name);

            scope.register(fun);
            Some(call)
        }
        Statement::Inverted(ref path, ref block) => {
            let children = block.statements
                .iter()
                .filter_map(|stmt| transform(scope.next(), stmt))
                .collect();

            let fun = Function {
                name: format!("section_{}", scope.name),
                decl: format!("static void section_{}(VALUE buf, VALUE stack)", scope.name),
                body: children,
                export: None,
            };

            let call = format!("{{ {} inverted(buf, stack, &path, {}); }}",
                               path_ary(path),
                               fun.name);

            scope.register(fun);
            Some(call)
        }
        Statement::Partial(ref name, ref padding) => {
            let name = Name::new(name);
            Some(format!("render_{}(buf, stack);", name.id()))
        }
        Statement::Comment(_) => None,
        Statement::Content(ref text) => {
            let content = clean(text);

            let name = format!("content_{}", scope.next().name);
            let string = StaticString {
                decl: format!("static VALUE {}", name),
                name: name,
                value: content,
                length: text.len(),
            };

            let append = format!("rb_str_buf_append(buf, {});", string.name);

            scope.content(string);
            Some(append)
        }
        Statement::Variable(ref path) => {
            let path = path_ary(path);
            Some(format!("{{ {} append_value(buf, stack, &path, true); }}", path))
        }
        Statement::Html(ref path) => {
            let path = path_ary(path);
            Some(format!("{{ {} append_value(buf, stack, &path, false); }}", path))
        }
    }
}

/// Transforms the AST of each parsed template into a source code tree
/// and links each template together into a single executable program.
pub fn link(templates: &Vec<Template>) -> Result<Program, ParseError> {
    validate(templates)?;

    let mut program = Program::new();
    templates.iter()
        .map(|template| {
            let mut scope = Scope::new(template.name());
            transform(&mut scope, &template.tree);
            scope
        })
        .fold(&mut program, |program, scope| program.merge(scope));

    Ok(program)
}

/// Ensures all templates may be linked together into an executable.
///
/// This method checks that all partial template paths are provided by
/// another template. For example, a `{{>include/header}}` partial invocation
/// must be provided by an `include/header.mustache` template file.
///
/// Partials can be considered function calls, so the function must be defined.
fn validate(templates: &Vec<Template>) -> Result<(), ParseError> {
    let all: HashSet<_> = templates.iter().map(|temp| &temp.name).collect();

    for template in templates {
        let names: HashSet<_> = template.tree.partials().into_iter().collect();
        let missing = &names - &all;
        if !missing.is_empty() {
            let name = missing.into_iter().next().unwrap();
            return Err(ParseError::UnknownPartial(name.clone(), template.path.clone()));
        }
    }

    Ok(())
}

/// Replaces string literal characters considered invalid inside a cstr with
/// their escaped counterparts.
fn clean(text: &str) -> String {
    let re = Regex::new(r"\\").unwrap();
    let text = re.replace_all(&text, "\\\\");

    let re = Regex::new(r"\r").unwrap();
    let text = re.replace_all(&text, "\\r");

    let re = Regex::new(r"\n").unwrap();
    let text = re.replace_all(&text, "\\n");

    let re = Regex::new(r#"["]"#).unwrap();
    re.replace_all(&text, "\\\"").into_owned()
}

/// Transforms a Mustache variable key path into the source code to build a
/// Ruby array. At runtime, each key in the array is recursively processed to
/// find the replacement text for a Mustache expression.
fn path_ary(path: &Path) -> String {
    let args = path.keys
        .iter()
        .map(|key| format!("\"{}\"", key))
        .collect::<Vec<String>>()
        .join(", ");

    format!("static const struct path path = {{ .keys = {{ {} }}, .length = {} }};",
            args,
            path.keys.len())
}

#[cfg(test)]
mod tests {
    use super::{link, transform, Scope};
    use super::super::{Name, ParseError, Statement, Template};
    use std::path::{Path, PathBuf};

    #[test]
    fn validates_valid_partial_reference() {
        let base = PathBuf::from("app/templates");
        let path = PathBuf::from("app/templates/machines/robots.mustache");
        let tree = Statement::Partial(String::from("machines/robot"), None);
        let master = Template::new(&base, path, tree);

        let path = PathBuf::from("app/templates/machines/robot.mustache");
        let tree = Statement::Content(String::from("hubot"));
        let detail = Template::new(&base, path, tree);

        let templates = vec![master, detail];
        match link(&templates) {
            Ok(_) => (),
            Err(e) => panic!("Must link valid partials: {}", e),
        }
    }

    #[test]
    fn validates_invalid_partial_reference() {
        let base = PathBuf::from("app/templates");
        let path = PathBuf::from("app/templates/machines/robots.mustache");
        let tree = Statement::Partial(String::from("machines/unknown"), None);

        let master = Template::new(&base, path, tree);

        let path = PathBuf::from("app/templates/machines/robot.mustache");
        let tree = Statement::Content(String::from("hubot"));
        let detail = Template::new(&base, path, tree);

        let templates = vec![master, detail];
        match link(&templates) {
            Err(ParseError::UnknownPartial(ref name, ref path)) => {
                assert_eq!("machines/unknown", name);
                assert_eq!(Path::new("app/templates/machines/robots.mustache"), path);
            }
            _ => panic!("Must enforce partial references"),
        }
    }

    #[test]
    fn transforms_tree_into_functions() {
        let text = "
            {{> includes/header }}

                {{# robots}}

{{ name.first }}

                {{/ robots}}
                {{^ robots}}
                    {{! else clause }}
                    No robots
                {{/ robots}}

            {{> includes/footer }}
            {{{ unescaped.html }}}
        ";

        match Statement::parse(text) {
            Ok(tree) => {
                let mut scope = Scope::new(Name::new("machines/robot"));
                transform(&mut scope, &tree);

                // One for each section, private render, and exported template function.
                let names: Vec<_> = scope.functions.iter().map(|fun| &fun.name).collect();
                assert_eq!(vec!["section_machines_robot11",
                                "section_machines_robot15",
                                "render_machines_robot"],
                           names);

                // Single exported function name.
                let exports: Vec<_> =
                    scope.functions.iter().filter_map(|fun| fun.export.as_ref()).collect();
                assert_eq!(vec!["machines/robot"], exports);
            }
            Err(e) => panic!("Failed to parse tree: {}", e),
        }
    }
}
<commit_msg>Increment scope name for section block function<commit_after>extern crate regex;

use regex::Regex;
use std::collections::HashSet;
use std::io::{self, Write};

use super::{Compile, Name, ParseError, Path, Statement, Template};
use self::runtime::RUNTIME;

mod runtime;

/// A program is the final result of Mustache AST to Ruby extension source
/// translation that is presented to the main compiler driver for output.
///
/// It contains all external rendering functions generated by the translator,
/// which are exposed to Ruby code after the extension is compiled.
#[derive(Debug)]
pub struct Program {
    global: Scope,
}

impl Program {
    fn new() -> Self {
        Program { global: Scope::new(Name::new("global")) }
    }

    fn merge(&mut self, scope: Scope) -> &mut Self {
        self.global.merge(scope);
        self
    }
}

impl Compile for Program {
    /// Writes the final translated source code to an output buffer.
    ///
    /// This emits fully-formed Ruby extension source code that may be input
    /// into a mkmf build process, creating a dynamically loadable shared
    /// object file.
    fn emit(&self, buf: &mut Write) -> io::Result<()> {
        // Emit runtime preamble.
        writeln!(buf, "{}", RUNTIME)?;

        // Emit string content declarations.
        for string in &self.global.strings {
            writeln!(buf, "{};", string.decl)?;
        }

        writeln!(buf, "")?;

        // Emit function declarations.
        for fun in &self.global.functions {
            writeln!(buf, "{};", fun.decl)?;
        }

        writeln!(buf, "")?;

        // Emit function definitions.
        for fun in &self.global.functions {
            fun.emit(buf)?
        }

        // Emit public render function.
        let renders: Vec<_> = self.global.functions.iter().filter_map(|f| f.invoke_if()).collect();
        writeln!(buf,
                 r#"static VALUE render(VALUE self, VALUE name, VALUE context) {{
                        const char *ptr = StringValuePtr(name);
                        const long length = RSTRING_LEN(name);
                        VALUE buf = rb_str_buf_new(0);
                        VALUE stack = rb_ary_new_from_args(1, context);
                        {}
                        else {{
                            rb_raise(rb_eArgError, "Template not found");
                        }}
                        return buf;
                    }}"#,
                 renders.join(" else "))?;

        writeln!(buf, "")?;

        // Emit initialize function.
        writeln!(buf, "static void initialize() {{")?;
        for string in &self.global.strings {
            string.emit(buf)?;
        }
        writeln!(buf, "}}")
    }
}

/// A store for functions created by the translation process of an input
/// template to source code output.
///
/// Scopes have name generators that are used in function naming, providing a
/// stable name that other scopes may rely on for partial template function
/// calls.
///
/// After each template is translated into a scope they are merged into a
/// Program's global scope for final output.
#[derive(Debug)]
struct Scope {
    name: Name,
    functions: Vec<Function>,
    strings: Vec<StaticString>,
}

impl Scope {
    fn new(name: Name) -> Self {
        Scope {
            name: name,
            functions: Vec::new(),
            strings: Vec::new(),
        }
    }

    /// Combines this scope's function definitions with another's.
    fn merge(&mut self, mut other: Scope) -> &mut Self {
        self.functions.append(&mut other.functions);
        self.strings.append(&mut other.strings);
        self
    }

    /// Advances the scope's name generator to the next unique identifier. This
    /// should be called before descending another level in the recursive
    /// tree translation process.
    fn next(&mut self) -> &mut Self {
        self.name.next();
        self
    }

    /// Adds a function to this scope.
    fn register(&mut self, fun: Function) {
        self.functions.push(fun);
    }

    /// Adds a constant string value to this scope.
    fn content(&mut self, string: StaticString) {
        self.strings.push(string);
    }

    /// Returns the template path used to generate function names in this
    /// scope (e.g. "includes/header").
    fn base_name(&self) -> String {
        self.name.base.clone()
    }
}

#[derive(Debug)]
struct StaticString {
    name: String,
    decl: String,
    value: String,
    length: usize,
}

impl StaticString {
    /// Writes the raw content string global to the buffer.
    fn emit(&self, buf: &mut Write) -> io::Result<()> {
        writeln!(buf, "{{")?;
        writeln!(buf, "static const char* content = \"{}\";", self.value)?;
        writeln!(buf,
                 "{} = rb_str_new_static(content, {});",
                 self.name,
                 self.length)?;
        writeln!(buf, "rb_global_variable(&{});", self.name)?;
        writeln!(buf, "}}")
    }
}

#[derive(Debug)]
struct Function {
    name: String,
    decl: String,
    body: Vec<String>,
    export: Option<String>,
}

impl Function {
    /// Writes the function definition to the buffer.
    fn emit(&self, buf: &mut Write) -> io::Result<()> {
        writeln!(buf, "{} {{", self.decl)?;
        for node in &self.body {
            writeln!(buf, "{}", node)?;
        }
        writeln!(buf, "}}\n")
    }

    /// Builds a conditional statement to call the function if the template
    /// name matches the function's exported name, like "includes/header".
    fn invoke_if(&self) -> Option<String> {
        if self.export.is_none() {
            return None;
        }

        let export = self.export.as_ref().unwrap();
        Some(format!("if (length == {len} && strncmp(ptr, \"{path}\", {len}) == 0) {{
                          {fun}(buf, stack);
                      }}",
                     len = export.len(),
                     path = export,
                     fun = self.name))
    }
}

/// Recursively walks the AST, translating Mustache statement tree nodes into
/// the corresponding Ruby extension source code.
///
/// Sections are extracted into top-level functions paired with a function
/// call at the location the section appeared in the template. Partials are
/// similarly translated into a function call which is expected to be provided
/// by another template in the final tree.
fn transform(scope: &mut Scope, node: &Statement) -> Option<String> {
    match *node {
        Statement::Program(ref block) => {
            let id = scope.name.id();

            // Build private render function.
            let children = block.statements
                .iter()
                .filter_map(|stmt| transform(scope.next(), stmt))
                .collect();

            let render = Function {
                name: format!("render_{}", id),
                decl: format!("static void render_{}(VALUE buf, VALUE stack)", id),
                body: children,
                export: Some(scope.base_name()),
            };

            scope.register(render);
            None
        }
        Statement::Section(ref path, ref block) => {
            let children = block.statements
                .iter()
                .filter_map(|stmt| transform(scope.next(), stmt))
                .collect();

            let name = format!("section_{}", scope.next().name);
            let fun = Function {
                decl: format!("static void {}(VALUE buf, VALUE stack)", name),
                name: name,
                body: children,
                export: None,
            };

            let call = format!("{{ {} section(buf, stack, &path, {}); }}",
                               path_ary(path),
                               fun.name);

            scope.register(fun);
            Some(call)
        }
        Statement::Inverted(ref path, ref block) => {
            let children = block.statements
                .iter()
                .filter_map(|stmt| transform(scope.next(), stmt))
                .collect();

            let name = format!("section_{}", scope.next().name);
            let fun = Function {
                decl: format!("static void {}(VALUE buf, VALUE stack)", name),
                name: name,
                body: children,
                export: None,
            };

            let call = format!("{{ {} inverted(buf, stack, &path, {}); }}",
                               path_ary(path),
                               fun.name);

            scope.register(fun);
            Some(call)
        }
        Statement::Partial(ref name, ref padding) => {
            let name = Name::new(name);
            Some(format!("render_{}(buf, stack);", name.id()))
        }
        Statement::Comment(_) => None,
        Statement::Content(ref text) => {
            let content = clean(text);

            let name = format!("content_{}", scope.next().name);
            let string = StaticString {
                decl: format!("static VALUE {}", name),
                name: name,
                value: content,
                length: text.len(),
            };

            let append = format!("rb_str_buf_append(buf, {});", string.name);

            scope.content(string);
            Some(append)
        }
        Statement::Variable(ref path) => {
            let path = path_ary(path);
            Some(format!("{{ {} append_value(buf, stack, &path, true); }}", path))
        }
        Statement::Html(ref path) => {
            let path = path_ary(path);
            Some(format!("{{ {} append_value(buf, stack, &path, false); }}", path))
        }
    }
}

/// Transforms the AST of each parsed template into a source code tree
/// and links each template together into a single executable program.
pub fn link(templates: &Vec<Template>) -> Result<Program, ParseError> {
    validate(templates)?;

    let mut program = Program::new();
    templates.iter()
        .map(|template| {
            let mut scope = Scope::new(template.name());
            transform(&mut scope, &template.tree);
            scope
        })
        .fold(&mut program, |program, scope| program.merge(scope));

    Ok(program)
}

/// Ensures all templates may be linked together into an executable.
///
/// This method checks that all partial template paths are provided by
/// another template. For example, a `{{>include/header}}` partial invocation
/// must be provided by an `include/header.mustache` template file.
///
/// Partials can be considered function calls, so the function must be defined.
fn validate(templates: &Vec<Template>) -> Result<(), ParseError> {
    let all: HashSet<_> = templates.iter().map(|temp| &temp.name).collect();

    for template in templates {
        let names: HashSet<_> = template.tree.partials().into_iter().collect();
        let missing = &names - &all;
        if !missing.is_empty() {
            let name = missing.into_iter().next().unwrap();
            return Err(ParseError::UnknownPartial(name.clone(), template.path.clone()));
        }
    }

    Ok(())
}

/// Replaces string literal characters considered invalid inside a cstr with
/// their escaped counterparts.
fn clean(text: &str) -> String {
    let re = Regex::new(r"\\").unwrap();
    let text = re.replace_all(&text, "\\\\");

    let re = Regex::new(r"\r").unwrap();
    let text = re.replace_all(&text, "\\r");

    let re = Regex::new(r"\n").unwrap();
    let text = re.replace_all(&text, "\\n");

    let re = Regex::new(r#"["]"#).unwrap();
    re.replace_all(&text, "\\\"").into_owned()
}

/// Transforms a Mustache variable key path into the source code to build a
/// Ruby array. At runtime, each key in the array is recursively processed to
/// find the replacement text for a Mustache expression.
fn path_ary(path: &Path) -> String {
    let args = path.keys
        .iter()
        .map(|key| format!("\"{}\"", key))
        .collect::<Vec<String>>()
        .join(", ");

    format!("static const struct path path = {{ .keys = {{ {} }}, .length = {} }};",
            args,
            path.keys.len())
}

#[cfg(test)]
mod tests {
    use super::{link, transform, Scope};
    use super::super::{Name, ParseError, Statement, Template};
    use std::path::{Path, PathBuf};

    #[test]
    fn validates_valid_partial_reference() {
        let base = PathBuf::from("app/templates");
        let path = PathBuf::from("app/templates/machines/robots.mustache");
        let tree = Statement::Partial(String::from("machines/robot"), None);
        let master = Template::new(&base, path, tree);

        let path = PathBuf::from("app/templates/machines/robot.mustache");
        let tree = Statement::Content(String::from("hubot"));
        let detail = Template::new(&base, path, tree);

        let templates = vec![master, detail];
        match link(&templates) {
            Ok(_) => (),
            Err(e) => panic!("Must link valid partials: {}", e),
        }
    }

    #[test]
    fn validates_invalid_partial_reference() {
        let base = PathBuf::from("app/templates");
        let path = PathBuf::from("app/templates/machines/robots.mustache");
        let tree = Statement::Partial(String::from("machines/unknown"), None);

        let master = Template::new(&base, path, tree);

        let path = PathBuf::from("app/templates/machines/robot.mustache");
        let tree = Statement::Content(String::from("hubot"));
        let detail = Template::new(&base, path, tree);

        let templates = vec![master, detail];
        match link(&templates) {
            Err(ParseError::UnknownPartial(ref name, ref path)) => {
                assert_eq!("machines/unknown", name);
                assert_eq!(Path::new("app/templates/machines/robots.mustache"), path);
            }
            _ => panic!("Must enforce partial references"),
        }
    }

    #[test]
    fn transforms_tree_into_functions() {
        let text = "
            {{> includes/header }}

                {{# robots}}

{{ name.first }}

                {{/ robots}}
                {{^ robots}}
                    {{! else clause }}
                    No robots
                {{/ robots}}

            {{> includes/footer }}
            {{{ unescaped.html }}}
        ";

        match Statement::parse(text) {
            Ok(tree) => {
                let mut scope = Scope::new(Name::new("machines/robot"));
                transform(&mut scope, &tree);

                // One for each section, private render, and exported template function.
                let names: Vec<_> = scope.functions.iter().map(|fun| &fun.name).collect();
                assert_eq!(vec!["section_machines_robot12",
                                "section_machines_robot17",
                                "render_machines_robot"],
                           names);

                // Single exported function name.
                let exports: Vec<_> =
                    scope.functions.iter().filter_map(|fun| fun.export.as_ref()).collect();
                assert_eq!(vec!["machines/robot"], exports);
            }
            Err(e) => panic!("Failed to parse tree: {}", e),
        }
    }
}
<|endoftext|>