<commit_before>#[macro_use]
mod common;

use std::str;
use std::u16;

fn version_ge_4_3() -> bool {
    let (major, minor, _) = zmq::version();
    (major > 4) || (major == 4 && minor >= 3)
}

/// Read one event off the monitor socket; return the SocketEvent value.
fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result<zmq::SocketEvent> {
    let msg = monitor.recv_msg(0)?;
    // TODO: could be simplified by using `TryInto` (since 1.34)
    let event = u16::from_ne_bytes([msg[0], msg[1]]);

    assert!(
        monitor.get_rcvmore()?,
        "Monitor socket should have two messages per event"
    );

    // the address, we'll ignore it
    let _ = monitor.recv_msg(0)?;

    Ok(zmq::SocketEvent::from_raw(event))
}

fn expect_event(mon: &mut zmq::Socket, expected: zmq::SocketEvent) {
    let event = get_monitor_event(mon).unwrap();
    assert_eq!(expected, event);
}

/// Send a series of pings between the client and the server.
/// The messages should round trip from the client to the server
/// and back again.
fn bounce(client: &mut zmq::Socket, server: &mut zmq::Socket) {
    let data = "12345678ABCDEFGH12345678abcdefgh";

    //  Send message from client to server
    client.send(data.as_bytes(), zmq::SNDMORE).unwrap();
    client.send(data.as_bytes(), 0).unwrap();

    //  Receive message at server side
    let mut recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(server.get_rcvmore().unwrap());

    recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!server.get_rcvmore().unwrap());

    //  Send message from client to server
    server.send(&recv_data, zmq::SNDMORE).unwrap();
    server.send(&recv_data, 0).unwrap();

    //  Receive the two parts at the client side
    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(client.get_rcvmore().unwrap());

    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!client.get_rcvmore().unwrap());
}

/// Close the given socket with LINGER set to 0
fn close_zero_linger(socket: zmq::Socket) {
    socket.set_linger(0).unwrap();
    drop(socket);
}

test!(test_monitor_events, {
    let ctx = zmq::Context::new();

    let mut client = ctx.socket(zmq::DEALER).unwrap();
    let mut server = ctx.socket(zmq::DEALER).unwrap();

    let err = client
        .monitor("tcp://127.0.0.1:9999", 0)
        .expect_err("Socket monitoring only works over inproc://");
    assert_eq!(zmq::Error::EPROTONOSUPPORT, err);

    assert!(client
        .monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32)
        .is_ok());
    assert!(server
        .monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32)
        .is_ok());

    let mut client_mon = ctx.socket(zmq::PAIR).unwrap();
    let mut server_mon = ctx.socket(zmq::PAIR).unwrap();

    // Connect these to the inproc endpoints so they'll get events
    client_mon.connect("inproc://monitor-client").unwrap();
    server_mon.connect("inproc://monitor-server").unwrap();

    // Now do a basic ping test
    server.bind("tcp://127.0.0.1:9998").unwrap();
    client.connect("tcp://127.0.0.1:9998").unwrap();
    bounce(&mut client, &mut server);

    // Close client and server
    close_zero_linger(client);
    close_zero_linger(server);

    // Now collect and check events from both sockets
    let mut event = get_monitor_event(&mut client_mon).unwrap();
    if event == zmq::SocketEvent::CONNECT_DELAYED {
        event = get_monitor_event(&mut client_mon).unwrap();
    }
    assert_eq!(zmq::SocketEvent::CONNECTED, event);

    if version_ge_4_3() {
        expect_event(&mut client_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED);
    }

    expect_event(&mut client_mon, zmq::SocketEvent::MONITOR_STOPPED);

    // This is the flow of server events
    expect_event(&mut server_mon, zmq::SocketEvent::LISTENING);
    expect_event(&mut server_mon, zmq::SocketEvent::ACCEPTED);

    if version_ge_4_3() {
        expect_event(&mut server_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED);
    }
    expect_event(&mut server_mon, zmq::SocketEvent::CLOSED);
    expect_event(&mut server_mon, zmq::SocketEvent::MONITOR_STOPPED);

    // Close down the sockets
    close_zero_linger(client_mon);
    close_zero_linger(server_mon);
});
<commit_msg>Fix flaky `test_monitor_events` test<commit_after>#[macro_use]
mod common;

use std::str;
use std::u16;

fn version_ge_4_3() -> bool {
    let (major, minor, _) = zmq::version();
    (major > 4) || (major == 4 && minor >= 3)
}

/// Read one event off the monitor socket; return the SocketEvent value.
fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result<zmq::SocketEvent> {
    let msg = monitor.recv_msg(0)?;
    // TODO: could be simplified by using `TryInto` (since 1.34)
    let event = u16::from_ne_bytes([msg[0], msg[1]]);

    assert!(
        monitor.get_rcvmore()?,
        "Monitor socket should have two messages per event"
    );

    // the address, we'll ignore it
    let _ = monitor.recv_msg(0)?;

    Ok(zmq::SocketEvent::from_raw(event))
}

fn expect_event(mon: &mut zmq::Socket, expected: zmq::SocketEvent) {
    let event = get_monitor_event(mon).unwrap();
    assert_eq!(expected, event);
}

/// Send a series of pings between the client and the server.
/// The messages should round trip from the client to the server
/// and back again.
fn bounce(client: &mut zmq::Socket, server: &mut zmq::Socket) {
    let data = "12345678ABCDEFGH12345678abcdefgh";

    //  Send message from client to server
    client.send(data.as_bytes(), zmq::SNDMORE).unwrap();
    client.send(data.as_bytes(), 0).unwrap();

    //  Receive message at server side
    let mut recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(server.get_rcvmore().unwrap());

    recv_data = server.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!server.get_rcvmore().unwrap());

    //  Send message from client to server
    server.send(&recv_data, zmq::SNDMORE).unwrap();
    server.send(&recv_data, 0).unwrap();

    //  Receive the two parts at the client side
    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(client.get_rcvmore().unwrap());

    recv_data = client.recv_bytes(0).unwrap();
    assert_eq!(str::from_utf8(&recv_data).unwrap(), data);
    assert!(!client.get_rcvmore().unwrap());
}

/// Close the given socket with LINGER set to 0
fn close_zero_linger(socket: zmq::Socket) {
    socket.set_linger(0).unwrap();
    drop(socket);
}

test!(test_monitor_events, {
    let ctx = zmq::Context::new();

    let mut client = ctx.socket(zmq::DEALER).unwrap();
    let mut server = ctx.socket(zmq::DEALER).unwrap();

    let err = client
        .monitor("tcp://127.0.0.1:9999", 0)
        .expect_err("Socket monitoring only works over inproc://");
    assert_eq!(zmq::Error::EPROTONOSUPPORT, err);

    assert!(client
        .monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32)
        .is_ok());
    assert!(server
        .monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32)
        .is_ok());

    let mut client_mon = ctx.socket(zmq::PAIR).unwrap();
    let mut server_mon = ctx.socket(zmq::PAIR).unwrap();

    // Connect these to the inproc endpoints so they'll get events
    client_mon.connect("inproc://monitor-client").unwrap();
    server_mon.connect("inproc://monitor-server").unwrap();

    // Now do a basic ping test
    server.bind("tcp://127.0.0.1:9998").unwrap();
    client.connect("tcp://127.0.0.1:9998").unwrap();
    bounce(&mut client, &mut server);

    close_zero_linger(client);

    // Now collect and check events from both sockets
    let mut event = get_monitor_event(&mut client_mon).unwrap();
    if event == zmq::SocketEvent::CONNECT_DELAYED {
        event = get_monitor_event(&mut client_mon).unwrap();
    }
    assert_eq!(zmq::SocketEvent::CONNECTED, event);

    if version_ge_4_3() {
        expect_event(&mut client_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED);
    }
    expect_event(&mut client_mon, zmq::SocketEvent::MONITOR_STOPPED);

    // This is the flow of server events
    expect_event(&mut server_mon, zmq::SocketEvent::LISTENING);
    expect_event(&mut server_mon, zmq::SocketEvent::ACCEPTED);

    if version_ge_4_3() {
        expect_event(&mut server_mon, zmq::SocketEvent::HANDSHAKE_SUCCEEDED);
    }
    expect_event(&mut server_mon, zmq::SocketEvent::DISCONNECTED);

    close_zero_linger(server);

    expect_event(&mut server_mon, zmq::SocketEvent::CLOSED);
    expect_event(&mut server_mon, zmq::SocketEvent::MONITOR_STOPPED);

    // Close down the sockets
    close_zero_linger(client_mon);
    close_zero_linger(server_mon);
});
<|endoftext|>


<commit_before>extern crate hyper;
extern crate regex;

use std::collections::HashMap;

use hyper::method::Method;
use hyper::server::{Handler, Request, Response};
use hyper::status::StatusCode;
use regex::{Regex, RegexSet};

use error::RouterError;

pub type Captures = Option<Vec<String>>;
pub type RouterFn = fn(Request, Response, Captures);

#[derive(PartialEq, Eq, Hash)]
pub struct RouteInfo {
    route: String,
    verb: Method
}

