<commit_before>//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any
//!   combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file,
//!   and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need
//!   them!
//! - Thread-local logger storage. This allows for convenient debug/info/warning/severe!() and
//!   log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to
//! change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new(config.log_file.as_slice())`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```
//! #[feature(phase)]
//!
//! // ...
//!
//! #[phase(plugin)]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows:
//!
//! ```
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     // Initialize the logger for this worker thread.
//!     fern::local::set_thread_logger(logger_arc.clone());
//!
//!     // Do other calculations, and log more here as well.
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use errors::Error;
pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

#[unstable]
pub mod local;
mod api;
mod config;
mod loggers;
mod errors;
<commit_msg>Update documentation so that it isn't run with `cargo test` - so it builds with latest nightly.<commit_after>//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any
//!   combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file,
//!   and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need
//!   them!
//! - Thread-local logger storage. This allows for convenient debug/info/warning/severe!() and
//!   log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to
//! change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```no_test
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```text
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new(config.log_file.as_slice())`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```no_test
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```no_test
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```no_test
//! #[macro_use]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows:
//!
//! ```no_test
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     // Initialize the logger for this worker thread.
//!     fern::local::set_thread_logger(logger_arc.clone());
//!
//!     // Do other calculations, and log more here as well.
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use errors::Error;
pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

#[unstable]
pub mod local;
mod api;
mod config;
mod loggers;
mod errors;
<|endoftext|>


<commit_before>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write, Error, ErrorKind};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll, Async};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

pub struct Packet {
    pub bytes: Vec<u8>
}

pub enum Action {
    Forward,                // forward the packet unmodified
    Mutate(Packet),         // mutate the packet
    Respond(Vec<Packet>)    // handle directly and optionally return some packets
}

pub trait PacketHandler {
    fn handle_request(&self, p: &Packet) -> Action;
    fn handle_response(&self, p: &Packet) -> Action;
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve<H: PacketHandler + 'static>(self, conn: TcpStream,
                                             handler: H,
                                        ) -> Box<Future<Item = (u64, u64), Error = Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        let pair = connected.and_then(move |server| Ok((conn,server)));

        Box::new(pair.and_then(move |(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);
            Pipe::new(c1, c2, handler)
        }))
    }
}

#[derive(Debug)]
enum Direction {
    Client,
    Server
}

struct ConnReader {
    direction: Direction,
    stream: Rc<TcpStream>,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_amt: u64,
}

struct ConnWriter {
    direction: Direction,
    stream: Rc<TcpStream>,
    write_buf: Vec<u8>,
    write_pos: usize,
    write_amt: u64,
}

impl ConnReader {

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnReader {
            stream: stream,
            direction: direction,
            read_buf: vec![0u8; 4096],
            read_pos: 0,
            read_amt: 0,
        }
    }

    fn read(&mut self) -> Poll<Option<Packet>, io::Error> {
        println!("{:?} read()", self.direction);
        loop {

            // see if there is a packet already in the buffer
            if let Some(p) = self.parse_packet() {
                println!("{:?} read() returning Ready(packet)", self.direction);
                return Ok(Async::Ready(Some(p)))
            }

            println!("{:?} Calling poll_read(), read_pos={}", self.direction, self.read_pos);

            // try reading more data
            try_ready!(self.stream.poll_read());

            println!("{:?} After poll_read()", self.direction);

            println!("{:?} Before try_nb()", self.direction);

            //TODO: ensure capacity first
            let n = try_nb!((&*self.stream).read(&mut self.read_buf[self.read_pos..]));
            if n == 0 {
                println!("{:?} Detected connection closed", self.direction);
                return Err(Error::new(ErrorKind::Other, "connection closed"));
            }
            println!("{:?} read() read {} bytes", self.direction, n);
            self.read_amt += n as u64;
            self.read_pos += n;

            if let Some(p) = self.parse_packet() {
                println!("{:?} read() returning Ready(packet)", self.direction);
                return Ok(Async::Ready(Some(p)))
            } else {
                println!("{:?} read() returning Ready(None)", self.direction);
                return Ok(Async::Ready(None))
            }
        }
    }

    fn parse_packet(&mut self) -> Option<Packet> {
        // do we have a header
        if self.read_pos > 3 {
            let l = parse_packet_length(&self.read_buf);
            // do we have the whole packet?
            let s = 4 + l;
            if self.read_pos >= s {

                //TODO: clean up this hack
                let mut temp : Vec<u8> = vec![];
                temp.extend_from_slice( &self.read_buf[0..s]);
                let p = Packet { bytes: temp };

                // remove this packet from the buffer
                //TODO: must be more efficient way to do this
                for _ in 0..s {
                    self.read_buf.remove(0);
                }
                self.read_pos -= s;

                println!("{:?} parse_packet(): read_pos={}, returning packet:", self.direction, self.read_pos);
                print_packet_bytes(&p.bytes);
                print_packet_chars(&p.bytes);

                Some(p)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl ConnWriter{

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnWriter{
            stream: stream,
            direction: direction,
            write_buf: vec![0u8; 4096],
            write_pos: 0,
            write_amt: 0
        }
    }

    /// Write a packet to the write buffer
    fn push(&mut self, p: &Packet) {
        self.write_buf.truncate(self.write_pos);
        self.write_buf.extend_from_slice(&p.bytes);
        self.write_pos += p.bytes.len();
        println!("{:?} extended write buffer by {} bytes", self.direction, p.bytes.len());
    }

    /// Writes the contents of the write buffer to the socket
    fn write(&mut self) -> Poll<(), io::Error> {
        println!("{:?} write()", self.direction);
        while self.write_pos > 0 {
            try_ready!(self.stream.poll_write());
            let m = try!((&*self.stream).write(&self.write_buf[0..self.write_pos]));
            println!("{:?} Wrote {} bytes", self.direction, m);
            // remove this packet from the buffer
            //TODO: must be more efficient way to do this
            for _ in 0..m {
                self.write_buf.remove(0);
            }
            self.write_pos -= m;
        }
        return Ok(Async::Ready(()));
    }
}

struct Pipe<H: PacketHandler + 'static> {
    client_reader: ConnReader,
    client_writer: ConnWriter,
    server_reader: ConnReader,
    server_writer: ConnWriter,
    handler: H,
}

impl<H> Pipe<H> where H: PacketHandler + 'static {
    fn new(client: Rc<TcpStream>,
           server: Rc<TcpStream>,
           handler: H
           ) -> Pipe<H> {

        Pipe {
            client_reader: ConnReader::new(client.clone(), Direction::Client),
            client_writer: ConnWriter::new(client, Direction::Client),
            server_reader: ConnReader::new(server.clone(), Direction::Server),
            server_writer: ConnWriter::new(server, Direction::Server),
            handler: handler,
        }
    }
}

impl<H> Future for Pipe<H> where H: PacketHandler + 'static {
    type Item = (u64, u64);
    type Error = Error;

    fn poll(&mut self) -> Poll<(u64, u64), io::Error> {
        println!("poll()");

        loop {
            // try reading from client
            println!("CLIENT READ");
            let client_read = match self.client_reader.read() {
                Ok(Async::Ready(None)) => Ok(Async::Ready(())),
                Ok(Async::Ready(Some(p))) => {
                    match self.handler.handle_request(&p) {
                        Action::Forward => self.server_writer.push(&p),
                        Action::Mutate(ref p2) => self.server_writer.push(p2),
                        Action::Respond(ref v) => {
                            for p in v {
                                self.client_writer.push(&p);
                            }
                        }
                    };
                    Ok(Async::Ready(()))
                },
                Ok(Async::NotReady) => Ok(Async::NotReady),
                Err(e) => {
                    //try!(self.server_writer.stream.shutdown(Shutdown::Write));
                    Err(e)
                }
            };

            // try writing to server
            println!("SERVER WRITE");
            let server_write = self.server_writer.write();

            // try reading from server
            println!("SERVER READ");
            let server_read = match self.server_reader.read() {
                Ok(Async::Ready(None)) => Ok(Async::Ready(())),
                Ok(Async::Ready(Some(p))) => {
                    match self.handler.handle_response(&p) {
                        Action::Forward => self.client_writer.push(&p),
                        Action::Mutate(ref p2) => self.client_writer.push(p2),
                        Action::Respond(ref v) => {
                            for p in v {
                                self.server_writer.push(&p);
                            }
                        }
                    };
                    Ok(Async::Ready(()))
                },
                Ok(Async::NotReady) => Ok(Async::NotReady),
                Err(e) => {
                    //try!(self.client_writer.stream.shutdown(Shutdown::Write));
                    Err(e)
                }
            };

            // try writing to client
            println!("CLIENT WRITE");
            let client_write = self.client_writer.write();

            println!("client_read = {:?}", client_read);
            println!("client_write = {:?}", client_write);
            println!("server_read = {:?}", server_read);
            println!("server_write = {:?}", server_write);

            try_ready!(client_read);
            try_ready!(client_write);
            try_ready!(server_read);
            try_ready!(server_write);
        }

    }

}