/// The Router struct contains the information for your app to route requests
/// properly based on their HTTP method and matching route. It allows the use
/// of a custom 404 handler if desired but provides a default as well.
///
/// Under the hood a Router uses a RegexSet to match URI's that come in to the
/// instance of the hyper server. Because of this, it has the potential to match
/// multiple patterns that you provide. It will call the first handler that it
/// matches against so order matters.
pub struct Router {
    /// A custom 404 handler that you can provide.
    pub not_found: Option<RouterFn>,

    routes: Option<RegexSet>,
    route_list: Vec<String>,
    compiled_list: Vec<Regex>,
    route_map: HashMap<RouteInfo, RouterFn>
}

impl Handler for Router {
    // The handle method for the router simply tries to match the URI against
    // the first pattern that it can which in turn calls its associated handle
    // function passing the hyper Request and Response structures.
    fn handle(&self, req: Request, res: Response) {
        let uri = format!("{}", req.uri);
        let matches = self.routes.as_ref().unwrap().matches(&uri);
        let index = matches.iter().next();
        match index {
            Some(i) => {
                let route = &self.route_list[i];
                let route_info = RouteInfo{route: route.clone(), verb: req.method.clone()};
                let handler = self.route_map.get(&route_info);
                match handler {
                    Some(h) => {
                        let compiled_pattern = &self.compiled_list[i];
                        let captures = get_captures(compiled_pattern, &uri);
                        h(req, res, captures);
                    }
                    None => {
                        not_allowed(req, res);
                    }
                }
            },
            // There is no point in passing captures to a route handler that
            // wasn't found.
            None => self.not_found.unwrap()(req, res, None)
        }
    }
}

impl Router {
    /// Construct a new Router to maintain the routes and their handler
    /// functions.
    pub fn new() -> Router {
        Router {
            not_found: None,
            routes: None,
            route_list: Vec::new(),
            compiled_list: Vec::new(),
            route_map: HashMap::new(),
        }
    }

    /// Add a route to the router and give it a function to call when the route
    /// is matched against. You can call this explicitly or use the convenience
    /// methods defined below.
    pub fn add_route(&mut self, verb: Method, route: &str, handler: RouterFn) {
        let route_info = RouteInfo{route: route.to_owned(), verb: verb};
        let pattern = Regex::new(route);
        match pattern {
            Ok(p) => { self.compiled_list.push(p); },
            Err(e) => { println!("Not adding this route due to error: {}", e); }
        }
        self.route_list.push(route.to_owned());
        self.route_map.insert(route_info, handler);
    }

    /// A convenience method for OPTIONS requests.
    pub fn options(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Options, route, handler);
    }

    /// A convenience method for GET requests.
    pub fn get(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Get, route, handler);
    }

    /// A convenience method for POST requests.
    pub fn post(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Post, route, handler);
    }

    /// A convenience method for PUT requests.
    pub fn put(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Put, route, handler);
    }

    /// A convenience method for DELETE requests.
    pub fn delete(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Delete, route, handler);
    }

    /// This function ensures that a valid RegexSet could be made from the route
    /// vector that was built while using the functions that add routes. It also
    /// requires that there exist at least one route so that the RegexSet can be
    /// successfully constructed.
    ///
    /// It will also ensure that there is a handler for routes that do not match
    /// any available in the set.
    pub fn finalize(&mut self) -> Result<(), RouterError> {
        if self.route_list.len() == 0  {
            return Err(RouterError::TooFewRoutes);
        }

        // Check if the user added a 404 handler, else use the default.
        match self.not_found {
            Some(_) => {},
            None => { self.not_found = Some(default_not_found); }
        }

        let re_routes = RegexSet::new(self.route_list.iter());
        match re_routes {
            Ok(r) => {
                self.routes = Some(r);
                Ok(())
            }
            Err(_) => {
                Err(RouterError::BadSet)
            }
        }
    }

    /// Add a function to handle routes that get no matches.
    pub fn add_not_found(&mut self, not_found: RouterFn) {
        self.not_found = Some(not_found)
    }
}

// The default 404 handler.
fn default_not_found(req: Request, mut res: Response, _: Captures) {
    let message = format!("No route handler found for {}", req.uri);
    *res.status_mut() = StatusCode::NotFound;
    res.send(message.as_bytes()).unwrap();
}

// This handler will get fired when a URI matches a route but contains the wrong method.
fn not_allowed(_: Request, mut res: Response) {
    *res.status_mut() = StatusCode::MethodNotAllowed;
    let res = res.start().unwrap();
    res.end().unwrap();
}

// Return that captures from a pattern that was matched.
fn get_captures(pattern: &Regex, uri: &str) -> Captures {
    // We know this compiles because it was part of the set.
    let caps = pattern.captures(uri);
    match caps {
        Some(caps) => {
            let mut v = vec![];
            for c in caps.iter() {
                v.push(c.unwrap().to_owned());
            }
            Some(v)
        },
        None => None
    }
}

mod error;

#[test]
fn less_than_two_routes() {
    let mut router = Router::new();
    let e = router.finalize();
    assert_eq!(e.err(), Some(RouterError::TooFewRoutes));
}

#[test]
fn bad_regular_expression() {
    fn test_handler(_: Request, _: Response, _: Captures) {}
    let mut router = Router::new();
    router.add_route(Method::Get, r"/[", test_handler);
    let e = router.finalize();
    assert_eq!(e.err(), Some(RouterError::BadSet));
}
<commit_msg>change test name for what it is testing<commit_after>extern crate hyper;
extern crate regex;

use std::collections::HashMap;

use hyper::method::Method;
use hyper::server::{Handler, Request, Response};
use hyper::status::StatusCode;
use regex::{Regex, RegexSet};

use error::RouterError;

pub type Captures = Option<Vec<String>>;
pub type RouterFn = fn(Request, Response, Captures);

#[derive(PartialEq, Eq, Hash)]
pub struct RouteInfo {
    route: String,
    verb: Method
}

/// The Router struct contains the information for your app to route requests
/// properly based on their HTTP method and matching route. It allows the use
/// of a custom 404 handler if desired but provides a default as well.
///
/// Under the hood a Router uses a RegexSet to match URI's that come in to the
/// instance of the hyper server. Because of this, it has the potential to match
/// multiple patterns that you provide. It will call the first handler that it
/// matches against so order matters.
pub struct Router {
    /// A custom 404 handler that you can provide.
    pub not_found: Option<RouterFn>,

    routes: Option<RegexSet>,
    route_list: Vec<String>,
    compiled_list: Vec<Regex>,
    route_map: HashMap<RouteInfo, RouterFn>
}

impl Handler for Router {
    // The handle method for the router simply tries to match the URI against
    // the first pattern that it can which in turn calls its associated handle
    // function passing the hyper Request and Response structures.
    fn handle(&self, req: Request, res: Response) {
        let uri = format!("{}", req.uri);
        let matches = self.routes.as_ref().unwrap().matches(&uri);
        let index = matches.iter().next();
        match index {
            Some(i) => {
                let route = &self.route_list[i];
                let route_info = RouteInfo{route: route.clone(), verb: req.method.clone()};
                let handler = self.route_map.get(&route_info);
                match handler {
                    Some(h) => {
                        let compiled_pattern = &self.compiled_list[i];
                        let captures = get_captures(compiled_pattern, &uri);
                        h(req, res, captures);
                    }
                    None => {
                        not_allowed(req, res);
                    }
                }
            },
            // There is no point in passing captures to a route handler that
            // wasn't found.
            None => self.not_found.unwrap()(req, res, None)
        }
    }
}

impl Router {
    /// Construct a new Router to maintain the routes and their handler
    /// functions.
    pub fn new() -> Router {
        Router {
            not_found: None,
            routes: None,
            route_list: Vec::new(),
            compiled_list: Vec::new(),
            route_map: HashMap::new(),
        }
    }

    /// Add a route to the router and give it a function to call when the route
    /// is matched against. You can call this explicitly or use the convenience
    /// methods defined below.
    pub fn add_route(&mut self, verb: Method, route: &str, handler: RouterFn) {
        let route_info = RouteInfo{route: route.to_owned(), verb: verb};
        let pattern = Regex::new(route);
        match pattern {
            Ok(p) => { self.compiled_list.push(p); },
            Err(e) => { println!("Not adding this route due to error: {}", e); }
        }
        self.route_list.push(route.to_owned());
        self.route_map.insert(route_info, handler);
    }

    /// A convenience method for OPTIONS requests.
    pub fn options(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Options, route, handler);
    }

    /// A convenience method for GET requests.
    pub fn get(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Get, route, handler);
    }

    /// A convenience method for POST requests.
    pub fn post(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Post, route, handler);
    }

    /// A convenience method for PUT requests.
    pub fn put(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Put, route, handler);
    }

    /// A convenience method for DELETE requests.
    pub fn delete(&mut self, route: &str, handler: RouterFn) {
        self.add_route(Method::Delete, route, handler);
    }

    /// This function ensures that a valid RegexSet could be made from the route
    /// vector that was built while using the functions that add routes. It also
    /// requires that there exist at least one route so that the RegexSet can be
    /// successfully constructed.
    ///
    /// It will also ensure that there is a handler for routes that do not match
    /// any available in the set.
    pub fn finalize(&mut self) -> Result<(), RouterError> {
        if self.route_list.len() == 0  {
            return Err(RouterError::TooFewRoutes);
        }

        // Check if the user added a 404 handler, else use the default.
        match self.not_found {
            Some(_) => {},
            None => { self.not_found = Some(default_not_found); }
        }

        let re_routes = RegexSet::new(self.route_list.iter());
        match re_routes {
            Ok(r) => {
                self.routes = Some(r);
                Ok(())
            }
            Err(_) => {
                Err(RouterError::BadSet)
            }
        }
    }

    /// Add a function to handle routes that get no matches.
    pub fn add_not_found(&mut self, not_found: RouterFn) {
        self.not_found = Some(not_found)
    }
}

// The default 404 handler.
fn default_not_found(req: Request, mut res: Response, _: Captures) {
    let message = format!("No route handler found for {}", req.uri);
    *res.status_mut() = StatusCode::NotFound;
    res.send(message.as_bytes()).unwrap();
}

// This handler will get fired when a URI matches a route but contains the wrong method.
fn not_allowed(_: Request, mut res: Response) {
    *res.status_mut() = StatusCode::MethodNotAllowed;
    let res = res.start().unwrap();
    res.end().unwrap();
}

// Return that captures from a pattern that was matched.
fn get_captures(pattern: &Regex, uri: &str) -> Captures {
    // We know this compiles because it was part of the set.
    let caps = pattern.captures(uri);
    match caps {
        Some(caps) => {
            let mut v = vec![];
            for c in caps.iter() {
                v.push(c.unwrap().to_owned());
            }
            Some(v)
        },
        None => None
    }
}

mod error;

#[test]
fn no_routes() {
    let mut router = Router::new();
    let e = router.finalize();
    assert_eq!(e.err(), Some(RouterError::TooFewRoutes));
}

#[test]
fn bad_regular_expression() {
    fn test_handler(_: Request, _: Response, _: Captures) {}
    let mut router = Router::new();
    router.add_route(Method::Get, r"/[", test_handler);
    let e = router.finalize();
    assert_eq!(e.err(), Some(RouterError::BadSet));
}
<|endoftext|>


<commit_before>extern crate semver;
extern crate conduit;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::Cursor;
use std::net::{SocketAddr, Ipv4Addr, SocketAddrV4};

use semver::Version;
use conduit::{Method, Scheme, Host, Extensions, Headers, TypeMap};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    body: Option<Vec<u8>>,
    build_headers: HashMap<String, String>,
    headers: MockHeaders,
    extensions: TypeMap,
    reader: Option<Cursor<Vec<u8>>>
}

impl MockRequest {
    pub fn new(method: Method, path: &str) -> MockRequest {
        let headers = HashMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            body: None,
            build_headers: headers,
            headers: MockHeaders { headers: HashMap::new() },
            method: method,
            reader: None
        }
    }

    pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
        self.method = method;
        self
    }

    pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
        self.path = path.to_string();
        self
    }

    pub fn with_query(&mut self, string: &str) -> &mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body(&mut self, bytes: &[u8]) -> &mut MockRequest {
        self.body = Some(bytes.to_vec());
        self.reader = None;
        self
    }

    pub fn header(&mut self, name: &str, value: &str) -> &mut MockRequest {
        self.build_headers.insert(name.to_string(), value.to_string());
        let headers = MockHeaders { headers: self.build_headers.clone() };
        self.headers = headers;

        self
    }
}

pub struct MockHeaders {
    headers: HashMap<String, String>
}

impl Headers for MockHeaders {
    fn find(&self, key: &str) -> Option<Vec<&str>> {
        self.headers.get(key).map(|v| vec![&v[..]])
    }

    fn has(&self, key: &str) -> bool {
        self.headers.contains_key(key)
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        self.headers.iter().map(|(k,v)| (&k[..], vec![&v[..]]))
                    .collect()
    }
}

impl conduit::Request for MockRequest {
    fn http_version(&self) -> Version {
        Version::parse("1.1.0").unwrap()
    }

    fn conduit_version(&self) -> Version {
        Version::parse("0.1.0").unwrap()
    }

    fn method(&self) -> Method { self.method }
    fn scheme(&self) -> Scheme { Scheme::Http }
    fn host(&self) -> Host { Host::Name("example.com") }
    fn virtual_root(&self) -> Option<&str> { None }

    fn path(&self) -> &str {
        &self.path
    }

    fn query_string(&self) -> Option<&str> {
        self.query_string.as_ref().map(|s| &s[..])
    }

    fn remote_addr(&self) -> SocketAddr {
        SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
    }

    fn content_length(&self) -> Option<u64> {
        self.body.as_ref().map(|b| b.len() as u64)
    }

    fn headers(&self) -> &Headers {
        &self.headers as &Headers
    }

    fn body(&mut self) -> &mut Read {
        if self.reader.is_none() {
            let body = self.body.clone().unwrap_or(Vec::new());
            self.reader = Some(Cursor::new(body));
        }
        self.reader.as_mut().unwrap()
    }

    fn extensions(&self) -> &Extensions {
        &self.extensions
    }
    fn mut_extensions(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

#[cfg(test)]
mod tests {
    use super::MockRequest;
    use semver::Version;

    use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};

    use conduit::{Request, Method, Host, Scheme};

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(Method::Get, "/");

        assert_eq!(req.http_version(), Version::parse("1.1.0").unwrap());
        assert_eq!(req.conduit_version(), Version::parse("0.1.0").unwrap());
        assert_eq!(req.method(), Method::Get);
        assert_eq!(req.scheme(), Scheme::Http);
        assert_eq!(req.host(), Host::Name("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(req.remote_addr(),
                   SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1),
                                                    80)));
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().all().len(), 0);
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(Method::Post, "/articles");
        req.with_body(b"Hello world");

        assert_eq!(req.method(), Method::Post);
        assert_eq!(req.path(), "/articles");
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(Method::Post, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(Method::Post, "/articles");
        req.header("User-Agent", "lulz");
        req.header("DNT", "1");

        assert_eq!(req.headers().all().len(), 2);
        assert_eq!(req.headers().find("User-Agent").unwrap(), vec!("lulz"));
        assert_eq!(req.headers().find("DNT").unwrap(), vec!("1"));
    }
}
<commit_msg>Update with master<commit_after>extern crate semver;
extern crate conduit;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::Cursor;
use std::net::{SocketAddr, Ipv4Addr, SocketAddrV4};

use semver::Version;
use conduit::{Method, Scheme, Host, Extensions, Headers, TypeMap};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    body: Option<Vec<u8>>,
    build_headers: HashMap<String, String>,
    headers: MockHeaders,
    extensions: TypeMap,
    reader: Option<Cursor<Vec<u8>>>
}

impl MockRequest {
    pub fn new(method: Method, path: &str) -> MockRequest {
        let headers = HashMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            body: None,
            build_headers: headers,
            headers: MockHeaders { headers: HashMap::new() },
            method: method,
            reader: None
        }
    }

    pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
        self.method = method;
        self
    }

    pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
        self.path = path.to_string();
        self
    }

    pub fn with_query(&mut self, string: &str) -> &mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body(&mut self, bytes: &[u8]) -> &mut MockRequest {
        self.body = Some(bytes.to_vec());
        self.reader = None;
        self
    }

    pub fn header(&mut self, name: &str, value: &str) -> &mut MockRequest {
        self.build_headers.insert(name.to_string(), value.to_string());
        let headers = MockHeaders { headers: self.build_headers.clone() };
        self.headers = headers;

        self
    }
}

pub struct MockHeaders {
    headers: HashMap<String, String>
}

impl Headers for MockHeaders {
    fn find(&self, key: &str) -> Option<Vec<&str>> {
        self.headers.get(key).map(|v| vec![&v[..]])
    }

    fn has(&self, key: &str) -> bool {
        self.headers.contains_key(key)
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        self.headers.iter().map(|(k,v)| (&k[..], vec![&v[..]]))
                    .collect()
    }
}

impl conduit::Request for MockRequest {
    fn http_version(&self) -> Version {
        Version::parse("1.1.0").unwrap()
    }

    fn conduit_version(&self) -> Version {
        Version::parse("0.1.0").unwrap()
    }

    fn method(&self) -> Method { self.method.clone() }
    fn scheme(&self) -> Scheme { Scheme::Http }
    fn host(&self) -> Host { Host::Name("example.com") }
    fn virtual_root(&self) -> Option<&str> { None }

    fn path(&self) -> &str {
        &self.path
    }

    fn query_string(&self) -> Option<&str> {
        self.query_string.as_ref().map(|s| &s[..])
    }

    fn remote_addr(&self) -> SocketAddr {
        SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
    }

    fn content_length(&self) -> Option<u64> {
        self.body.as_ref().map(|b| b.len() as u64)
    }

    fn headers(&self) -> &Headers {
        &self.headers as &Headers
    }

    fn body(&mut self) -> &mut Read {
        if self.reader.is_none() {
            let body = self.body.clone().unwrap_or(Vec::new());
            self.reader = Some(Cursor::new(body));
        }
        self.reader.as_mut().unwrap()
    }