#[allow(dead_code)]
pub fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
pub fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<commit_msg>bug fix: read until tokio reports NotReady<commit_after>//! MySQL Proxy Server

#[macro_use]
extern crate log;
extern crate env_logger;
#[macro_use]
extern crate futures;
#[macro_use]
extern crate tokio_core;
extern crate futures_cpupool;

use std::cell::RefCell;
use std::rc::Rc;
use std::env;
use std::io::{self, Read, Write, Error, ErrorKind};
use std::net::{SocketAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
use std::net::Shutdown;
use std::str;
use std::time::Duration;

use futures::{Future, Poll, Async};
use futures::stream::Stream;
use futures_cpupool::CpuPool;
use tokio_core::{Loop, LoopHandle, TcpStream};
use tokio_core::io::{read_exact, write_all, Window};

pub struct Packet {
    pub bytes: Vec<u8>
}

pub enum Action {
    Forward,                // forward the packet unmodified
    Mutate(Packet),         // mutate the packet
    Respond(Vec<Packet>)    // handle directly and optionally return some packets
}

pub trait PacketHandler {
    fn handle_request(&self, p: &Packet) -> Action;
    fn handle_response(&self, p: &Packet) -> Action;
}

fn parse_packet_length(header: &[u8]) -> usize {
    (((header[2] as u32) << 16) |
    ((header[1] as u32) << 8) |
    header[0] as u32) as usize
}

pub struct Client {
    pub pool: CpuPool,
    pub handle: LoopHandle,
}

impl Client {

    pub fn serve<H: PacketHandler + 'static>(self, conn: TcpStream,
                                             handler: H,
                                        ) -> Box<Future<Item = (u64, u64), Error = Error>> {

        let addr = Ipv4Addr::new(127, 0, 0, 1);
        let port = 3306;
        let addr = SocketAddr::V4(SocketAddrV4::new(addr, port));

        let handle = self.handle.clone();
        let connected = handle.tcp_connect(&addr);

        let pair = connected.and_then(move |server| Ok((conn,server)));

        Box::new(pair.and_then(move |(c1, c2)| {
            let c1 = Rc::new(c1);
            let c2 = Rc::new(c2);
            Pipe::new(c1, c2, handler)
        }))
    }
}

#[derive(Debug)]
enum Direction {
    Client,
    Server
}

struct ConnReader {
    direction: Direction,
    stream: Rc<TcpStream>,
    read_buf: Vec<u8>,
    read_pos: usize,
    read_amt: u64,
}

struct ConnWriter {
    direction: Direction,
    stream: Rc<TcpStream>,
    write_buf: Vec<u8>,
    write_pos: usize,
    write_amt: u64,
}

impl ConnReader {

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnReader {
            stream: stream,
            direction: direction,
            read_buf: vec![0u8; 4096],
            read_pos: 0,
            read_amt: 0,
        }
    }

    /// Read from the socket until the status is NotReady
    fn read(&mut self) -> Poll<(), io::Error> {
        println!("{:?} read()", self.direction);
        loop {
            println!("{:?} before poll_read()", self.direction);
            try_ready!(self.stream.poll_read());
            println!("{:?} before try_nb()", self.direction);
            //TODO: ensure capacity first
            let n = try_nb!((&*self.stream).read(&mut self.read_buf[self.read_pos..]));
            if n == 0 {
                println!("{:?} Detected connection closed", self.direction);
                return Err(Error::new(ErrorKind::Other, "connection closed"));
            }
            println!("{:?} read() read {} bytes", self.direction, n);
            self.read_amt += n as u64;
            self.read_pos += n;
        }
    }

    fn next(&mut self) -> Option<Packet> {
        // do we have a header
        if self.read_pos > 3 {
            let l = parse_packet_length(&self.read_buf);
            // do we have the whole packet?
            let s = 4 + l;
            if self.read_pos >= s {

                //TODO: clean up this hack
                let mut temp : Vec<u8> = vec![];
                temp.extend_from_slice( &self.read_buf[0..s]);
                let p = Packet { bytes: temp };

                // remove this packet from the buffer
                //TODO: must be more efficient way to do this
                for _ in 0..s {
                    self.read_buf.remove(0);
                }
                self.read_pos -= s;

                println!("{:?} parse_packet(): read_pos={}, returning packet:", self.direction, self.read_pos);
                print_packet_bytes(&p.bytes);
                print_packet_chars(&p.bytes);

                Some(p)
            } else {
                None
            }
        } else {
            None
        }
    }
}

impl ConnWriter{

    fn new(stream: Rc<TcpStream>, direction: Direction) -> Self {
        ConnWriter{
            stream: stream,
            direction: direction,
            write_buf: vec![0u8; 4096],
            write_pos: 0,
            write_amt: 0
        }
    }

    /// Write a packet to the write buffer
    fn push(&mut self, p: &Packet) {
        self.write_buf.truncate(self.write_pos);
        self.write_buf.extend_from_slice(&p.bytes);
        self.write_pos += p.bytes.len();
        println!("{:?} extended write buffer by {} bytes", self.direction, p.bytes.len());
    }

    /// Writes the contents of the write buffer to the socket
    fn write(&mut self) -> Poll<(), io::Error> {
        println!("{:?} write()", self.direction);
        while self.write_pos > 0 {
            try_ready!(self.stream.poll_write());
            let m = try!((&*self.stream).write(&self.write_buf[0..self.write_pos]));
            println!("{:?} Wrote {} bytes", self.direction, m);
            // remove this packet from the buffer
            //TODO: must be more efficient way to do this
            for _ in 0..m {
                self.write_buf.remove(0);
            }
            self.write_pos -= m;
        }
        return Ok(Async::Ready(()));
    }
}

struct Pipe<H: PacketHandler + 'static> {
    client_reader: ConnReader,
    client_writer: ConnWriter,
    server_reader: ConnReader,
    server_writer: ConnWriter,
    handler: H,
}

impl<H> Pipe<H> where H: PacketHandler + 'static {
    fn new(client: Rc<TcpStream>,
           server: Rc<TcpStream>,
           handler: H
           ) -> Pipe<H> {

        Pipe {
            client_reader: ConnReader::new(client.clone(), Direction::Client),
            client_writer: ConnWriter::new(client, Direction::Client),
            server_reader: ConnReader::new(server.clone(), Direction::Server),
            server_writer: ConnWriter::new(server, Direction::Server),
            handler: handler,
        }
    }
}