    fn extensions(&self) -> &Extensions {
        &self.extensions
    }
    fn mut_extensions(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

#[cfg(test)]
mod tests {
    use super::MockRequest;
    use semver::Version;

    use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};

    use conduit::{Request, Method, Host, Scheme};

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(Method::Get, "/");

        assert_eq!(req.http_version(), Version::parse("1.1.0").unwrap());
        assert_eq!(req.conduit_version(), Version::parse("0.1.0").unwrap());
        assert_eq!(req.method(), Method::Get);
        assert_eq!(req.scheme(), Scheme::Http);
        assert_eq!(req.host(), Host::Name("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(req.remote_addr(),
                   SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1),
                                                    80)));
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().all().len(), 0);
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(Method::Post, "/articles");
        req.with_body(b"Hello world");

        assert_eq!(req.method(), Method::Post);
        assert_eq!(req.path(), "/articles");
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(Method::Post, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(Method::Post, "/articles");
        req.header("User-Agent", "lulz");
        req.header("DNT", "1");

        assert_eq!(req.headers().all().len(), 2);
        assert_eq!(req.headers().find("User-Agent").unwrap(), vec!("lulz"));
        assert_eq!(req.headers().find("DNT").unwrap(), vec!("1"));
    }
}
<|endoftext|>


<commit_before>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    // pub language: Option<String>,
    // pub copyright: Option<String>,
    // pub managing_editor: Option<String>,
    // pub web_master: Option<String>,
    // pub pub_date: Option<String>,
    // pub last_build_date: Option<String>,
    // pub category:
    // pub generator: Option<String>,
    // pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    // pub image: Option<String>,
    // pub rating: Option<String>,
    // pub text_input:
    // pub skip_hours: Option<String>,
    // pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag(elem_with_text("title", &self.title));
        channel.tag(elem_with_text("link", &self.link));
        channel.tag(elem_with_text("description", &self.description));

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        if let Some(ref s) = self.title {
            item.tag(elem_with_text("title", s));
        }

        if let Some(ref s) = self.link {
            item.tag(elem_with_text("link", s));
        }

        if let Some(ref s) = self.description {
            item.tag(elem_with_text("description", s));
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        Ok(item)
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(_) = Rss::from_read(&mut file).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Create+utilize helper function<commit_after>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

fn tag_text_elem(parent: &mut Element, child_name: &'static str, child_body: &str) {
    parent.tag(elem_with_text(child_name, child_body));
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    // pub language: Option<String>,
    // pub copyright: Option<String>,
    // pub managing_editor: Option<String>,
    // pub web_master: Option<String>,
    // pub pub_date: Option<String>,
    // pub last_build_date: Option<String>,
    // pub category:
    // pub generator: Option<String>,
    // pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    // pub image: Option<String>,
    // pub rating: Option<String>,
    // pub text_input:
    // pub skip_hours: Option<String>,
    // pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        tag_text_elem(&mut channel, "title", &self.title);
        tag_text_elem(&mut channel, "link", &self.link);
        tag_text_elem(&mut channel, "description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        if let Some(ref s) = self.title {
            tag_text_elem(&mut item, "title", s);
        }

        if let Some(ref s) = self.link {
            tag_text_elem(&mut item, "link", s);
        }

        if let Some(ref s) = self.description {
            tag_text_elem(&mut item, "description", s);
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        Ok(item)
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(_) = Rss::from_read(&mut file).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![unstable]

//! A library for setting current values for stack scope,
//! such as application structure.

pub use get::Get;
pub use set::Set;
pub use action::Action;

mod refcell;
mod get;
mod set;
mod action;

/// Something that can be set at an object.
///
/// Must be implemented on a `(Property, Object)`
#[unstable]
pub trait SetAt: Pair {
    /// Modify `F` with self.
    fn set_at(
        val: <Self as Pair>::Data,
        obj: &mut <Self as Pair>::Object
    );
}

/// Something that can be retrieved from another object.
#[unstable]
pub trait GetFrom: Pair {
    /// Gets value from object.
    fn get_from(
        obj: &<Self as Pair>::Object
    ) -> <Self as Pair>::Data;
}

/// Does something to an object.
#[unstable]
pub trait ActOn<T>: Pair {
    /// Does something to an object.
    fn act_on(
        action: <Self as Pair>::Data,
        obj: &mut <Self as Pair>::Object
    ) -> T;
}

/// Used to reduce the need for associated types.
pub trait Pair: std::marker::PhantomFn<Self> {
    type Data;
    type Object;
}

impl<T, U> Pair for (T, U) {
    type Data = T;
    type Object = U;
}

/// Used to work around limits in macro syntax.
#[macro_export]
macro_rules! quack_macro_items { ($($x:item)+) => ($($x)+) }

#[macro_export]
macro_rules! quack_get {
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn [$($u:tt),*] () -> $get_prop_type:path [$($w:tt)*] $e:block
    ) => {quack_macro_items!{
        impl<$($u),*> $crate::GetFrom for ($get_prop_type, $this_type<$($t),*>)
            $($w)*
        {
            #[allow(unused_variables)]
            #[inline(always)]
            fn get_from($this: &$this_type<$($t),*>) -> $get_prop_type {
                $e
            }
        }
    }};
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn () -> $get_prop_type:path [$($w:tt)*] $e:block
    ) => {
        quack_get! {
            $this : $this_type [$($t),*]
            fn [$($t),*] () -> $get_prop_type [$($w)*] $e
        }
    }
}

#[macro_export]
macro_rules! quack_set {
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn [$($u:tt),*] ($val:ident : $set_prop_type:path) [$($w:tt)*] $f:block
    ) => {quack_macro_items!{
        impl<$($u),*> $crate::SetAt for ($set_prop_type, $this_type<$($t),*>)
            $($w)*
        {
            #[allow(unused_variables)]
            #[inline(always)]
            fn set_at($val : $set_prop_type, $this : &mut $this_type<$($t),*>) {
                $f
            }
        }
    }};
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn ($val:ident : $set_prop_type:path) [$($w:tt)*] $f:block
    ) => {
        quack_set! {
            $this : $this_type [$($t),*]
            fn [$($t),*] ($val : $set_prop_type) [$($w)*] $f
        }
    }
}

#[macro_export]
macro_rules! quack_action {
    (
        $this: ident : $this_type:ident [$($t:tt),*]
        fn [$($u:tt),*] (
            $action:ident : $action_type:path
        ) -> $ret_action_type:ty [$($w:tt)*] $g:block
    ) => {quack_macro_items!{
        impl<$($u),*> $crate::ActOn<$ret_action_type>
        for ($action_type, $this_type<$($t),*>)
            $($w)*
        {
            #[allow(unused_variables)]
            #[inline(always)]
            fn act_on(
                $action : $action_type,
                $this: &mut $this_type<$($t),*>
            ) -> $ret_action_type {
                $g
            }
        }
    }};
    (
        $this: ident : $this_type:ident [$($t:tt),*]
        fn (
            $action:ident : $action_type:path
        ) -> $ret_action_type:ty [$($w:tt)*] $g:block
    ) => {
        quack_action! {
            $this : $this_type [$($t),*]
            fn [$($t),*] ($action : $action_type) -> $ret_action_type [$($w)*] $g
        }
    }
}

#[macro_export]
macro_rules! quack {
    (
        $this:ident : $this_type:ident $t:tt
        get:
        $(fn $([$($u_get:tt),*])* (
        ) -> $get_prop_type:path [$($w_get:tt)*] $e:block)*
        set:
        $(fn $([$($u_set:tt),*])* (
            $val:ident : $set_prop_type:path
        ) [$($w_set:tt)*] $f:block)*
        action:
        $(fn $([$($u_action:tt),*])* (
            $action:ident : $action_type:path
        ) -> $ret_action_type:ty [$($w_action:tt)*] $g:block)*
    ) => {
        $(quack_get!{
            $this : $this_type $t
            fn $([$($u_get),*])* () -> $get_prop_type [$($w_get)*] $e
        })*
        $(quack_set!{
            $this: $this_type $t
            fn $([$($u_set),*])* ($val : $set_prop_type) [$($w_set)*] $f
        })*
        $(quack_action!{
            $this: $this_type $t
            fn $([$($u_action),*])* (
                $action : $action_type
            ) -> $ret_action_type [$($w_action)*] $g
        })*
    };
}

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

    pub struct Foo<'a, 'b, A, B> {
        x: i32,
        y: i32,
    }

    impl<'a, 'b, A, B> Foo<'a, 'b, A, B> {
        pub fn new() -> Foo<'a, 'b, A, B> {
            Foo { x: 0, y: 0 }
        }
    }

    pub struct X<'a>(pub i32);
    pub struct Y<A>(pub i32);
    pub struct IncX;
    #[allow(dead_code)]
    pub struct IncY<'c>;

    quack! {
        this: Foo['a, 'b, A, B]
        get:
            fn () -> X<'a> [] { assert!(true); X(this.x) }
            fn () -> Y<A> [] { Y(this.y) }
        set:
            fn (x: X<'a>) [] { this.x = x.0 }
            fn (y: Y<A>) [] { this.y = y.0 }
        action:
            fn (__: IncX) -> () [] { this.x += 1 }
            fn ['a, 'b, 'c, A, B] (__: IncY<'c>) -> () [where 'c: 'a] { this.y += 1 }
    }

    pub struct Bar;

    #[test]
    fn test_foo() {
        let mut foo: Foo<Bar, Bar> = Foo::new().set(X(1));
        let X(x) = foo.get();
        assert_eq!(x, 1);
        foo.action(IncX);
        let X(x) = foo.get();
        assert_eq!(x, 2);
    }
}
<commit_msg>Fix tests.<commit_after>#![deny(missing_docs)]
#![unstable]