impl<H> Future for Pipe<H> where H: PacketHandler + 'static {
    type Item = (u64, u64);
    type Error = Error;

    fn poll(&mut self) -> Poll<(u64, u64), io::Error> {
        println!("poll()");

        loop {
            // try reading from client
            println!("CLIENT READ");
            let client_read = self.client_reader.read();

            // process buffered requests
            while let Some(request) = self.client_reader.next() {
                match self.handler.handle_request(&request) {
                    Action::Forward => self.server_writer.push(&request),
                    Action::Mutate(ref p2) => self.server_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.client_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to server
            println!("SERVER WRITE");
            let server_write = self.server_writer.write();

            // try reading from server
            println!("SERVER READ");
            let server_read = self.server_reader.read();

            // process buffered responses
            while let Some(response) = self.server_reader.next() {
                match self.handler.handle_response(&response) {
                    Action::Forward => self.client_writer.push(&response),
                    Action::Mutate(ref p2) => self.client_writer.push(p2),
                    Action::Respond(ref v) => {
                        for p in v {
                            self.server_writer.push(&p);
                        }
                    }
                };
            }

            // try writing to client
            println!("CLIENT WRITE");
            let client_write = self.client_writer.write();

            println!("client_read = {:?}", client_read);
            println!("client_write = {:?}", client_write);
            println!("server_read = {:?}", server_read);
            println!("server_write = {:?}", server_write);

            try_ready!(client_read);
            try_ready!(client_write);
            try_ready!(server_read);
            try_ready!(server_write);
        }

    }

}

#[allow(dead_code)]
pub fn print_packet_chars(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        print!("{} ", buf[i] as char);
    }
    println!("]");
}

#[allow(dead_code)]
pub fn print_packet_bytes(buf: &[u8]) {
    print!("[");
    for i in 0..buf.len() {
        if i%8==0 { println!(""); }
        print!("{:#04x} ",buf[i]);
    }
    println!("]");
}

<|endoftext|>


<commit_before>#[cfg(not(test))]
extern crate libc;

#[cfg(not(test))]
use std::fs::OpenOptions;
#[cfg(not(test))]
use std::fs::File;

#[cfg(test)]
use mocks::{File, OpenOptions};

use std::fmt;
use std::os::unix::prelude::*;
use std::io;
use std::path::PathBuf;
use libc::{c_int, ioctl};

const LOOP_PREFIX: &'static str = "/dev/loop";

#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    pub fn open(dev_file: &str) -> io::Result<LoopControl> {
        Ok(LoopControl { dev_file: try!(OpenOptions::new().read(true).write(true).open(dev_file)) })
    }

    // Finds and returns the next availble loop device
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result: i32;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, 0x4C82);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            let path = LOOP_PREFIX.to_string() + &result.to_string();
            Ok(LoopDevice {
                device_name: PathBuf::from(path.clone()),
                device: try!(OpenOptions::new()
                                 .read(true)
                                 .write(true)
                                 .open(path)),
                backing_file: None,
            })
        }
    }
}

#[derive(Debug)]
pub struct LoopDevice {
    device_name: PathBuf,
    device: File,
    backing_file: Option<File>,
}

impl LoopDevice {
    // Attach a loop device to a file.
    #[allow(unused_variables)]
    pub fn attach(&self, backing_file: File) -> io::Result<()> {
        Ok(())
    }

    // Detach a loop device from its backing file.
    pub fn detach(&self) -> io::Result<()> {
        Ok(())
    }
}

impl fmt::Display for LoopDevice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.device_name.display())
    }
}

#[cfg(test)]
mod mocks {
    use std::io;
    use std::path::Path;
    use libc::c_int;
    use std::os::unix::prelude::AsRawFd;

    pub type RawFd = c_int;

    #[derive(Debug)]
    pub struct File {
        fd: RawFd,
        read: bool,
        write: bool,
    }

    impl File {
        pub fn new(fd: RawFd, read: bool, write: bool) -> File {
            File {
                fd: fd,
                read: read,
                write: write,
            }
        }
    }

    impl AsRawFd for File {
        fn as_raw_fd(&self) -> RawFd {
            self.fd
        }
    }

    pub struct OpenOptions {
        read: bool,
        write: bool,
    }

    impl OpenOptions {
        pub fn new() -> OpenOptions {
            OpenOptions {
                read: false,
                write: false,
            }
        }

        pub fn read(&mut self, en: bool) -> &mut OpenOptions {
            self.read = en;
            self
        }

        pub fn write(&mut self, en: bool) -> &mut OpenOptions {
            self.write = en;
            self
        }

        #[allow(unused_variables)]
        pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
            if path.as_ref().to_str().unwrap() == "/dev/null" {
                Err(io::Error::new(io::ErrorKind::PermissionDenied,
                                   "/dev/loop-control: Operation not permitted"))
            } else {
                Ok(File {
                    fd: 3,
                    read: self.read,
                    write: self.write,
                })
            }
        }
    }

}

#[cfg(test)]
mod libc {
    extern crate libc as real_libc;
    extern crate errno;

    use std::cell::RefCell;
    pub use self::real_libc::{c_int, c_ulong};

    thread_local!(static RETURN_VALUE: RefCell<c_int> = RefCell::new(0));

    // pub fn set_return_value(value: c_int) {
    //     RETURN_VALUE.with(|v| {
    //         *v.borrow_mut() = value;
    //     })
    // }
    //
    fn get_return_value() -> c_int {
        RETURN_VALUE.with(|v| {
            if *v.borrow() < 0 {
                errno::set_errno(errno::Errno(-*v.borrow()));
            }
            *v.borrow()
        })
    }

    #[allow(unused_variables)]
    pub unsafe extern "C" fn ioctl(fd: c_int, request: c_ulong) -> c_int {
        get_return_value()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use mocks::File;

    macro_rules! lc_open {
        ( $name:ident, $i:expr, $r:expr ) => {
            #[test]
            fn $name() {
                assert_eq!(format!("{:?}", LoopControl::open($i).unwrap()), format!("{:?}", $r));
            }
        };
    }
    lc_open!(lc_open_0,
             "/dev/loop-control",
             LoopControl { dev_file: File::new(3, true, true) });

    // TODO get error tests working
    // lc_open!(lc_open_err,
    //          "/dev/null",
    //          LoopControl { dev_file: File::new(3, true, true) });

    // macro_rules! lc_next_free {
    //     ( $name:ident, $inp:expr, $out:expr, $exp:expr ) => {
    //         #[test]
    //         fn $name() {
    //             libc::set_return_value($out);
    //             let lc = LoopControl { fd: $inp };
    //             assert_eq!(lc.next_free(), $exp);
    //         }
    //     };
    // }
    //
    // lc_next_free!(lc_next_free_0,
    //               0,
    //               0,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop0")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_1,
    //               1,
    //               1,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop1")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_2,
    //               2,
    //               2,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop2")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_3,
    //               5,
    //               5,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop5")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_4,
    //               10,
    //               10,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop10")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_5,
    //               54,
    //               54,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop54")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_7,
    //               128,
    //               128,
    //               Ok(LoopDevice {
    //                   device: PathBuf::from(String::from("/dev/loop128")),
    //                   backing_file: None,
    //                   device_fd: None,
    //                   backing_file_fd: None,
    //               }));
    // lc_next_free!(lc_next_free_err_1,
    //               123,
    //               -1,
    //               Err(String::from("Operation not permitted")));
    // lc_next_free!(lc_next_free_err_2,
    //               123,
    //               -2,
    //               Err(String::from("No such file or directory")));
    // lc_next_free!(lc_next_free_err_3,
    //               123,
    //               -3,
    //               Err(String::from("No such process")));
    // #[test]
    // #[should_panic(expected = "assertion failed")]
    // #[allow(unused_must_use)]
    // fn ln_next_free_panic() {
    //     libc::set_return_value(-1);
    //     let lc = LoopControl { fd: -1 };
    //     lc.next_free();
    // }
}
<commit_msg>Refactors tests to work with the code refactor<commit_after>#[cfg(not(test))]
extern crate libc;

#[cfg(not(test))]
use std::fs::OpenOptions;
#[cfg(not(test))]
use std::fs::File;

#[cfg(test)]
use mocks::{File, OpenOptions};

use std::fmt;
use std::os::unix::prelude::*;
use std::io;
use std::path::PathBuf;
use libc::{c_int, ioctl};

const LOOP_PREFIX: &'static str = "/dev/loop";

#[derive(Debug)]
pub struct LoopControl {
    dev_file: File,
}

impl LoopControl {
    pub fn open(dev_file: &str) -> io::Result<LoopControl> {
        Ok(LoopControl { dev_file: try!(OpenOptions::new().read(true).write(true).open(dev_file)) })
    }