//! A library for setting current values for stack scope,
//! such as application structure.

pub use get::Get;
pub use set::Set;
pub use action::Action;

mod refcell;
mod get;
mod set;
mod action;

/// Something that can be set at an object.
///
/// Must be implemented on a `(Property, Object)`
#[unstable]
pub trait SetAt: Pair {
    /// Modify `F` with self.
    fn set_at(
        val: <Self as Pair>::Data,
        obj: &mut <Self as Pair>::Object
    );
}

/// Something that can be retrieved from another object.
#[unstable]
pub trait GetFrom: Pair {
    /// Gets value from object.
    fn get_from(
        obj: &<Self as Pair>::Object
    ) -> <Self as Pair>::Data;
}

/// Does something to an object.
#[unstable]
pub trait ActOn<T>: Pair {
    /// Does something to an object.
    fn act_on(
        action: <Self as Pair>::Data,
        obj: &mut <Self as Pair>::Object
    ) -> T;
}

/// Used to reduce the need for associated types.
pub trait Pair: std::marker::PhantomFn<Self> {
    type Data;
    type Object;
}

impl<T, U> Pair for (T, U) {
    type Data = T;
    type Object = U;
}

/// Used to work around limits in macro syntax.
#[macro_export]
macro_rules! quack_macro_items { ($($x:item)+) => ($($x)+) }

#[macro_export]
macro_rules! quack_get {
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn [$($u:tt),*] () -> $get_prop_type:path [$($w:tt)*] $e:block
    ) => {quack_macro_items!{
        impl<$($u),*> $crate::GetFrom for ($get_prop_type, $this_type<$($t),*>)
            $($w)*
        {
            #[allow(unused_variables)]
            #[inline(always)]
            fn get_from($this: &$this_type<$($t),*>) -> $get_prop_type {
                $e
            }
        }
    }};
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn () -> $get_prop_type:path [$($w:tt)*] $e:block
    ) => {
        quack_get! {
            $this : $this_type [$($t),*]
            fn [$($t),*] () -> $get_prop_type [$($w)*] $e
        }
    }
}

#[macro_export]
macro_rules! quack_set {
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn [$($u:tt),*] ($val:ident : $set_prop_type:path) [$($w:tt)*] $f:block
    ) => {quack_macro_items!{
        impl<$($u),*> $crate::SetAt for ($set_prop_type, $this_type<$($t),*>)
            $($w)*
        {
            #[allow(unused_variables)]
            #[inline(always)]
            fn set_at($val : $set_prop_type, $this : &mut $this_type<$($t),*>) {
                $f
            }
        }
    }};
    (
        $this:ident : $this_type:ident [$($t:tt),*]
        fn ($val:ident : $set_prop_type:path) [$($w:tt)*] $f:block
    ) => {
        quack_set! {
            $this : $this_type [$($t),*]
            fn [$($t),*] ($val : $set_prop_type) [$($w)*] $f
        }
    }
}

#[macro_export]
macro_rules! quack_action {
    (
        $this: ident : $this_type:ident [$($t:tt),*]
        fn [$($u:tt),*] (
            $action:ident : $action_type:path
        ) -> $ret_action_type:ty [$($w:tt)*] $g:block
    ) => {quack_macro_items!{
        impl<$($u),*> $crate::ActOn<$ret_action_type>
        for ($action_type, $this_type<$($t),*>)
            $($w)*
        {
            #[allow(unused_variables)]
            #[inline(always)]
            fn act_on(
                $action : $action_type,
                $this: &mut $this_type<$($t),*>
            ) -> $ret_action_type {
                $g
            }
        }
    }};
    (
        $this: ident : $this_type:ident [$($t:tt),*]
        fn (
            $action:ident : $action_type:path
        ) -> $ret_action_type:ty [$($w:tt)*] $g:block
    ) => {
        quack_action! {
            $this : $this_type [$($t),*]
            fn [$($t),*] ($action : $action_type) -> $ret_action_type [$($w)*] $g
        }
    }
}

#[macro_export]
macro_rules! quack {
    (
        $this:ident : $this_type:ident $t:tt
        get:
        $(fn $([$($u_get:tt),*])* (
        ) -> $get_prop_type:path [$($w_get:tt)*] $e:block)*
        set:
        $(fn $([$($u_set:tt),*])* (
            $val:ident : $set_prop_type:path
        ) [$($w_set:tt)*] $f:block)*
        action:
        $(fn $([$($u_action:tt),*])* (
            $action:ident : $action_type:path
        ) -> $ret_action_type:ty [$($w_action:tt)*] $g:block)*
    ) => {
        $(quack_get!{
            $this : $this_type $t
            fn $([$($u_get),*])* () -> $get_prop_type [$($w_get)*] $e
        })*
        $(quack_set!{
            $this: $this_type $t
            fn $([$($u_set),*])* ($val : $set_prop_type) [$($w_set)*] $f
        })*
        $(quack_action!{
            $this: $this_type $t
            fn $([$($u_action),*])* (
                $action : $action_type
            ) -> $ret_action_type [$($w_action)*] $g
        })*
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::marker::{ PhantomData };

    pub struct Foo<'a, 'b, A, B> {
        x: i32,
        y: i32,
        _marker_lifetime_a: PhantomData<&'a ()>,
        _marker_lifetime_b: PhantomData<&'b ()>,
        _marker_a: PhantomData<A>,
        _marker_b: PhantomData<B>,
    }

    impl<'a, 'b, A, B> Foo<'a, 'b, A, B> {
        pub fn new() -> Foo<'a, 'b, A, B> {
            Foo { _marker_lifetime_a: PhantomData,
                  _marker_lifetime_b: PhantomData,
                  _marker_a: PhantomData,
                  _marker_b: PhantomData,
                  x: 0, y: 0 }
        }
    }

    pub struct X<'a>(pub i32, PhantomData<&'a ()>);
    pub struct Y<A>(pub i32, PhantomData<A>);
    pub struct IncX;
    #[allow(dead_code)]
    pub struct IncY<'c>(PhantomData<&'c ()>);

    quack! {
        this: Foo['a, 'b, A, B]
        get:
            fn () -> X<'a> [] { assert!(true); X(this.x, PhantomData) }
            fn () -> Y<A> [] { Y(this.y, PhantomData) }
        set:
            fn (x: X<'a>) [] { this.x = x.0 }
            fn (y: Y<A>) [] { this.y = y.0 }
        action:
            fn (__: IncX) -> () [] { this.x += 1 }
            fn ['a, 'b, 'c, A, B] (__: IncY<'c>) -> () [where 'c: 'a] { this.y += 1 }
    }

    pub struct Bar;

    #[test]
    fn test_foo() {
        let mut foo: Foo<Bar, Bar> = Foo::new().set(X(1, PhantomData));
        let X(x,_) = foo.get();
        assert_eq!(x, 1);
        foo.action(IncX);
        let X(x,_) = foo.get();
        assert_eq!(x, 2);
    }
}
<|endoftext|>


<commit_before>//! Txtdist is small utility crate for calculating the distance between two strings.

/*
#![feature(test)]
extern crate test;
*/

use std::ops::{ Index, IndexMut };
use std::collections::BTreeMap;
use std::cmp::min;

// A simple wrapper around vec so we can get contiguous but index it like it's 2D array.
struct N2Array<T> {
    y_size: usize,
    buf: Vec<T>
}

impl<T: Clone> N2Array<T> {
    fn new(x: usize, y: usize, value: T) -> N2Array<T> {
        N2Array { y_size: y, buf: vec![value; x * y] }
    }
}

impl<T> Index<(usize, usize)> for N2Array<T> {
    type Output = T;

    #[inline]
    fn index<'a>(&'a self, (x, y): (usize, usize)) -> &'a T {
        &self.buf[(x * self.y_size) + y]
    }
}

impl<T> IndexMut<(usize, usize)> for N2Array<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, (x, y): (usize, usize)) -> &'a mut T {
        &mut self.buf[(x * self.y_size) + y]
    }
}

/// Calculate the distance between two strings using the levenshtein algorithm.
///
/// > Levenshtein distance is a string metric for measuring the difference between two sequences.
/// > Informally, the Levenshtein distance between two words is the minimum number of single-character edits
/// > (i.e. insertions, deletions or substitutions) required to change one word into the other.
/// [wikipedia](http://en.wikipedia.org/wiki/Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::levenshtein;
///
/// let distance = levenshtein("an act", "a cat");
/// assert_eq!(distance, 3)
/// ```
pub fn levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    let mut matrix = N2Array::new(n+1, m+1, 0);

    for i in 1..n+1 {
        matrix[(i, 0)] = i;
    }

    for i in 1..m+1 {
        matrix[(0, i)] = i;
    }

    for (row, char_s) in source.chars().enumerate() {
        let row = row + 1;

        for (col, char_t) in target.chars().enumerate() {
            let col = col + 1;
            if char_s == char_t {
                matrix[(row, col)] = matrix[(row-1, col-1)];
            } else {
                matrix[(row, col)] = min(matrix[(row-1, col)]   + 1,
                                     min(matrix[(row, col-1)]   + 1,
                                         matrix[(row-1, col-1)] + 1));
            }
        }
    }

    matrix[(n, m)] as u32
}