    // Finds and returns the next availble loop device
    pub fn next_free(&self) -> io::Result<LoopDevice> {
        let result: i32;
        unsafe {
            result = ioctl(self.dev_file.as_raw_fd() as c_int, 0x4C82);
        }
        if result < 0 {
            Err(io::Error::last_os_error())
        } else {
            let path = LOOP_PREFIX.to_string() + &result.to_string();
            Ok(LoopDevice {
                device_name: PathBuf::from(path.clone()),
                device: try!(OpenOptions::new()
                                 .read(true)
                                 .write(true)
                                 .open(path)),
                backing_file: None,
            })
        }
    }
}

#[derive(Debug)]
pub struct LoopDevice {
    device_name: PathBuf,
    device: File,
    backing_file: Option<File>,
}

impl LoopDevice {
    // Attach a loop device to a file.
    #[allow(unused_variables)]
    pub fn attach(&self, backing_file: File) -> io::Result<()> {
        Ok(())
    }

    // Detach a loop device from its backing file.
    pub fn detach(&self) -> io::Result<()> {
        Ok(())
    }
}

impl fmt::Display for LoopDevice {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.device_name.display())
    }
}

#[cfg(test)]
mod mocks {
    use std::io;
    use std::path::Path;
    use libc::c_int;
    use std::os::unix::prelude::AsRawFd;

    pub type RawFd = c_int;

    #[derive(Debug)]
    pub struct File {
        fd: RawFd,
        read: bool,
        write: bool,
    }

    impl File {
        pub fn new(fd: RawFd, read: bool, write: bool) -> File {
            File {
                fd: fd,
                read: read,
                write: write,
            }
        }
    }

    impl AsRawFd for File {
        fn as_raw_fd(&self) -> RawFd {
            self.fd
        }
    }

    pub struct OpenOptions {
        read: bool,
        write: bool,
    }

    impl OpenOptions {
        pub fn new() -> OpenOptions {
            OpenOptions {
                read: false,
                write: false,
            }
        }

        pub fn read(&mut self, en: bool) -> &mut OpenOptions {
            self.read = en;
            self
        }

        pub fn write(&mut self, en: bool) -> &mut OpenOptions {
            self.write = en;
            self
        }

        #[allow(unused_variables)]
        pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
            if path.as_ref().to_str().unwrap() == "/dev/null" {
                Err(io::Error::new(io::ErrorKind::PermissionDenied,
                                   "/dev/null: Operation not permitted"))
            } else {
                Ok(File {
                    fd: 3,
                    read: self.read,
                    write: self.write,
                })
            }
        }
    }

}

#[cfg(test)]
mod libc {
    extern crate libc as real_libc;
    extern crate errno;

    use std::cell::RefCell;
    pub use self::real_libc::{c_int, c_ulong};

    thread_local!(static RETURN_VALUE: RefCell<c_int> = RefCell::new(0));

    pub fn set_return_value(value: c_int) {
        RETURN_VALUE.with(|v| {
            *v.borrow_mut() = value;
        })
    }

    fn get_return_value() -> c_int {
        RETURN_VALUE.with(|v| {
            if *v.borrow() < 0 {
                errno::set_errno(errno::Errno(-*v.borrow()));
            }
            *v.borrow()
        })
    }

    #[allow(unused_variables)]
    pub unsafe extern "C" fn ioctl(fd: c_int, request: c_ulong) -> c_int {
        get_return_value()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use mocks::File;
    use std::io;
    use libc;
    use std::path::PathBuf;

    macro_rules! lc_open {
        ( $name:ident, $i:expr, $r:expr ) => {
            #[test]
            fn $name() {
                let r: io::Result<LoopControl> = $r;
                assert_eq!(format!("{:?}", LoopControl::open($i)), format!("{:?}", r));
            }
        };
    }
    lc_open!(lc_open_ok,
             "/dev/loop-control",
             Ok(LoopControl { dev_file: File::new(3, true, true) }));
    lc_open!(lc_open_err,
             "/dev/null",
             Err(io::Error::new(io::ErrorKind::PermissionDenied,
                                "/dev/null: Operation not permitted")));

    macro_rules! lc_next_free {
        ( $name:ident, $out:expr, $exp:expr ) => {
            #[test]
            fn $name() {
                libc::set_return_value($out);
                let lc = LoopControl { dev_file: File::new(3, true, true) };
                let exp: io::Result<LoopDevice> = $exp;
                assert_eq!(format!("{:?}", lc.next_free()), format!("{:?}", exp));
            }
        };
    }
    lc_next_free!(lc_next_free_0,
                  0,
                  Ok(LoopDevice {
                      device_name: PathBuf::from(String::from("/dev/loop0")),
                      device: File::new(3, true, true),
                      backing_file: None,
                  }));
    lc_next_free!(lc_next_free_1,
                  1,
                  Ok(LoopDevice {
                      device_name: PathBuf::from(String::from("/dev/loop1")),
                      device: File::new(3, true, true),
                      backing_file: None,
                  }));
    lc_next_free!(lc_next_free_2,
                  2,
                  Ok(LoopDevice {
                      device_name: PathBuf::from(String::from("/dev/loop2")),
                      device: File::new(3, true, true),
                      backing_file: None,
                  }));
    lc_next_free!(lc_next_free_10,
                  10,
                  Ok(LoopDevice {
                      device_name: PathBuf::from(String::from("/dev/loop10")),
                      device: File::new(3, true, true),
                      backing_file: None,
                  }));
    lc_next_free!(lc_next_free_99,
                  99,
                  Ok(LoopDevice {
                      device_name: PathBuf::from(String::from("/dev/loop99")),
                      device: File::new(3, true, true),
                      backing_file: None,
                  }));
    lc_next_free!(lc_next_free_100,
                  100,
                  Ok(LoopDevice {
                      device_name: PathBuf::from(String::from("/dev/loop100")),
                      device: File::new(3, true, true),
                      backing_file: None,
                  }));
    lc_next_free!(lc_next_free_err_1, -1, Err(io::Error::from_raw_os_error(1)));
    lc_next_free!(lc_next_free_err_2, -2, Err(io::Error::from_raw_os_error(2)));
    lc_next_free!(lc_next_free_err_3, -3, Err(io::Error::from_raw_os_error(3)));
}
<|endoftext|>


<commit_before>//! A probability-theory toolbox.

#![feature(phase, tuple_indexing)]

extern crate sfunc;

use std::rand::Rng;

pub mod distributions;

/// An interface for a probability distribution.
pub trait Distribution<T> {
    /// Compute the cumulative distribution function (CDF) at point `x`.
    fn cdf(&self, x: T) -> f64;

    /// Compute the inverse of the cumulative distribution function at
    /// probability `p`.
    fn inv_cdf(&self, p: f64) -> T;

    /// Draw a random sample.
    fn sample<R: Rng>(&self, rng: &mut R) -> T;
}

/// A means of drawing a sequence of samples from a probability distribution.
///
/// # Example
///
/// ```
/// use std::rand::task_rng;
/// use probability::Sampler;
/// use probability::distributions::Uniform;
///
/// let uniform = Uniform::new(0.0, 1.0);
/// let samples = Sampler(&uniform, &mut task_rng()).take(10).collect::<Vec<_>>();
/// ```
pub struct Sampler<D, R>(pub D, pub R);

impl<'a, T, D, R> Iterator<T> for Sampler<&'a D, &'a mut R>
    where D: Distribution<T>, R: Rng {

    #[inline]
    fn next(&mut self) -> Option<T> {
        Some(self.0.sample(self.1))
    }
}
<commit_msg>Removed a deprecation<commit_after>//! A probability-theory toolbox.

#![feature(phase)]

extern crate sfunc;

use std::rand::Rng;

pub mod distributions;

/// An interface for a probability distribution.
pub trait Distribution<T> {
    /// Compute the cumulative distribution function (CDF) at point `x`.
    fn cdf(&self, x: T) -> f64;

    /// Compute the inverse of the cumulative distribution function at
    /// probability `p`.
    fn inv_cdf(&self, p: f64) -> T;

    /// Draw a random sample.
    fn sample<R: Rng>(&self, rng: &mut R) -> T;
}

/// A means of drawing a sequence of samples from a probability distribution.
///
/// # Example
///
/// ```
/// use std::rand::task_rng;
/// use probability::Sampler;
/// use probability::distributions::Uniform;
///
/// let uniform = Uniform::new(0.0, 1.0);
/// let samples = Sampler(&uniform, &mut task_rng()).take(10).collect::<Vec<_>>();
/// ```
pub struct Sampler<D, R>(pub D, pub R);

impl<'a, T, D, R> Iterator<T> for Sampler<&'a D, &'a mut R>
    where D: Distribution<T>, R: Rng {

    #[inline]
    fn next(&mut self) -> Option<T> {
        Some(self.0.sample(self.1))
    }
}
<|endoftext|>


<commit_before>#[crate_id = "fragments#0.1-pre"];

#[comment = "A simple template library for Rust"];
#[license = "MIT"];
#[crate_type = "lib"];
#[crate_type = "rlib"];

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::BufReader;
use std::vec_ng::Vec;
use collections::hashmap::{HashMap, HashSet};

type ParserState = Option<fn(&mut Buffer) -> ParserResult>;

struct ParserResult {
	token: Token,
	next_parser: ParserState
}

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert(~"label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and just added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	content: ~HashMap<~str, ~fmt::Show>,
	///Conditional switches
	conditions: ~HashSet<~str>,
	priv tokens: Vec<Token>
}

impl Template {
	pub fn from_buffer(b: &mut Buffer) -> Template {
		Template {
			content: ~HashMap::new(),
			conditions: ~HashSet::new(),
			tokens: parse_block(b)
		}
	}

	///Convenience method for inserting content.
	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show);
	}

	///Convenience method for setting a condition.
	pub fn set(&mut self, condition: ~str, value: bool) {
		if value {
			self.conditions.insert(condition);
		} else {
			self.conditions.remove(&condition);
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

fn parse_block(b: &mut Buffer) -> Vec<Token> {
	let mut tokens = vec!();
	let mut parser = parse_string;

	loop {
		let ParserResult{token: token, next_parser: next} = parser(b);

		tokens.push(token);

		match next {
			Some(p) => parser = p,
			None => break
		}
	}

	tokens
}

fn parse_string(b: &mut Buffer) -> ParserResult {
	let mut content = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						content.push_char(c);
					},
					_ => break
				}
			},
			Ok('[') => {
				match b.read_char() {
					Ok('[') => {
						match b.read_char() {
							Ok(':') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_placeholder)
							},
							Ok('?') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_conditional)
							},
							Ok('/') => {
								skip_to_token_end(b);

								return ParserResult{
									token: String(content),
									next_parser: None
								}
							},
							_ => break
						}
					},
					Ok(c) => {
						content.push_char('[');
						content.push_char(c);
					},
					Err(_) => content.push_char('[')
				}
			},
			Ok(c) => content.push_char(c),
			Err(_) => break
		}
	}

	ParserResult{
		token: String(content),
		next_parser: None
	}
}

fn skip_to_token_end(b: &mut Buffer) {
	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(_) => {},
					_ => break
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => break,
					_ => {}
				}
			},
			Err(_) => break,
			_ => {}
		}
	}
}

fn parse_placeholder(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					_ => break
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Placeholder(label),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(_) => label.push_char(']')
				}
			},
			Ok(c) => label.push_char(c),
			Err(_) => break
		}
	}

	ParserResult{
		token: Placeholder(label),
		next_parser: None
	}
}

fn parse_conditional(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";
	let mut expected = true;
	let mut expected_set = false;

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					_ => break
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Conditional(label, expected, parse_block(b)),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(_) => label.push_char(']')
				}
			},
			Ok('!') => {
				if label.len() == 0 && !expected_set {
					expected = false;
					expected_set = true;
				} else {
					label.push_char('!');
				}
			},
			Ok(c) => {
				label.push_char(c)
			},
			Err(_) => break
		}
	}

	ParserResult{
		token: Conditional(label, expected, vec!()),
		next_parser: None
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! This is a "));
		assert_eq!(template.tokens.get(3), &Placeholder(~"something"));
		assert_eq!(template.tokens.get(4), &String(~" template."));
	}

	#[test]
	fn strange_tokens() {
		let template: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! Write placeholders like [[:this]] and escape them like \\[[:this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[:something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}

	#[test]
	fn conditional() {
		let mut template: Template = from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter!");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}

	#[test]
	fn conditional_switch() {
		let mut template: Template = from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is false.");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}
}<commit_msg>Template content and conditions are no longer stored in ~-pointers<commit_after>#[crate_id = "fragments#0.1-pre"];

#[comment = "A simple template library for Rust"];
#[license = "MIT"];
#[crate_type = "lib"];
#[crate_type = "rlib"];

extern crate collections;

use std::fmt;
use std::from_str::FromStr;
use std::io::BufReader;
use std::vec_ng::Vec;
use collections::hashmap::{HashMap, HashSet};

type ParserState = Option<fn(&mut Buffer) -> ParserResult>;

struct ParserResult {
	token: Token,
	next_parser: ParserState
}

#[deriving(Eq, TotalEq, Show)]
enum Token {
	String(~str),
	Placeholder(~str),
	Conditional(~str, bool, Vec<Token>)
}

///A string template with placeholders and conditional content.
///
///Placeholders are written as `[[:label]]`, where `label` becomes the name of the placeholder.
///The label is then used to insert content: `my_template.insert(~"label", my_content);`.
///The assigned content for a placeholder can be anything that implements `Show`.
///Even other templates may be inserted, which allows a more atomic structure.
///
///Conditional segments are surrounded by `[[?label]]...[[/]]`, where `label` becomes the name of the condition,
///and they are used to display content depending on whether its label exists in the `conditions` set.
///`[[/]]` marks the end of a block and may contain other characters after the `/`, which may be useful for labeling the end mark.
///Conditions can be made negative by writing `[[?!label]]...[[/]]`, which makes the content visible if the label
///is missing from the `conditions` set.
///
///Any character can be escaped by writing `\` before it. It can be used like this: `\[[[:label1]], [[:label2]]]`
///which will result in `[content1, content2]`, since the first `[` will be ignored by the parser and just added to the
///rest of the content.
pub struct Template {
	///Content for the placeholders
	content: HashMap<~str, ~fmt::Show>,
	///Conditional switches
	conditions: HashSet<~str>,
	priv tokens: Vec<Token>
}

impl Template {
	pub fn from_buffer(b: &mut Buffer) -> Template {
		Template {
			content: HashMap::new(),
			conditions: HashSet::new(),
			tokens: parse_block(b)
		}
	}

	///Convenience method for inserting content.
	pub fn insert<T: fmt::Show + Send>(&mut self, placeholder: ~str, item: ~T) {
		self.content.insert(placeholder, item as ~fmt::Show);
	}

	///Convenience method for setting a condition.
	pub fn set(&mut self, condition: ~str, value: bool) {
		if value {
			self.conditions.insert(condition);
		} else {
			self.conditions.remove(&condition);
		}
	}

	fn format_tokens(&self, tokens: &Vec<Token>, f: &mut fmt::Formatter) -> fmt::Result {
		for token in tokens.iter() {
			let res = match token {
				&String(ref s) => f.buf.write_str(*s),

				&Placeholder(ref k) => {
					match self.content.find(k) {
						Some(value) => value.fmt(f),
						None => Ok(())
					}
				},

				&Conditional(ref k, expected, ref tokens) => {
					if self.conditions.contains(k) == expected {
						self.format_tokens(tokens, f)
					} else {
						Ok(())
					}
				}
			};

			match res {
				Err(e) => return Err(e),
				_ => {}
			}
		}

		Ok(())
	}
}

impl FromStr for Template {
	///Creates a new `Template` from a string.
	fn from_str(s: &str) -> Option<Template> {
		Some(Template::from_buffer(&mut BufReader::new(s.as_bytes())))
	}
}

impl fmt::Show for Template {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		self.format_tokens(&self.tokens, f)
	}
}

fn parse_block(b: &mut Buffer) -> Vec<Token> {
	let mut tokens = vec!();
	let mut parser = parse_string;

	loop {
		let ParserResult{token: token, next_parser: next} = parser(b);

		tokens.push(token);

		match next {
			Some(p) => parser = p,
			None => break
		}
	}

	tokens
}

fn parse_string(b: &mut Buffer) -> ParserResult {
	let mut content = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						content.push_char(c);
					},
					_ => break
				}
			},
			Ok('[') => {
				match b.read_char() {
					Ok('[') => {
						match b.read_char() {
							Ok(':') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_placeholder)
							},
							Ok('?') => return ParserResult{
								token: String(content),
								next_parser: Some(parse_conditional)
							},
							Ok('/') => {
								skip_to_token_end(b);

								return ParserResult{
									token: String(content),
									next_parser: None
								}
							},
							_ => break
						}
					},
					Ok(c) => {
						content.push_char('[');
						content.push_char(c);
					},
					Err(_) => content.push_char('[')
				}
			},
			Ok(c) => content.push_char(c),
			Err(_) => break
		}
	}

	ParserResult{
		token: String(content),
		next_parser: None
	}
}