/// Calculate the distance between two strings using the damerau levenshtein algorithm.
///
/// > The Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein)
/// > is a distance (string metric) between two strings, i.e., finite sequence of symbols,
/// > given by counting the minimum number of operations needed to transform one string into the other,
/// > where an operation is defined as an insertion, deletion, or substitution of a single character,
/// > or a transposition of two adjacent characters.
/// [wikipedia](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::damerau_levenshtein;
///
/// let distance = damerau_levenshtein("an act", "a cat");
/// assert_eq!(distance, 2)
/// ```
pub fn damerau_levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let inf = n + m;
    let mut matrix = N2Array::new(n+2, m+2, 0);

    matrix[(0, 0)] = inf;
    for i in 0..n+1 {
        matrix[(i+1, 0)] = inf;
        matrix[(i+1, 1)] = i;
    }
    for j in 0..m+1 {
        matrix[(0, j+1)] = inf;
        matrix[(1, j+1)] = j;
    };

    let mut last_row = BTreeMap::new();

    for (row, char_s) in source.chars().enumerate() {
        let mut last_match_col = 0;
        let row = row + 1;

        for (col, char_t) in target.chars().enumerate() {
            let col = col + 1;
            let last_match_row = *last_row.get(&char_t).unwrap_or(&0);
            let cost = if char_s == char_t { 0 } else { 1 };

            let dist_add = matrix[(row, col+1)] + 1;
            let dist_del = matrix[(row+1, col)] + 1;
            let dist_sub = matrix[(row, col)] + cost;
            let dist_trans = matrix[(last_match_row, last_match_col)]
                            + (row - last_match_row - 1) + 1
                            + (col - last_match_col - 1);

            let dist = min(min(dist_add, dist_del),
                           min(dist_sub, dist_trans));

            matrix[(row+1, col+1)] = dist;

            if cost == 0 {
                last_match_col = col;
            }
        }

        last_row.insert(char_s.clone(), row);
    }

    matrix[(n+1, m+1)] as u32
}

#[cfg(test)]
mod tests {
    use super::*;
    //use test::Bencher;

    #[test]
    fn test_levenschtein() {
        let distance = levenshtein("kitten", "sitting");
        assert_eq!(distance, 3);

        let distance = levenshtein("saturday", "sunday");
        assert_eq!(distance, 3);

        let distance = levenshtein("an act", "a cat");
        assert_eq!(distance, 3);

        let distance = levenshtein("", "AA");
        assert_eq!(distance, 2);

        let distance = levenshtein("string", "string");
        assert_eq!(distance, 0);
    }

    #[test]
    fn test_damerau_levenschtein() {
        let distance = damerau_levenshtein("CA", "ABC");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("an act", "a cat");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("", "a cat");
        assert_eq!(distance, 5);

        let distance = damerau_levenshtein("MERCEDES-BENS", "MERCEDES-BENZ");
        assert_eq!(distance, 1);

        let distance = damerau_levenshtein("", "");
        assert_eq!(distance, 0);

        let distance = damerau_levenshtein("some string", "some string");
        assert_eq!(distance, 0);
    }
    /*
    #[bench]
    fn bench_damerau_levenschtein(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same_length(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string12", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_empty(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("some string", "some string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_long(b: &mut Bencher) {
        let text1 = r"
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Curabitur in maximus lectus. Nulla ornare metus sit amet congue feugiat.
            Nunc sit amet mollis lectus. Integer vel mollis lacus. Nullam molestie justo dui,
            vitae vulputate augue molestie nec. Sed non urna at augue aliquet feugiat eu ut diam.
            Nam dignissim semper est, et dignissim lectus. Curabitur luctus mattis mauris. Lorem ipsum dolor sit amet,
            consectetur adipiscing elit. Morbi at neque a leo mollis bibendum.

            Pellentesque mattis lacus et arcu fermentum, non volutpat orci tincidunt.
            Nam et blandit magna. Vivamus dignissim in nisi at fringilla.
            Donec pretium justo justo, vel placerat urna ultricies sit amet. Sed erat felis,
            commodo non laoreet in, aliquet a lacus. Curabitur condimentum enim elit.
            Curabitur tincidunt ligula ut quam rutrum fermentum. Donec laoreet mattis porttitor.
            Etiam ornare urna in congue vehicula. Nam non metus sapien.
            Morbi vel turpis volutpat, hendrerit augue sed, mattis est.
            Sed auctor nibh lorem, vitae sagittis nibh egestas eget.
        ";

        let text2 = r"
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Curabitur in maximus lectus. Nulla ornare metus sit amet congue feugiat.
            Nunc sit amet mollis lectus. Integer vel mollis lacus. Nullam molestie justo dui,
            vitae vulputate augue molestie nec. Sed non urna at augue aliquet feugiat eu ut diam.
            Nam dignissim semper est, et eignissim lectus. Curabitur luctus mattis mauris. Lorem ipsum dolor sit amet,
            consectetur adipiscing elit. Morbi at neque a leo mollis bibendum.

            Pellentesque mattis lacus et arcu fermentum, non volutpat orci tincidunt.
            Nam et blandit magna. Vivamus dignmssim in nisi at fringilla.
            Donec pretium justo justo, vel placerat urna ultricies sit amet. Sed erat felis,
            commodo non laoreet in, aliquet a lacus. Curabitur condimentum enim elit.
            Curabitur tincidunt ligula ut quam rutrum fermentum. Donec laoreet mattis porttitor.
        ";

        b.iter(|| damerau_levenshtein(text1, text2))
    }*/
}
<commit_msg>Degenerate cases<commit_after>//! Txtdist is small utility crate for calculating the distance between two strings.

/*
#![feature(test)]
extern crate test;
*/

use std::ops::{ Index, IndexMut };
use std::collections::BTreeMap;
use std::cmp::min;

// A simple wrapper around vec so we can get contiguous but index it like it's 2D array.
struct N2Array<T> {
    y_size: usize,
    buf: Vec<T>
}

impl<T: Clone> N2Array<T> {
    fn new(x: usize, y: usize, value: T) -> N2Array<T> {
        N2Array { y_size: y, buf: vec![value; x * y] }
    }
}

impl<T> Index<(usize, usize)> for N2Array<T> {
    type Output = T;

    #[inline]
    fn index<'a>(&'a self, (x, y): (usize, usize)) -> &'a T {
        &self.buf[(x * self.y_size) + y]
    }
}

impl<T> IndexMut<(usize, usize)> for N2Array<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, (x, y): (usize, usize)) -> &'a mut T {
        &mut self.buf[(x * self.y_size) + y]
    }
}

/// Calculate the distance between two strings using the levenshtein algorithm.
///
/// > Levenshtein distance is a string metric for measuring the difference between two sequences.
/// > Informally, the Levenshtein distance between two words is the minimum number of single-character edits
/// > (i.e. insertions, deletions or substitutions) required to change one word into the other.
/// [wikipedia](http://en.wikipedia.org/wiki/Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::levenshtein;
///
/// let distance = levenshtein("an act", "a cat");
/// assert_eq!(distance, 3)
/// ```
pub fn levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let mut matrix = N2Array::new(n+1, m+1, 0);

    for i in 1..n+1 {
        matrix[(i, 0)] = i;
    }

    for i in 1..m+1 {
        matrix[(0, i)] = i;
    }

    for (row, char_s) in source.chars().enumerate() {
        let row = row + 1;

        for (col, char_t) in target.chars().enumerate() {
            let col = col + 1;
            if char_s == char_t {
                matrix[(row, col)] = matrix[(row-1, col-1)];
            } else {
                matrix[(row, col)] = min(matrix[(row-1, col)]   + 1,
                                     min(matrix[(row, col-1)]   + 1,
                                         matrix[(row-1, col-1)] + 1));
            }
        }
    }

    matrix[(n, m)] as u32
}

/// Calculate the distance between two strings using the damerau levenshtein algorithm.
///
/// > The Damerau–Levenshtein distance (named after Frederick J. Damerau and Vladimir I. Levenshtein)
/// > is a distance (string metric) between two strings, i.e., finite sequence of symbols,
/// > given by counting the minimum number of operations needed to transform one string into the other,
/// > where an operation is defined as an insertion, deletion, or substitution of a single character,
/// > or a transposition of two adjacent characters.
/// [wikipedia](http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance)
///
/// # Example
///
/// ```rust
/// use txtdist::damerau_levenshtein;
///
/// let distance = damerau_levenshtein("an act", "a cat");
/// assert_eq!(distance, 2)
/// ```
pub fn damerau_levenshtein(source: &str, target: &str) -> u32 {
    let (n, m) = (source.len(), target.len());

    if n == 0 { return m as u32; }
    if m == 0 { return n as u32; }

    if n == m && source == target {
        return 0;
    }

    let inf = n + m;
    let mut matrix = N2Array::new(n+2, m+2, 0);

    matrix[(0, 0)] = inf;
    for i in 0..n+1 {
        matrix[(i+1, 0)] = inf;
        matrix[(i+1, 1)] = i;
    }
    for j in 0..m+1 {
        matrix[(0, j+1)] = inf;
        matrix[(1, j+1)] = j;
    };

    let mut last_row = BTreeMap::new();

    for (row, char_s) in source.chars().enumerate() {
        let mut last_match_col = 0;
        let row = row + 1;

        for (col, char_t) in target.chars().enumerate() {
            let col = col + 1;
            let last_match_row = *last_row.get(&char_t).unwrap_or(&0);
            let cost = if char_s == char_t { 0 } else { 1 };

            let dist_add = matrix[(row, col+1)] + 1;
            let dist_del = matrix[(row+1, col)] + 1;
            let dist_sub = matrix[(row, col)] + cost;
            let dist_trans = matrix[(last_match_row, last_match_col)]
                            + (row - last_match_row - 1) + 1
                            + (col - last_match_col - 1);

            let dist = min(min(dist_add, dist_del),
                           min(dist_sub, dist_trans));

            matrix[(row+1, col+1)] = dist;

            if cost == 0 {
                last_match_col = col;
            }
        }

        last_row.insert(char_s.clone(), row);
    }

    matrix[(n+1, m+1)] as u32
}