fn skip_to_token_end(b: &mut Buffer) {
	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(_) => {},
					_ => break
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => break,
					_ => {}
				}
			},
			Err(_) => break,
			_ => {}
		}
	}
}

fn parse_placeholder(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					_ => break
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Placeholder(label),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(_) => label.push_char(']')
				}
			},
			Ok(c) => label.push_char(c),
			Err(_) => break
		}
	}

	ParserResult{
		token: Placeholder(label),
		next_parser: None
	}
}

fn parse_conditional(b: &mut Buffer) -> ParserResult {
	let mut label = ~"";
	let mut expected = true;
	let mut expected_set = false;

	loop {
		match b.read_char() {
			Ok('\\') => {
				match b.read_char() {
					Ok(c) => {
						label.push_char(c);
					},
					_ => break
				}
			},
			Ok(']') => {
				match b.read_char() {
					Ok(']') => {
						return ParserResult{
							token: Conditional(label, expected, parse_block(b)),
							next_parser: Some(parse_string)
						}
					},
					Ok(c) => {
						label.push_char(']');
						label.push_char(c);
					},
					Err(_) => label.push_char(']')
				}
			},
			Ok('!') => {
				if label.len() == 0 && !expected_set {
					expected = false;
					expected_set = true;
				} else {
					label.push_char('!');
				}
			},
			Ok(c) => {
				label.push_char(c)
			},
			Err(_) => break
		}
	}

	ParserResult{
		token: Conditional(label, expected, vec!()),
		next_parser: None
	}
}

#[cfg(test)]
mod test {
	use super::{Template, Placeholder, String};

	#[test]
	fn basic_tokens() {
		let template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! This is a "));
		assert_eq!(template.tokens.get(3), &Placeholder(~"something"));
		assert_eq!(template.tokens.get(4), &String(~" template."));
	}

	#[test]
	fn strange_tokens() {
		let template: Template = from_str("Hello, [[[:name]]]! This is a [[[[:something]] template.").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
	}

	#[test]
	fn escaped_tokens() {
		let template: Template = from_str("Hello, [[:name]]! Write placeholders like \\[[:this]] and escape them like \\\\\\[[:this]]").unwrap();
		assert_eq!(template.tokens.get(0), &String(~"Hello, "));
		assert_eq!(template.tokens.get(1), &Placeholder(~"name"));
		assert_eq!(template.tokens.get(2), &String(~"! Write placeholders like [[:this]] and escape them like \\[[:this]]"));
	}

	#[test]
	fn replacement() {
		let mut template: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		template.insert(~"name", ~("Peter"));
		template.insert(~"something", ~("nice"));
		assert_eq!(template.to_str(), ~"Hello, Peter! This is a nice template.");
	}

	#[test]
	fn templates_in_templates() {
		let mut template1: Template = from_str("Hello, [[:name]]! This is a [[:something]] template.").unwrap();
		let mut template2: ~Template = ~from_str("really [[:something]]").unwrap();
		template1.insert(~"name", ~("Peter"));
		template2.insert(~"something", ~("nice"));

		template1.insert(~"something", template2);

		assert_eq!(template1.to_str(), ~"Hello, Peter! This is a really nice template.");
	}

	#[test]
	fn conditional() {
		let mut template: Template = from_str("Hello, [[:name]]![[?condition]] The condition is true.[[/condition]]").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter!");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}

	#[test]
	fn conditional_switch() {
		let mut template: Template = from_str("Hello, [[:name]]! The condition is [[?condition]]true[[/condition]][[?!condition]]false[[/condition]].").unwrap();
		template.insert(~"name", ~("Peter"));
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is false.");
		template.set(~"condition", true);
		assert_eq!(template.to_str(), ~"Hello, Peter! The condition is true.");
	}
}<|endoftext|>


<commit_before>//! Provides two types, `CBox` and `DisposeRef`
extern crate libc;
use libc::{malloc, free, c_char, c_void, size_t};
use std::borrow::Borrow;
use std::ffi::{CString, CStr};
use std::{fmt, mem, str};
use std::ops::{Deref, DerefMut, Drop};
use std::cmp::PartialEq;
use std::marker::PhantomData;
/// Implemented by any type of which its reference represents a C pointer that can be disposed.
pub trait DisposeRef {
    /// What a reference to this type represents as a C pointer.
    type RefTo;
    /// Destroy the contents at the pointer's location.
    ///
    /// This should run some variant of `libc::free(ptr)`
    unsafe fn dispose(ptr: *mut Self::RefTo) {
        free(ptr as *mut c_void);
    }
}

/// A wrapper for pointers made by C that are now owned in Rust.
///
/// This is necessary to allow owned and borrowed representations of C types
/// to be represented by the same type as they are in C with little overhead
pub struct CBox<'a, D:?Sized> where D:DisposeRef+'a {
    ptr: *mut D::RefTo,
    marker: PhantomData<&'a ()>
}
impl<'a, D:?Sized> CBox<'a, D> where D:DisposeRef+'a {
    #[inline(always)]
    /// Wrap the pointer in a `CBox`
    pub fn new(ptr: *mut D::RefTo) -> Self {
        CBox {
            ptr: ptr,
            marker: PhantomData
        }
    }
    #[inline(always)]
    /// Returns the internal pointer
    pub unsafe fn as_ptr(&self) -> *mut D::RefTo {
        self.ptr
    }
    #[inline(always)]
    /// Returns the internal pointer
    pub unsafe fn unwrap(self) -> *mut D::RefTo {
        let ptr = self.ptr;
        mem::forget(self);
        ptr
    }
}
impl<'a, D:?Sized> From<*mut D::RefTo> for CBox<'a, D> where D:DisposeRef+'a {
    #[inline(always)]
    fn from(ptr: *mut D::RefTo) -> Self {
        CBox::new(ptr)
    }
}
impl<'a, D:?Sized> Drop for CBox<'a, D> where D:DisposeRef+'a {
    #[inline(always)]
    /// Run the destructor
    fn drop(&mut self) {
        unsafe { <D as DisposeRef>::dispose(self.ptr) }
    }
}
impl<'a, D> Deref for CBox<'a, D> where D:DisposeRef+'a, *mut D::RefTo:Into<&'a D> {
    type Target = D;
    fn deref(&self) -> &D {
        self.ptr.into()
    }
}
impl<'a, D> Borrow<D> for CBox<'a, D> where D:DisposeRef+'a, *mut D::RefTo:Into<&'a D> {
    fn borrow(&self) -> &D {
        self.ptr.into()
    }
}
impl<'a, D> DerefMut for CBox<'a, D> where D:DisposeRef+'a, *mut D::RefTo:Into<&'a D>, *mut D::RefTo:Into<&'a mut D> {
    fn deref_mut(&mut self) -> &mut D {
        self.ptr.into()
    }
}
impl<'a> Deref for CBox<'a, str> {
    type Target = str;
    fn deref(&self) -> &str {
        unsafe {
            let text = CStr::from_ptr(self.ptr);
            str::from_utf8_unchecked(text.to_bytes())
        }
    }
}
impl<'a, 'b> From<&'a str> for CBox<'b, str> {
    fn from(text: &'a str) -> CBox<'b, str> {
        unsafe {
            let cstr = CString::new(text).unwrap();
            let ptr = libc::malloc(text.len() as size_t + 1) as *mut c_char;
            libc::strcpy(ptr, cstr.as_ptr());
            CBox::new(ptr)
        }
    }
}
impl<'a> Clone for CBox<'a, str> {
    fn clone(&self) -> CBox<'a, str> {
        unsafe {
            let ptr = libc::malloc(self.len() as size_t + 1) as *mut c_char;
            libc::strcpy(ptr, self.ptr);
            CBox::new(ptr)
        }
    }
}
impl<'a> fmt::Display for CBox<'a, str> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.deref())
    }
}
impl<'a> fmt::Debug for CBox<'a, str> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.deref())
    }
}
impl<'a, T> fmt::Display for CBox<'a, T> where T:fmt::Display+DisposeRef+'a, *mut T::RefTo:Into<&'a T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self as &T, fmt)
    }
}
impl<'a, T> fmt::Debug for CBox<'a, T> where T:fmt::Debug+DisposeRef+'a, *mut T::RefTo:Into<&'a T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self as &T, fmt)
    }
}
impl<'a, T> PartialEq<T> for CBox<'a, T> where T:'a+DisposeRef+PartialEq, *mut T::RefTo:Into<&'a T> {
    fn eq(&self, other: &T) -> bool {
        (self as &T).eq(other)
    }
}
impl DisposeRef for str {
    type RefTo = c_char;
}
<commit_msg>`CBox` => `CSemiBox`, add new `CBox` which is truly owned<commit_after>//! Provides two types, `CSemiBox` and `DisposeRef`
extern crate libc;
use libc::{malloc, free, c_char, c_void, size_t};
use std::borrow::Borrow;
use std::ffi::{CString, CStr};
use std::{fmt, mem, str};
use std::ops::{Deref, DerefMut, Drop};
use std::cmp::PartialEq;
use std::marker::PhantomData;
/// Implemented by any type of which its reference represents a C pointer that can be disposed.
pub trait DisposeRef {
    /// What a reference to this type represents as a C pointer.
    type RefTo;
    /// Destroy the contents at the pointer's location.
    ///
    /// This should run some variant of `libc::free(ptr)`
    unsafe fn dispose(ptr: *mut Self::RefTo) {
        free(ptr as *mut c_void);
    }
}

/// A wrapper for pointers made by C that are now partially owned in Rust.
///
/// This is necessary to allow owned and borrowed representations of C types
/// to be represented by the same type as they are in C with little overhead
pub struct CSemiBox<'a, D:?Sized> where D:DisposeRef+'a {
    ptr: *mut D::RefTo,
    marker: PhantomData<&'a ()>
}
impl<'a, D:?Sized> CSemiBox<'a, D> where D:DisposeRef+'a {
    #[inline(always)]
    /// Wrap the pointer in a `CSemiBox`
    pub fn new(ptr: *mut D::RefTo) -> Self {
        CSemiBox {
            ptr: ptr,
            marker: PhantomData
        }
    }
    #[inline(always)]
    /// Returns the internal pointer
    pub unsafe fn as_ptr(&self) -> *mut D::RefTo {
        self.ptr
    }
    #[inline(always)]
    /// Returns the internal pointer
    pub unsafe fn unwrap(self) -> *mut D::RefTo {
        let ptr = self.ptr;
        mem::forget(self);
        ptr
    }
}
impl<'a, D:?Sized> From<*mut D::RefTo> for CSemiBox<'a, D> where D:DisposeRef+'a {
    #[inline(always)]
    fn from(ptr: *mut D::RefTo) -> Self {
        CSemiBox::new(ptr)
    }
}
impl<'a, D:?Sized> Drop for CSemiBox<'a, D> where D:DisposeRef+'a {
    #[inline(always)]
    /// Run the destructor
    fn drop(&mut self) {
        unsafe { <D as DisposeRef>::dispose(self.ptr) }
    }
}
impl<'a, D> Deref for CSemiBox<'a, D> where D:DisposeRef+'a, *mut D::RefTo:Into<&'a D> {
    type Target = D;
    fn deref(&self) -> &D {
        self.ptr.into()
    }
}
impl<'a, D> Borrow<D> for CSemiBox<'a, D> where D:DisposeRef+'a, *mut D::RefTo:Into<&'a D> {
    fn borrow(&self) -> &D {
        self.ptr.into()
    }
}
impl<'a, D> DerefMut for CSemiBox<'a, D> where D:DisposeRef+'a, *mut D::RefTo:Into<&'a D>, *mut D::RefTo:Into<&'a mut D> {
    fn deref_mut(&mut self) -> &mut D {
        self.ptr.into()
    }
}
impl<'a, T> fmt::Display for CSemiBox<'a, T> where T:fmt::Display+DisposeRef+'a, *mut T::RefTo:Into<&'a T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self as &T, fmt)
    }
}
impl<'a, T> fmt::Debug for CSemiBox<'a, T> where T:fmt::Debug+DisposeRef+'a, *mut T::RefTo:Into<&'a T> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self as &T, fmt)
    }
}
impl<'a, T> PartialEq<T> for CSemiBox<'a, T> where T:'a+DisposeRef+PartialEq, *mut T::RefTo:Into<&'a T> {
    fn eq(&self, other: &T) -> bool {
        (self as &T).eq(other)
    }
}
impl<'a> From<&'a CStr> for CSemiBox<'a, str> {
    fn from(text: &'a CStr) -> CSemiBox<'a, str> {
        CSemiBox::new(text.as_ptr() as *mut c_char)
    }
}
impl DisposeRef for str {
    type RefTo = c_char;
}

/// A wrapper for pointers made by C that are now completely owned by Rust, so
/// they are not limited by any lifetimes.
///
/// This is necessary to allow owned and borrowed representations of C types
/// to be represented by the same type as they are in C with little overhead.
pub struct CBox<D:?Sized> where D:DisposeRef {
    ptr: *mut D::RefTo
}
impl<D:?Sized> CBox<D> where D:DisposeRef {
    #[inline(always)]
    /// Wrap the pointer in a `CBox`
    pub fn new(ptr: *mut D::RefTo) -> Self {
        CBox {
            ptr: ptr
        }
    }
    #[inline(always)]
    /// Returns the internal pointer
    pub unsafe fn as_ptr(&self) -> *mut D::RefTo {
        self.ptr
    }
    #[inline(always)]
    /// Returns the internal pointer
    pub unsafe fn unwrap(self) -> *mut D::RefTo {
        let ptr = self.ptr;
        mem::forget(self);
        ptr
    }
    /// Returns the box as a 'CSemiBox'
    pub fn as_semi<'a>(&'a self) -> &CSemiBox<'a, D> {
        unsafe {
            mem::transmute(self)
        }
    }
    /// Returns the box as a 'CSemiBox'
    pub fn as_semi_mut<'a>(&'a mut self) -> &mut CSemiBox<'a, D> {
        unsafe {
            mem::transmute(self)
        }
    }
}
impl<'a> From<&'a str> for CBox<str> {
    fn from(text: &'a str) -> CBox<str> {
        unsafe {
            let cstr = CString::new(text).unwrap();
            let ptr = libc::malloc(text.len() as size_t + 1) as *mut c_char;
            libc::strcpy(ptr, cstr.as_ptr());
            CBox::new(ptr)
        }
    }
}