#[cfg(test)]
mod tests {
    use super::*;
    //use test::Bencher;

    #[test]
    fn test_levenschtein() {
        let distance = levenshtein("kitten", "sitting");
        assert_eq!(distance, 3);

        let distance = levenshtein("saturday", "sunday");
        assert_eq!(distance, 3);

        let distance = levenshtein("an act", "a cat");
        assert_eq!(distance, 3);

        let distance = levenshtein("", "AA");
        assert_eq!(distance, 2);

        let distance = levenshtein("string", "string");
        assert_eq!(distance, 0);

        let distance = levenshtein("", "a cat");
        assert_eq!(distance, 5);
    }

    #[test]
    fn test_damerau_levenschtein() {
        let distance = damerau_levenshtein("CA", "ABC");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("an act", "a cat");
        assert_eq!(distance, 2);

        let distance = damerau_levenshtein("", "a cat");
        assert_eq!(distance, 5);

        let distance = damerau_levenshtein("MERCEDES-BENS", "MERCEDES-BENZ");
        assert_eq!(distance, 1);

        let distance = damerau_levenshtein("", "");
        assert_eq!(distance, 0);

        let distance = damerau_levenshtein("some string", "some string");
        assert_eq!(distance, 0);
    }
    /*
    #[bench]
    fn bench_damerau_levenschtein(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same_length(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("one string12", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_empty(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("", "other string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_same(b: &mut Bencher) {
        b.iter(|| damerau_levenshtein("some string", "some string"));
    }

    #[bench]
    fn bench_damerau_levenschtein_long(b: &mut Bencher) {
        let text1 = r"
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Curabitur in maximus lectus. Nulla ornare metus sit amet congue feugiat.
            Nunc sit amet mollis lectus. Integer vel mollis lacus. Nullam molestie justo dui,
            vitae vulputate augue molestie nec. Sed non urna at augue aliquet feugiat eu ut diam.
            Nam dignissim semper est, et dignissim lectus. Curabitur luctus mattis mauris. Lorem ipsum dolor sit amet,
            consectetur adipiscing elit. Morbi at neque a leo mollis bibendum.

            Pellentesque mattis lacus et arcu fermentum, non volutpat orci tincidunt.
            Nam et blandit magna. Vivamus dignissim in nisi at fringilla.
            Donec pretium justo justo, vel placerat urna ultricies sit amet. Sed erat felis,
            commodo non laoreet in, aliquet a lacus. Curabitur condimentum enim elit.
            Curabitur tincidunt ligula ut quam rutrum fermentum. Donec laoreet mattis porttitor.
            Etiam ornare urna in congue vehicula. Nam non metus sapien.
            Morbi vel turpis volutpat, hendrerit augue sed, mattis est.
            Sed auctor nibh lorem, vitae sagittis nibh egestas eget.
        ";

        let text2 = r"
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            Curabitur in maximus lectus. Nulla ornare metus sit amet congue feugiat.
            Nunc sit amet mollis lectus. Integer vel mollis lacus. Nullam molestie justo dui,
            vitae vulputate augue molestie nec. Sed non urna at augue aliquet feugiat eu ut diam.
            Nam dignissim semper est, et eignissim lectus. Curabitur luctus mattis mauris. Lorem ipsum dolor sit amet,
            consectetur adipiscing elit. Morbi at neque a leo mollis bibendum.

            Pellentesque mattis lacus et arcu fermentum, non volutpat orci tincidunt.
            Nam et blandit magna. Vivamus dignmssim in nisi at fringilla.
            Donec pretium justo justo, vel placerat urna ultricies sit amet. Sed erat felis,
            commodo non laoreet in, aliquet a lacus. Curabitur condimentum enim elit.
            Curabitur tincidunt ligula ut quam rutrum fermentum. Donec laoreet mattis porttitor.
        ";

        b.iter(|| damerau_levenshtein(text1, text2))
    }*/
}
<|endoftext|>


<commit_before>extern crate libc;

use wiredtiger_def::{WT_CONNECTION,WT_SESSION,WT_CURSOR,
  wiredtiger_open,wiredtiger_strerror};

use self::libc::{c_int, c_char};
use std::ffi::{CStr,CString};
use std::{ptr,mem,str};
use std::ops::{Drop};

unsafe fn string_from_ptr(ptr: *const c_char) -> String {
  let slice = CStr::from_ptr(ptr);
  str::from_utf8(slice.to_bytes()).unwrap().to_string()
}

unsafe fn get_error(code: c_int) -> String {
  string_from_ptr(wiredtiger_strerror(code))
}

fn c_str(val: &str) -> CString{
  CString::new(val).unwrap()
}

pub fn open() -> Result<Connection, String> {
  let action = c_str("create");
  unsafe {
    let mut connection: *mut WT_CONNECTION = mem::uninitialized();

    let ret = wiredtiger_open(ptr::null(),
      ptr::null_mut(),
      action.as_ptr(),
      &mut connection);

    if ret != 0{
      return Err(get_error(ret));
    }

    Ok(Connection{
      wt_con: connection
    })
  }
}

pub struct Connection {
  wt_con: *mut WT_CONNECTION
}

pub struct Session {
  wt_session: *mut WT_SESSION
}

pub struct Cursor {
  wt_cursor: *mut WT_CURSOR
}

pub struct KeyValuePair {
  pub key: String,
  pub value: String
}

impl Drop for Connection {
  fn drop(&mut self) {
    unsafe{
      match (*self.wt_con).close {
        Some(close) => { close(self.wt_con, ptr::null_mut()); }
        None => ()
      };
    }
  }
}

impl Connection {
  pub fn open_session(&mut self) -> Result<Session, String>{
    unsafe{
      match (*self.wt_con).open_session {
        Some(open_session) => {
          let mut session: *mut WT_SESSION = mem::uninitialized();
          let ret = open_session(self.wt_con, ptr::null_mut(),
            ptr::null_mut(), &mut session);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(Session{
            wt_session: session
          })
        },
        None => Err("Failed to get open_session".to_string())
      }
    }
  }
}

impl Cursor {
  fn set_key(&mut self, key: &CString) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).set_key {
        Some(set_key) => {
          set_key(self.wt_cursor, key.as_ptr());
          Ok(())
        }
        None => Err("Failed to get set_key".to_string())
      }
    }
  }

  fn set_value(&mut self, value: &CString) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).set_value {
        Some(set_value) => {
          set_value(self.wt_cursor, value.as_ptr());
          Ok(())
        }
        None => Err("Failed to get set_value".to_string())
      }
    }
  }

  fn insert(&mut self) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).insert {
        Some(insert) => {
          let ret = insert(self.wt_cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get insert".to_string())
      }
    }
  }

  pub fn insert_pair(&mut self, key: &str, value: &str) -> Result<(), String>{
    let k = c_str(key);
    let v = c_str(value);
    try!(self.set_key(&k));
    try!(self.set_value(&v));
    try!(self.insert());
    Ok(())
  }

  pub fn reset(&mut self) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).reset {
        Some(reset) => {
          let ret = reset(self.wt_cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get reset".to_string())
      }
    }
  }

  pub fn next(&mut self) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).next {
        Some(next) => {
          let ret = next(self.wt_cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get next".to_string())
      }
    }
  }

  pub fn get_key(&mut self) -> Result<String, String>{
    unsafe {
      match(*self.wt_cursor).get_key {
        Some(get_key) => {
          let key: *mut c_char = mem::uninitialized();
          let ret = get_key(self.wt_cursor, &key);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(string_from_ptr(key))
        }
        None => Err("Failed to get get_key".to_string())
      }
    }
  }

  pub fn get_value(&mut self) -> Result<String, String>{
    unsafe {
      match(*self.wt_cursor).get_value {
        Some(get_value) => {
          let value: *mut c_char = mem::uninitialized();
          let ret = get_value(self.wt_cursor, &value);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(string_from_ptr(value))
        }
        None => Err("Failed to get get_value".to_string())
      }
    }
  }
}