impl<'a> Deref for CBox<str> {
    type Target = str;
    fn deref(&self) -> &str {
        unsafe {
            let text = CStr::from_ptr(self.ptr);
            str::from_utf8_unchecked(text.to_bytes())
        }
    }
}
impl Clone for CBox<str> {
    fn clone(&self) -> CBox<str> {
        unsafe {
            let ptr = libc::malloc(self.len() as size_t + 1) as *mut c_char;
            libc::strcpy(ptr, self.ptr);
            CBox::new(ptr)
        }
    }
}
impl fmt::Display for CBox<str> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.deref())
    }
}
impl fmt::Debug for CBox<str> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.deref())
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use route_recognizer::{Match, Params, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let mut m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        // We don't have `pub` access to the fields to destructure `Params`, so swap with an empty
        // value to avoid an allocation.
        let mut params = Params::new();
        std::mem::swap(m.params_mut(), &mut params);

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(params);
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a Params;
}

pub fn params(req: &dyn RequestExt) -> &Params {
    req.extensions().find::<Params>().expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a Params {
        params(self)
    }
}

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

    use super::{RequestParams, RouteBuilder, RoutePattern};

    use conduit::{
        Body, Extensions, Handler, HeaderMap, Host, Method, Response, Scheme, StatusCode, Version,
    };
    use conduit_test::ResponseExt;

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions,
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_string(),
                extensions: Extensions::new(),
                method,
            }
        }
    }

    impl conduit::RequestExt for RequestSentinel {
        fn http_version(&self) -> Version {
            unimplemented!()
        }
        fn method(&self) -> &Method {
            &self.method
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host(&self) -> Host<'_> {
            unimplemented!()
        }
        fn virtual_root(&self) -> Option<&str> {
            unimplemented!()
        }
        fn path(&self) -> &str {
            &self.path
        }
        fn path_mut(&mut self) -> &mut String {
            &mut self.path
        }
        fn query_string(&self) -> Option<&str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers(&self) -> &HeaderMap {
            unimplemented!()
        }
        fn body(&mut self) -> &mut dyn io::Read {
            unimplemented!()
        }
        fn extensions(&self) -> &Extensions {
            &self.extensions
        }
        fn mut_extensions(&mut self) -> &mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn path_not_found() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::POST, "/nonexistent");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::NOT_FOUND);
    }

    #[test]
    fn unknown_method() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = RequestSentinel::new(Method::DELETE, "/posts/1");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::UNKNOWN_METHOD);
    }

    #[test]
    fn catch_all() {
        lazy_static::initialize(&TRACING);

        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = RequestSentinel::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<commit_msg>Replace `RequestSentinal` with `conduit-test::MockRequest`<commit_after>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate tracing;

use std::collections::hash_map::{Entry, HashMap};
use std::error::Error;
use std::fmt;

use conduit::{box_error, Handler, HandlerResult, Method, RequestExt};
use route_recognizer::{Match, Params, Router};

static UNKNOWN_METHOD: &str = "Invalid method";
static NOT_FOUND: &str = "Path not found";

#[derive(Default)]
pub struct RouteBuilder {
    routers: HashMap<Method, Router<WrappedHandler>>,
}

#[derive(Clone, Copy)]
pub struct RoutePattern(&'static str);

impl RoutePattern {
    pub fn pattern(&self) -> &str {
        self.0
    }
}

pub struct WrappedHandler {
    pattern: RoutePattern,
    handler: Box<dyn Handler>,
}

impl conduit::Handler for WrappedHandler {
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        self.handler.call(request)
    }
}

#[derive(Debug)]
pub enum RouterError {
    UnknownMethod,
    PathNotFound,
}

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder {
            routers: HashMap::new(),
        }
    }

    #[instrument(level = "trace", skip(self))]
    pub fn recognize<'a>(
        &'a self,
        method: &Method,
        path: &str,
    ) -> Result<Match<&WrappedHandler>, RouterError> {
        match self.routers.get(method) {
            Some(router) => router.recognize(path).or(Err(RouterError::PathNotFound)),
            None => Err(RouterError::UnknownMethod),
        }
    }

    #[instrument(level = "trace", skip(self, handler))]
    pub fn map<H: Handler>(
        &mut self,
        method: Method,
        pattern: &'static str,
        handler: H,
    ) -> &mut RouteBuilder {
        {
            let router = match self.routers.entry(method) {
                Entry::Occupied(e) => e.into_mut(),
                Entry::Vacant(e) => e.insert(Router::new()),
            };
            let wrapped_handler = WrappedHandler {
                pattern: RoutePattern(pattern),
                handler: Box::new(handler),
            };
            router.add(pattern, wrapped_handler);
        }
        self
    }

    pub fn get<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::GET, pattern, handler)
    }

    pub fn post<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::POST, pattern, handler)
    }

    pub fn put<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::PUT, pattern, handler)
    }

    pub fn delete<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::DELETE, pattern, handler)
    }

    pub fn head<H: Handler>(&mut self, pattern: &'static str, handler: H) -> &mut RouteBuilder {
        self.map(Method::HEAD, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    #[instrument(level = "trace", skip(self, request))]
    fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
        let mut m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => {
                    info!("{}", e);
                    return Err(box_error(e));
                }
            }
        };

        // We don't have `pub` access to the fields to destructure `Params`, so swap with an empty
        // value to avoid an allocation.
        let mut params = Params::new();
        std::mem::swap(m.params_mut(), &mut params);

        let pattern = m.handler().pattern;
        debug!(pattern = pattern.0, "matching route handler found");

        {
            let extensions = request.mut_extensions();
            extensions.insert(pattern);
            extensions.insert(params);
        }

        let span = trace_span!("handler", pattern = pattern.0);
        span.in_scope(|| m.handler().call(request))
    }
}

impl Error for RouterError {
    fn description(&self) -> &str {
        match self {
            Self::UnknownMethod => UNKNOWN_METHOD,
            Self::PathNotFound => NOT_FOUND,
        }
    }
}

impl fmt::Display for RouterError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[allow(deprecated)]
        self.description().fmt(f)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a Params;
}

pub fn params(req: &dyn RequestExt) -> &Params {
    req.extensions().find::<Params>().expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a (dyn RequestExt + 'a) {
    fn params(self) -> &'a Params {
        params(self)
    }
}

#[cfg(test)]
mod tests {
    use super::{RequestParams, RouteBuilder, RoutePattern};

    use conduit::{Body, Handler, Method, Response, StatusCode};
    use conduit_test::{MockRequest, ResponseExt};

    lazy_static::lazy_static! {
        static ref TRACING: () = {
            tracing_subscriber::FmtSubscriber::builder()
                .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
                .with_span_events(tracing_subscriber::fmt::format::FmtSpan::FULL)
                .with_test_writer()
                .init();
        };
    }

    #[test]
    fn basic_get() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::GET, "/posts/1");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"1, GET, /posts/:id"[..]);
    }

    #[test]
    fn basic_post() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/posts/10");
        let res = router.call(&mut req).expect("No response");

        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b"10, POST, /posts/:id"[..]);
    }

    #[test]
    fn path_not_found() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::POST, "/nonexistent");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::NOT_FOUND);
    }

    #[test]
    fn unknown_method() {
        lazy_static::initialize(&TRACING);

        let router = test_router();
        let mut req = MockRequest::new(Method::DELETE, "/posts/1");
        let err = router.call(&mut req).err().unwrap();

        assert_eq!(err.to_string(), super::UNKNOWN_METHOD);
    }

    #[test]
    fn catch_all() {
        lazy_static::initialize(&TRACING);

        let mut router = RouteBuilder::new();
        router.get("/*", test_handler);

        let mut req = MockRequest::new(Method::GET, "/foo");
        let res = router.call(&mut req).expect("No response");
        assert_eq!(res.status(), StatusCode::OK);
        assert_eq!(*res.into_cow(), b", GET, /*"[..]);
    }

    fn test_router() -> RouteBuilder {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", test_handler);
        router.get("/posts/:id", test_handler);
        router
    }

    fn test_handler(req: &mut dyn conduit::RequestExt) -> conduit::HttpResult {
        let res = vec![
            req.params().find("id").unwrap_or("").to_string(),
            format!("{:?}", req.method()),
            req.extensions()
                .find::<RoutePattern>()
                .unwrap()
                .pattern()
                .to_string(),
        ];

        let bytes = res.join(", ").into_bytes();
        Response::builder().body(Body::from_vec(bytes))
    }
}
<|endoftext|>