impl Session {
  pub fn create_table(&mut self, name: &str) -> Result<(), String> {
    unsafe {
      match(*self.wt_session).create {
        Some(create) => {
          let full_command = &format!("table:{0}", name);
          let ret = create(self.wt_session,
            c_str(full_command).as_ptr(),
            c_str("key_format=S,value_format=S").as_ptr());

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get create".to_string())
      }
    }
  }

  pub fn open_cursor(&mut self, table_name: &str) -> Result<Cursor, String>{
    unsafe {
      match(*self.wt_session).open_cursor {
        Some(open_cursor) => {
          let mut cursor: *mut WT_CURSOR = mem::uninitialized();
          let cursor_uid = &format!("table:{0}", table_name);
          let ret = open_cursor(self.wt_session,
            c_str(cursor_uid).as_ptr(),
            ptr::null_mut(),
            ptr::null_mut(),
            &mut cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(Cursor{
            wt_cursor: cursor
          })
        }
        None => Err("Failed to get open_cursor".to_string())
      }
    }
  }
}

impl Iterator for Cursor {
  type Item = KeyValuePair;
  fn next(&mut self) -> Option<KeyValuePair> {
    match self.next() {
      Ok(_) => {
        match (self.get_key(), self.get_value()){
          (Ok(key), Ok(value)) => Some(KeyValuePair{
            key: key,
            value: value
          }),
          _ => None
        }
      }
      Err(_) => None
    }
  }
}<commit_msg>Initial doc and drop traits for cursor and session<commit_after>extern crate libc;

use wiredtiger_def::{WT_CONNECTION,WT_SESSION,WT_CURSOR,
  wiredtiger_open,wiredtiger_strerror};

use self::libc::{c_int, c_char};
use std::ffi::{CStr,CString};
use std::{ptr,mem,str};
use std::ops::{Drop};

unsafe fn string_from_ptr(ptr: *const c_char) -> String {
  let slice = CStr::from_ptr(ptr);
  str::from_utf8(slice.to_bytes()).unwrap().to_string()
}

unsafe fn get_error(code: c_int) -> String {
  string_from_ptr(wiredtiger_strerror(code))
}

fn c_str(val: &str) -> CString{
  CString::new(val).unwrap()
}

/// Opens a Wired Tiger connection and returns a new `Connection`.
/// # Examples
/// ```
/// match wiredtiger::open() {
///   Ok(mut connection) => {
///     // work with connection
///   }
///   Err(message) => {
///     // handle error
///   }
/// }
/// ```
/// # Failures
/// The function returns `Err(message)` if the connection failed to open.
pub fn open() -> Result<Connection, String> {
  let action = c_str("create");
  unsafe {
    let mut connection: *mut WT_CONNECTION = mem::uninitialized();

    let ret = wiredtiger_open(ptr::null(),
      ptr::null_mut(),
      action.as_ptr(),
      &mut connection);

    if ret != 0{
      return Err(get_error(ret));
    }

    Ok(Connection{
      wt_con: connection
    })
  }
}

/// Represents a Wired Tiger connection.
pub struct Connection {
  wt_con: *mut WT_CONNECTION
}

/// Represents a Wired Tiger session.
pub struct Session {
  wt_session: *mut WT_SESSION
}

/// Represents a Wired Tiger cursor.
pub struct Cursor {
  wt_cursor: *mut WT_CURSOR
}

/// A key value pair that can be used for Wired Tiger tables with that structure
pub struct KeyValuePair {
  pub key: String,
  pub value: String
}

impl Drop for Connection {
  /// When the connection is dropped the underlying connection is closed.
  /// All other components related to the connection are no longer usable.
  fn drop(&mut self) {
    unsafe{
      match (*self.wt_con).close {
        Some(close) => { close(self.wt_con, ptr::null_mut()); }
        None => ()
      };
    }
  }
}

impl Connection {
  /// Opens a Wired Tiger session and returns a `Session`.
  /// # Examples
  /// ```
  /// match wiredtiger::open().unwrap().open_session() {
  ///   Ok(session) => {
  ///     // work with session
  ///   },
  ///   Err(message) => {
  ///     // handle error
  ///   }
  /// }
  /// ```
  /// # Failures
  /// The function returns `Err(message)` if the session failed to open.
  pub fn open_session(&mut self) -> Result<Session, String>{
    unsafe{
      match (*self.wt_con).open_session {
        Some(open_session) => {
          let mut session: *mut WT_SESSION = mem::uninitialized();
          let ret = open_session(self.wt_con, ptr::null_mut(),
            ptr::null_mut(), &mut session);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(Session{
            wt_session: session
          })
        },
        None => Err("Failed to get open_session".to_string())
      }
    }
  }
}

impl Cursor {
  fn set_key(&mut self, key: &CString) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).set_key {
        Some(set_key) => {
          set_key(self.wt_cursor, key.as_ptr());
          Ok(())
        }
        None => Err("Failed to get set_key".to_string())
      }
    }
  }

  fn set_value(&mut self, value: &CString) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).set_value {
        Some(set_value) => {
          set_value(self.wt_cursor, value.as_ptr());
          Ok(())
        }
        None => Err("Failed to get set_value".to_string())
      }
    }
  }

  fn insert(&mut self) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).insert {
        Some(insert) => {
          let ret = insert(self.wt_cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get insert".to_string())
      }
    }
  }

  /// Inserts the `value` for the given `key` in the table related to the `Cursor`.
  /// # Examples
  /// ```
  /// cursor.insert_pair("1", "John Doe");
  /// ```
  /// # Failures
  /// The function returns `Err(message)` if:
  /// * The `key` fails to be set for the cursor
  /// * The `value` fails to be set for the cursor
  /// * The pair fail to be inserted
  pub fn insert_pair(&mut self, key: &str, value: &str) -> Result<(), String>{
    let k = c_str(key);
    let v = c_str(value);
    try!(self.set_key(&k));
    try!(self.set_value(&v));
    try!(self.insert());
    Ok(())
  }

  /// Places the cursor at its initial position
  /// # Examples
  /// ```
  /// cursor.reset();
  /// ```
  /// # Failures
  /// The function returns `Err(message)` if the cursor could not be reset
  pub fn reset(&mut self) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).reset {
        Some(reset) => {
          let ret = reset(self.wt_cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get reset".to_string())
      }
    }
  }

  fn next(&mut self) -> Result<(), String>{
    unsafe {
      match(*self.wt_cursor).next {
        Some(next) => {
          let ret = next(self.wt_cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get next".to_string())
      }
    }
  }

  fn get_key(&mut self) -> Result<String, String>{
    unsafe {
      match(*self.wt_cursor).get_key {
        Some(get_key) => {
          let key: *mut c_char = mem::uninitialized();
          let ret = get_key(self.wt_cursor, &key);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(string_from_ptr(key))
        }
        None => Err("Failed to get get_key".to_string())
      }
    }
  }

  fn get_value(&mut self) -> Result<String, String>{
    unsafe {
      match(*self.wt_cursor).get_value {
        Some(get_value) => {
          let value: *mut c_char = mem::uninitialized();
          let ret = get_value(self.wt_cursor, &value);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(string_from_ptr(value))
        }
        None => Err("Failed to get get_value".to_string())
      }
    }
  }
}

impl Session {
  /// Creates a table named `name` to hold key/value pairs.
  /// # Examples
  /// ```
  /// session.create_table("users");
  /// ```
  /// # Failures
  /// The function returns `Err(message)` if the table failed to be created.
  pub fn create_table(&mut self, name: &str) -> Result<(), String> {
    unsafe {
      match(*self.wt_session).create {
        Some(create) => {
          let full_command = &format!("table:{0}", name);
          let ret = create(self.wt_session,
            c_str(full_command).as_ptr(),
            c_str("key_format=S,value_format=S").as_ptr());

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(())
        }
        None => Err("Failed to get create".to_string())
      }
    }
  }

  /// Opens a `Cursor` for the table `table_name` and returns it.
  /// # Examples
  /// ```
  /// session.open_cursor("users");
  /// ```
  /// # Failures
  /// The function returns `Err(message)` if the cursor could not be opened.
  pub fn open_cursor(&mut self, table_name: &str) -> Result<Cursor, String>{
    unsafe {
      match(*self.wt_session).open_cursor {
        Some(open_cursor) => {
          let mut cursor: *mut WT_CURSOR = mem::uninitialized();
          let cursor_uid = &format!("table:{0}", table_name);
          let ret = open_cursor(self.wt_session,
            c_str(cursor_uid).as_ptr(),
            ptr::null_mut(),
            ptr::null_mut(),
            &mut cursor);

          if ret != 0 {
            return Err(get_error(ret));
          }

          Ok(Cursor{
            wt_cursor: cursor
          })
        }
        None => Err("Failed to get open_cursor".to_string())
      }
    }
  }
}

impl Iterator for Cursor {
  type Item = KeyValuePair;
  fn next(&mut self) -> Option<KeyValuePair> {
    match self.next() {
      Ok(_) => {
        match (self.get_key(), self.get_value()){
          (Ok(key), Ok(value)) => Some(KeyValuePair{
            key: key,
            value: value
          }),
          _ => None
        }
      }
      Err(_) => None
    }
  }
}

impl Drop for Cursor {
  /// When the connection is dropped the underlying connection is closed.
  /// All other components related to the connection are no longer usable.
  fn drop(&mut self) {
    unsafe{
      match (*self.wt_cursor).close {
        Some(close) => { close(self.wt_cursor); }
        None => ()
      };
    }
  }
}

impl Drop for Session {
  /// When the connection is dropped the underlying connection is closed.
  /// All other components related to the connection are no longer usable.
  fn drop(&mut self) {
    unsafe{
      match (*self.wt_session).close {
        Some(close) => { close(self.wt_session, ptr::null_mut()); }
        None => ()
      };
    }
  }
}<|endoftext|>