<commit_before>#![crate_name="civet"]
#![crate_type="rlib"]
#![feature(unsafe_destructor, globs)]

extern crate collections;
extern crate conduit;
extern crate libc;
extern crate rustrt;
extern crate semver;
extern crate "civet-sys" as ffi;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult, util, BufferedWriter};
use std::collections::HashMap;

use conduit::{Request, Handler, Extensions, TypeMap};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: uint, minor: uint) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> conduit::Method {
        match self.request_info.method().unwrap() {
            "HEAD" => conduit::Head,
            "GET" => conduit::Get,
            "POST" => conduit::Post,
            "PUT" => conduit::Put,
            "DELETE" => conduit::Delete,
            "PATCH" => conduit::Patch,
            "PURGE" => conduit::Purge,
            "CONNECT" => conduit::Connect,
            "OPTIONS" => conduit::Options,
            "TRACE" => conduit::Trace,
            other @ _ => panic!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> conduit::Scheme {
        if self.request_info.is_ssl() {
            conduit::Https
        } else {
            conduit::Http
        }
    }

    fn host<'a>(&'a self) -> conduit::Host<'a> {
        conduit::HostName(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        None
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request_info.url().unwrap()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    fn content_length(&self) -> Option<uint> {
        get_header(self.conn, "Content-Length").and_then(from_str)
    }

    fn headers<'a>(&'a self) -> &'a conduit::Headers {
        &self.headers as &conduit::Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }

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

pub fn response<S: ToStatusCode, R: Reader + Send>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().unwrap().to_code(),
        headers: headers,
        body: box body as Box<Reader + Send>
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.written = true;
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find<'a>(&'a self, string: &str) -> Option<Vec<&'a str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        HeaderIterator::new(self.conn).collect()
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, Vec<&'a str>)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler + 'static + Sync>)
                            -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufferedWriter::new(connection);

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{}: {}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Reader = &mut *body;
            try!(util::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let handler = box handler;
        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_string())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::io::net::ip::SocketAddr;
    use std::io::net::tcp::TcpStream;
    use std::io::test::next_test_ip4;
    use std::io::{IoResult, MemReader};
    use std::fmt::Show;
    use std::sync::Mutex;
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(addr).unwrap();
        s.write_str(req.trim_left()).unwrap();
        s.read_to_string().unwrap()
    }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                panic!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(());
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(req.headers().find("Foo").unwrap().connect(""));
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().as_slice(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                panic!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                panic!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.as_slice().contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<commit_msg>Update to rust master<commit_after>#![crate_name="civet"]
#![crate_type="rlib"]
#![feature(unsafe_destructor, globs)]

extern crate collections;
extern crate conduit;
extern crate libc;
extern crate rustrt;
extern crate semver;
extern crate "civet-sys" as ffi;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult, util, BufferedWriter};
use std::collections::HashMap;

use conduit::{Request, Handler, Extensions, TypeMap, Method, Scheme, Host};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: uint, minor: uint) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> Method {
        match self.request_info.method().unwrap() {
            "HEAD" => Method::Head,
            "GET" => Method::Get,
            "POST" => Method::Post,
            "PUT" => Method::Put,
            "DELETE" => Method::Delete,
            "PATCH" => Method::Patch,
            "PURGE" => Method::Purge,
            "CONNECT" => Method::Connect,
            "OPTIONS" => Method::Options,
            "TRACE" => Method::Trace,
            other @ _ => panic!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> Scheme {
        if self.request_info.is_ssl() {
            Scheme::Https
        } else {
            Scheme::Http
        }
    }

    fn host<'a>(&'a self) -> Host<'a> {
        Host::Name(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        None
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request_info.url().unwrap()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    fn content_length(&self) -> Option<uint> {
        get_header(self.conn, "Content-Length").and_then(from_str)
    }

    fn headers<'a>(&'a self) -> &'a conduit::Headers {
        &self.headers as &conduit::Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }

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

pub fn response<S: ToStatusCode, R: Reader + Send>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().unwrap().to_code(),
        headers: headers,
        body: box body as Box<Reader + Send>
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.written = true;
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find<'a>(&'a self, string: &str) -> Option<Vec<&'a str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        HeaderIterator::new(self.conn).collect()
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, Vec<&'a str>)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler + 'static + Sync>)
                            -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufferedWriter::new(connection);

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{}: {}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Reader = &mut *body;
            try!(util::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let handler = box handler;
        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_string())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::io::net::ip::SocketAddr;
    use std::io::net::tcp::TcpStream;
    use std::io::test::next_test_ip4;
    use std::io::{IoResult, MemReader};
    use std::fmt::Show;
    use std::sync::Mutex;
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(addr).unwrap();
        s.write_str(req.trim_left()).unwrap();
        s.read_to_string().unwrap()
    }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                panic!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(());
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                let Foo(ref tx) = *self;
                tx.lock().send(req.headers().find("Foo").unwrap().connect(""));
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().as_slice(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                panic!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show + 'static>> {
                panic!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.as_slice().contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new(Arc::new(io));
//! 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

use std::thread;
use std::sync::Arc;
use std::io::Read;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

pub type ServerResult = Result<hyper::server::Listening, hyper::error::Error>;

/// jsonrpc http request handler.
pub struct ServerHandler {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domain: AccessControlAllowOrigin,
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> Self {
		ServerHandler {
			jsonrpc_handler: jsonrpc_handler,
			cors_domain: cors_domain
		}
	}

	fn response_headers(&self) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);
		headers.set(self.cors_domain.clone());
		headers
	}
}

impl hyper::server::Handler for ServerHandler {
	fn handle(&self, mut req: hyper::server::Request, mut res: hyper::server::Response) {
		match req.method {
			Method::Options => {
				*res.headers_mut() = self.response_headers();
			},
			Method::Post => {
				let mut body = String::new();
				if let Err(_) = req.read_to_string(&mut body) {
					// TODO: return proper jsonrpc error instead
					*res.status_mut() = hyper::status::StatusCode::MethodNotAllowed;
					return;
				}
				if let Some(response) = self.jsonrpc_handler.handle_request(&body) {
					*res.headers_mut() = self.response_headers();
					res.send(response.as_ref()).unwrap();
				}
			},
			_ => *res.status_mut() = hyper::status::StatusCode::MethodNotAllowed
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let server = Server::new(Arc::new(io));
/// 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1).unwrap();
/// }
/// ```
pub struct Server {
	jsonrpc_handler: Arc<IoHandler>,
}

impl Server {
	pub fn new(jsonrpc_handler: Arc<IoHandler>) -> Self {
		Server {
			jsonrpc_handler: jsonrpc_handler,
		}
	}

	pub fn start(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) -> ServerResult {
		try!(hyper::Server::http(addr))
      .handle_threads(ServerHandler::new(self.jsonrpc_handler.clone(), cors_domain), threads)
	}

	pub fn start_async(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) -> thread::JoinHandle<ServerResult> {
		let address = addr.to_owned();
		let handler = self.jsonrpc_handler.clone();
		thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || {
			try!(hyper::Server::http(address.as_ref() as &str))
        .handle_threads(ServerHandler::new(handler, cors_domain), threads)
		}).expect("RPC thread spawned")
	}
}
<commit_msg>Fixing formatting<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new(Arc::new(io));
//! 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1);
//! }
//! ```

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

use std::thread;
use std::sync::Arc;
use std::io::Read;
use hyper::header::{Headers, Allow, ContentType, AccessControlAllowHeaders};
use hyper::method::Method;
use unicase::UniCase;
use self::jsonrpc::{IoHandler};

pub use hyper::header::AccessControlAllowOrigin;

pub type ServerResult = Result<hyper::server::Listening, hyper::error::Error>;

/// jsonrpc http request handler.
pub struct ServerHandler {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domain: AccessControlAllowOrigin,
}

impl ServerHandler {
	/// Create new request handler.
	pub fn new(jsonrpc_handler: Arc<IoHandler>, cors_domain: AccessControlAllowOrigin) -> Self {
		ServerHandler {
			jsonrpc_handler: jsonrpc_handler,
			cors_domain: cors_domain
		}
	}

	fn response_headers(&self) -> Headers {
		let mut headers = Headers::new();
		headers.set(
			Allow(vec![
				Method::Options, Method::Post
			])
		);
		headers.set(ContentType::json());
		headers.set(
			AccessControlAllowHeaders(vec![
				UniCase("origin".to_owned()),
				UniCase("content-type".to_owned()),
				UniCase("accept".to_owned()),
			])
		);
		headers.set(self.cors_domain.clone());
		headers
	}
}

impl hyper::server::Handler for ServerHandler {
	fn handle(&self, mut req: hyper::server::Request, mut res: hyper::server::Response) {
		match req.method {
			Method::Options => {
				*res.headers_mut() = self.response_headers();
			},
			Method::Post => {
				let mut body = String::new();
				if let Err(_) = req.read_to_string(&mut body) {
					// TODO: return proper jsonrpc error instead
					*res.status_mut() = hyper::status::StatusCode::MethodNotAllowed;
					return;
				}
				if let Some(response) = self.jsonrpc_handler.handle_request(&body) {
					*res.headers_mut() = self.response_headers();
					res.send(response.as_ref()).unwrap();
				}
			},
			_ => *res.status_mut() = hyper::status::StatusCode::MethodNotAllowed
		}
	}
}

/// jsonrpc http server.
///
/// ```no_run
/// extern crate jsonrpc_core;
/// extern crate jsonrpc_http_server;
///
/// use std::sync::Arc;
/// use jsonrpc_core::*;
/// use jsonrpc_http_server::*;
///
/// struct SayHello;
/// impl MethodCommand for SayHello {
/// 	fn execute(&self, _params: Params) -> Result<Value, Error> {
/// 		Ok(Value::String("hello".to_string()))
/// 	}
/// }
///
/// fn main() {
/// 	let io = IoHandler::new();
/// 	io.add_method("say_hello", SayHello);
/// 	let server = Server::new(Arc::new(io));
/// 	server.start("127.0.0.1:3030", AccessControlAllowOrigin::Null, 1).unwrap();
/// }
/// ```
pub struct Server {
	jsonrpc_handler: Arc<IoHandler>,
}

impl Server {
	pub fn new(jsonrpc_handler: Arc<IoHandler>) -> Self {
		Server {
			jsonrpc_handler: jsonrpc_handler,
		}
	}

	pub fn start(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) -> ServerResult {
		try!(hyper::Server::http(addr))
			.handle_threads(ServerHandler::new(self.jsonrpc_handler.clone(), cors_domain), threads)
	}

	pub fn start_async(&self, addr: &str, cors_domain: AccessControlAllowOrigin, threads: usize) -> thread::JoinHandle<ServerResult> {
		let address = addr.to_owned();
		let handler = self.jsonrpc_handler.clone();
		thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || {
			try!(hyper::Server::http(address.as_ref() as &str))
				.handle_threads(ServerHandler::new(handler, cors_domain), threads)
		}).expect("RPC thread spawned")
	}
}
<|endoftext|>


<commit_before>mod error;
pub mod reader;

#[test]
fn it_works() {
}
<commit_msg>Add `Result<T> `and make `error` module public<commit_after>pub mod error;
pub mod reader;

pub type Result<T> = std::result::Result<T, error::Error>;

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>//! Openapi provides structures and support for serializing and deserializing [openapi](https://github.com/OAI/OpenAPI-Specification) specifications
//!
//! # Examples
//!
//! Typical use deserialing an existing to a persisted spec to rust form or
//! visa versa
//!
//! The hyper client should be configured with tls.
//!
//! ```no_run
//! extern crate openapi;
//!
//! fn main() {
//!   match openapi::from_path("path/to/openapi.yaml") {
//!     Ok(spec) => println!("spec: {:?}", spec),
//!     Err(err) => println!("error: {}", err)
//!   }
//! }
//! ```
//!
//! # Errors
//!
//! Operations typically result in a `openapi::Result` Type which is an alias
//! for Rust's
//! built-in Result with the Err Type fixed to the
//! [openapi::errors::Error](errors/struct.Error.html) enum type. These are
//! provided
//! using [error_chain](https://github.com/brson/error-chain) crate so their
//! shape and behavior should be consistent and familiar to existing
//! error_chain users.
//!
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::Path, result::Result as StdResult};

pub mod error;
pub mod v2;
pub mod v3_0;

pub use error::Error;

const MINIMUM_OPENAPI30_VERSION: &str = ">= 3.0";

pub type Result<T> = StdResult<T, Error>;

/// Supported versions of the OpenApi.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum OpenApi {
    /// Version 2.0 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/2.0.md)
    /// for more information.
    V2(v2::Spec),

    /// Version 3.0.1 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/3.0.1.md)
    /// for more information.
    #[allow(non_camel_case_types)]
    V3_0(v3_0::Spec),
}

/// deserialize an open api spec from a path
pub fn from_path<P>(path: P) -> Result<OpenApi>
where
    P: AsRef<Path>,
{
    from_reader(File::open(path)?)
}

/// deserialize an open api spec from type which implements Read
pub fn from_reader<R>(read: R) -> Result<OpenApi>
where
    R: Read,
{
    Ok(serde_yaml::from_reader::<R, OpenApi>(read)?)
}

/// serialize to a yaml string
pub fn to_yaml(spec: &OpenApi) -> Result<String> {
    Ok(serde_yaml::to_string(spec)?)
}

/// serialize to a json string
pub fn to_json(spec: &OpenApi) -> Result<String> {
    Ok(serde_json::to_string_pretty(spec)?)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{
        fs::{self, read_to_string, File},
        io::Write,
    };

    /// Helper function to write string to file.
    fn write_to_file<P>(
        path: P,
        filename: &str,
        data: &str,
    ) where
        P: AsRef<Path> + std::fmt::Debug,
    {
        println!("    Saving string to {:?}...", path);
        std::fs::create_dir_all(&path).unwrap();
        let full_filename = path.as_ref().to_path_buf().join(filename);
        let mut f = File::create(&full_filename).unwrap();
        f.write_all(data.as_bytes()).unwrap();
    }

    /// Convert a YAML `&str` to a JSON `String`.
    fn convert_yaml_str_to_json(yaml_str: &str) -> String {
        let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
        let json: serde_json::Value = serde_yaml::from_value(yaml).unwrap();
        serde_json::to_string_pretty(&json).unwrap()
    }

    /// Deserialize and re-serialize the input file to a JSON string through two different
    /// paths, comparing the result.
    /// 1. File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`
    /// 2. File -> `Spec` -> `serde_json::Value` -> `String`
    /// Both conversion of `serde_json::Value` -> `String` are done
    /// using `serde_json::to_string_pretty`.
    /// Since the first conversion is independant of the current crate (and only
    /// uses serde's json and yaml support), no information should be lost in the final
    /// JSON string. The second conversion goes through our `OpenApi`, so the final JSON
    /// string is a representation of _our_ implementation.
    /// By comparing those two JSON conversions, we can validate our implementation.
    fn compare_spec_through_json(
        input_file: &Path,
        save_path_base: &Path,
    ) -> (String, String, String) {
        // First conversion:
        //     File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`

        // Read the original file to string
        let spec_yaml_str = read_to_string(&input_file).expect(&format!("failed to read contents of {:?}", input_file));
        // Convert YAML string to JSON string
        let spec_json_str = convert_yaml_str_to_json(&spec_yaml_str);

        // Second conversion:
        //     File -> `Spec` -> `serde_json::Value` -> `String`

        // Parse the input file
        let parsed_spec = from_path(&input_file).unwrap();
        // Convert to serde_json::Value
        let parsed_spec_json: serde_json::Value = serde_json::to_value(parsed_spec).unwrap();
        // Convert to a JSON string
        let parsed_spec_json_str: String = serde_json::to_string_pretty(&parsed_spec_json).unwrap();

        // Save JSON strings to file
        let api_filename = input_file
            .file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .replace(".yaml", ".json");

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_json");
        write_to_file(&save_path, &api_filename, &spec_json_str);

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_spec_to_json");
        write_to_file(&save_path, &api_filename, &parsed_spec_json_str);

        // Return the JSON filename and the two JSON strings
        (api_filename, parsed_spec_json_str, spec_json_str)
    }

    // Just tests if the deserialization does not blow up. But does not test correctness
    #[test]
    fn can_deserialize() {
        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            // cargo test -- --nocapture to see this message
            println!("Testing if {:?} is deserializable", path);
            from_path(path).unwrap();
        }
    }

    #[test]
    fn can_deserialize_and_reserialize_v2() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v2"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }

    #[test]
    fn can_deserialize_and_reserialize_v3() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v3"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v3.0").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }
}
<commit_msg>clippy warning<commit_after>//! Openapi provides structures and support for serializing and deserializing [openapi](https://github.com/OAI/OpenAPI-Specification) specifications
//!
//! # Examples
//!
//! Typical use deserialing an existing to a persisted spec to rust form or
//! visa versa
//!
//! The hyper client should be configured with tls.
//!
//! ```no_run
//! extern crate openapi;
//!
//! fn main() {
//!   match openapi::from_path("path/to/openapi.yaml") {
//!     Ok(spec) => println!("spec: {:?}", spec),
//!     Err(err) => println!("error: {}", err)
//!   }
//! }
//! ```
//!
//! # Errors
//!
//! Operations typically result in a `openapi::Result` Type which is an alias
//! for Rust's
//! built-in Result with the Err Type fixed to the
//! [openapi::errors::Error](errors/struct.Error.html) enum type. These are
//! provided
//! using [error_chain](https://github.com/brson/error-chain) crate so their
//! shape and behavior should be consistent and familiar to existing
//! error_chain users.
//!
use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::Path, result::Result as StdResult};

pub mod error;
pub mod v2;
pub mod v3_0;

pub use error::Error;

const MINIMUM_OPENAPI30_VERSION: &str = ">= 3.0";

pub type Result<T> = StdResult<T, Error>;

/// Supported versions of the OpenApi.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum OpenApi {
    /// Version 2.0 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/2.0.md)
    /// for more information.
    V2(v2::Spec),

    /// Version 3.0.1 of the OpenApi specification.
    ///
    /// Refer to the official
    /// [specification](https://github.com/OAI/OpenAPI-Specification/blob/0dd79f6/versions/3.0.1.md)
    /// for more information.
    #[allow(non_camel_case_types)]
    V3_0(v3_0::Spec),
}

/// deserialize an open api spec from a path
pub fn from_path<P>(path: P) -> Result<OpenApi>
where
    P: AsRef<Path>,
{
    from_reader(File::open(path)?)
}

/// deserialize an open api spec from type which implements Read
pub fn from_reader<R>(read: R) -> Result<OpenApi>
where
    R: Read,
{
    Ok(serde_yaml::from_reader::<R, OpenApi>(read)?)
}

/// serialize to a yaml string
pub fn to_yaml(spec: &OpenApi) -> Result<String> {
    Ok(serde_yaml::to_string(spec)?)
}

/// serialize to a json string
pub fn to_json(spec: &OpenApi) -> Result<String> {
    Ok(serde_json::to_string_pretty(spec)?)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{
        fs::{self, read_to_string, File},
        io::Write,
    };

    /// Helper function to write string to file.
    fn write_to_file<P>(
        path: P,
        filename: &str,
        data: &str,
    ) where
        P: AsRef<Path> + std::fmt::Debug,
    {
        println!("    Saving string to {:?}...", path);
        std::fs::create_dir_all(&path).unwrap();
        let full_filename = path.as_ref().to_path_buf().join(filename);
        let mut f = File::create(&full_filename).unwrap();
        f.write_all(data.as_bytes()).unwrap();
    }

    /// Convert a YAML `&str` to a JSON `String`.
    fn convert_yaml_str_to_json(yaml_str: &str) -> String {
        let yaml: serde_yaml::Value = serde_yaml::from_str(yaml_str).unwrap();
        let json: serde_json::Value = serde_yaml::from_value(yaml).unwrap();
        serde_json::to_string_pretty(&json).unwrap()
    }

    /// Deserialize and re-serialize the input file to a JSON string through two different
    /// paths, comparing the result.
    /// 1. File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`
    /// 2. File -> `Spec` -> `serde_json::Value` -> `String`
    /// Both conversion of `serde_json::Value` -> `String` are done
    /// using `serde_json::to_string_pretty`.
    /// Since the first conversion is independant of the current crate (and only
    /// uses serde's json and yaml support), no information should be lost in the final
    /// JSON string. The second conversion goes through our `OpenApi`, so the final JSON
    /// string is a representation of _our_ implementation.
    /// By comparing those two JSON conversions, we can validate our implementation.
    fn compare_spec_through_json(
        input_file: &Path,
        save_path_base: &Path,
    ) -> (String, String, String) {
        // First conversion:
        //     File -> `String` -> `serde_yaml::Value` -> `serde_json::Value` -> `String`

        // Read the original file to string
        let spec_yaml_str = read_to_string(&input_file)
            .unwrap_or_else(|e| panic!("failed to read contents of {:?}: {}", input_file, e));
        // Convert YAML string to JSON string
        let spec_json_str = convert_yaml_str_to_json(&spec_yaml_str);

        // Second conversion:
        //     File -> `Spec` -> `serde_json::Value` -> `String`

        // Parse the input file
        let parsed_spec = from_path(&input_file).unwrap();
        // Convert to serde_json::Value
        let parsed_spec_json: serde_json::Value = serde_json::to_value(parsed_spec).unwrap();
        // Convert to a JSON string
        let parsed_spec_json_str: String = serde_json::to_string_pretty(&parsed_spec_json).unwrap();

        // Save JSON strings to file
        let api_filename = input_file
            .file_name()
            .unwrap()
            .to_str()
            .unwrap()
            .replace(".yaml", ".json");

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_json");
        write_to_file(&save_path, &api_filename, &spec_json_str);

        let mut save_path = save_path_base.to_path_buf();
        save_path.push("yaml_to_spec_to_json");
        write_to_file(&save_path, &api_filename, &parsed_spec_json_str);

        // Return the JSON filename and the two JSON strings
        (api_filename, parsed_spec_json_str, spec_json_str)
    }

    // Just tests if the deserialization does not blow up. But does not test correctness
    #[test]
    fn can_deserialize() {
        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();
            // cargo test -- --nocapture to see this message
            println!("Testing if {:?} is deserializable", path);
            from_path(path).unwrap();
        }
    }

    #[test]
    fn can_deserialize_and_reserialize_v2() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v2"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v2").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }

    #[test]
    fn can_deserialize_and_reserialize_v3() {
        let save_path_base: std::path::PathBuf =
            ["target", "tests", "can_deserialize_and_reserialize_v3"]
                .iter()
                .collect();
        let mut invalid_diffs = Vec::new();

        for entry in fs::read_dir("data/v3.0").unwrap() {
            let entry = entry.unwrap();
            let path = entry.path();

            println!("Testing if {:?} is deserializable", path);

            let (api_filename, parsed_spec_json_str, spec_json_str) =
                compare_spec_through_json(&path, &save_path_base);

            if parsed_spec_json_str != spec_json_str {
                invalid_diffs.push((api_filename, parsed_spec_json_str, spec_json_str));
            }
        }

        for invalid_diff in &invalid_diffs {
            println!("File {} failed JSON comparison!", invalid_diff.0);
        }
        assert!(invalid_diffs.len() == 0);
    }
}
<|endoftext|>


<commit_before>use std::cell::UnsafeCell;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

/// A single-producer multiple-consumer buffer, useful for thread-safe data
/// sharing. More general variant of triple buffering for multiple consumers.
///
/// Triple buffering is an extremely efficient synchronization protocol when
/// a producer thread wants to constantly update a value that is visible by a
/// single consumer thread. However, it is not safe to use in the presence of
/// multiple consumers, because the consumer thread can no longer assume that
/// it is the only thread having access to the read buffer.
///
/// Reference counting techniques can be used to build a multi-consumer variant
/// of triple buffering which works for multiple consumers, remains provably
/// wait-free if one extra buffer per extra consumer is added, and degrades
/// gracefully when a smaller amount of buffers is used. I call the resulting
/// construct an SPMC buffer.
///
pub struct SPMCBuffer<T: Clone> {
    /// Input object used by the producer to send updates
    input: SPMCBufferInput<T>,

    /// Clonable output object, used by consumers to read the current value
    output: SPMCBufferOutput<T>,
}
//
impl<T: Clone> SPMCBuffer<T> {
    /// Construct an SPMC buffer allowing for wait-free writes under up to N
    /// concurrent readouts to distinct buffers, and with some initial content.
    pub fn new(max_conc_readers: usize, initial: T) -> Self {
        // Translate max_conc_readers into an actual buffer count
        assert!(max_conc_readers > 0);
        let num_buffers = max_conc_readers + 2;

        // Start with the shared state...
        let shared_state = Arc::new(
            SPMCBufferSharedState {
                storage: vec![
                    Buffer {
                        data: UnsafeCell::new(initial),
                        done_readers: AtomicRefcount::new(0),
                    };
                    num_buffers
                ],
                latest_buf: AtomicSharedIndex::new(0),
            }
        );

        // ...then construct the input and output structs
        let mut result = SPMCBuffer {
            input: SPMCBufferInput {
                shared: shared_state.clone(),
                reference_counts: vec![0; num_buffers],
            },
            output: SPMCBufferOutput {
                shared: shared_state,
                read_idx: INVALID_INDEX,
            },
        };

        // Don't forget to mark the currently published buffer as busy, so that
        // the producer doesn't get the silly idea of writing into it.
        result.input.reference_counts[0] = UNKNOWN_REFCOUNT;

        // Return the resulting valid SPMC buffer
        result
    }

    /// Extract input and output of the SPMC buffer
    pub fn split(self) -> (SPMCBufferInput<T>, SPMCBufferOutput<T>) {
        (self.input, self.output)
    }
}

/// Producer interface to SPMC buffers
///
/// The producer can use this struct to submit updates to the SPMC buffer
/// whenever he likes. These updates may or may not be nonblocking depending
/// on the buffer size and the readout pattern.
///
pub struct SPMCBufferInput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Amount of readers who potentially have access to each buffer.
    /// The latest buffer has a maximal reference count to clarify that its
    /// actual number of readers is unknown and potentially very high.
    reference_counts: Vec<Refcount>,
}

// TODO: Writer algorithm:
//          - We know which buffer is the latest buffer, and shouldn't touch it
//          - Scan private list of other buffers' read counts, to find a buffer
//            whose readers are all done (readcount = donereads)
//          - Write new data into this "safe" buffer, which has no readers
//          - When done, swap latest_idx with the latest buffer's index and
//            a readcount of zero
//          - Check if read count overflow occured, and if so panic
//          - Otherwise, memorize the old read count in our private list

/// Consumer interface to SPMC buffers
///
/// A consumer of data can use this struct to access the latest published update
/// from the producer whenever he likes. Readout is nonblocking: a collision
/// between the producer and a consumer will result cache contention induced
/// slowdown, but deadlocks and scheduling-induced slowdowns cannot happen.
///
pub struct SPMCBufferOutput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Index of the buffer which the consumer is currently reading from
    read_idx: BufferIndex,
}

// TODO: Reader algorithm:
//          - Keep track of the last buffer we've read
//          - Relaxed-check the latest_buf AtomicSharedIdx to see if a new
//            buffer is available
//          - If not, we're done, otherwise drop our buffer
//          - Fetch-add the latest_buf AtomicSharedIdx to acquire a new buffer
//          - Check if read count overflow occured, and if so panic
//          - Extract buffer ID
//          - Provide a buffer smart-ref that allows required read access
//          - When the smart-ref is dropped, increment buffer's done-read count
//              (Decrementing the readcount is unsafe because the writer may
//              have commited an update to latest_idx meanwhile)

/// Shared state for SPMC buffers
///
/// This struct provides both a set of shared buffers for single-producer
/// multiple-consumer broadcast communication and
///
/// The number of buffers N is a design tradeoff: the larger it is, the more
/// robust the primitive is against contention, at the cost of increased memory
/// usage. An SPMC buffer is provably wait-free for both readers and writers if
/// N >= Nreaders + 2, where Nreaders is the amount of data consumers, but it
/// can work correctly in a degraded regime which is wait-free for readers and
/// potentially blocking for writers as long as N >= 3.
///
struct SPMCBufferSharedState<T: Clone> {
    /// Data storage buffers
    storage: Vec<Buffer<T>>,

    /// Combination of reader count and latest buffer index (see below)
    latest_buf: AtomicSharedIndex,
}
//
struct Buffer<T: Clone> {
    /// Actual data must be in an UnsafeCell so that Rust knows it's mutable
    data: UnsafeCell<T>,

    /// Amount of readers who are done with this buffer and switched to another
    done_readers: AtomicRefcount,
}
//
impl<T: Clone> Clone for Buffer<T> {
    /// WARNING: Buffers are NOT safe to clone, because a writer might be
    ///          concurrently writing to them. The only reason why I'm not
    ///          marking this function as unsafe is that Rust won't allow me to
    ///          while staying compatible with the vec! single-item constructor
    fn clone(&self) -> Self {
        Buffer {
            data: UnsafeCell::new(
                unsafe { (*self.data.get()).clone() }
            ),
            done_readers: AtomicRefcount::new(
                self.done_readers.load(Ordering::Relaxed)
            ),
        }
    }
}

/// Atomic "shared index", combining "latest buffer" and "reader count" info
/// in a single large integer through silly bit tricks.
///
/// At the start of the readout process, a reader must atomically announce
/// itself as in the process of reading the current buffer (so that said buffer
/// does not get reclaimed) and determine which buffer is the current buffer.
///
/// Here is why these operations cannot be separated:
///
/// - Assume that the reader announces that it is reading, then determines which
///   buffer is the current buffer. In this case, the reader can only make the
///   generic announcement that it is reading "some" buffer, because it does not
///   know yet which buffer it'll be reading. This means that other threads do
///   not know which buffers are busy, and no buffer can be liberated until the
///   reader clarifies its intent or goes away. This way of operating is thus
///   effectively equivalent to a reader-directed update lock.
/// - Assume that the reader determines which buffer is the current buffer, then
///   announces itself as being in the process of reading this specific buffer.
///   Inbetween these two actions, the current buffer may have changed, so the
///   reader may increment the wrong refcount. Furthermore, the buffer that is
///   now targeted by the reader may have already be tagged as safe for reuse or
///   deletion by the writer, so if the reader proceeds with reading it, it may
///   accidentally end up in a data race w/ the writer. This follows the
///   classical rule of thumb that one should always reserve resources before
///   accessing them, however lightly.
///
/// To combine latest buffer index readout and reader count increment, we need
/// to pack both of these quantities into a single shared integer variable that
/// we can manipulate through a atomic operations. For refcounting, fetch_add
/// sounds like a good choice, so we want an atomic integer type whose low-order
/// bits act as a refcount and whose high-order bit act as a buffer index.
/// Here's an example for a 16-bit unsigned integer, allowing up to 64 buffers
/// and 511 concurrent readers on each buffer:
///
///   bit (high-order first):       15 .. 10  9  8 .. 0
///                                +--------+--+-------+
///   Contents:                    |BUFFERID|OF|READCNT|
///                                +--------+--+-------+
///
/// In this scheme, BUFFERID is the index of the "latest buffer", which contains
/// the newest data from the writer, and READCNT is the amount of readers who
/// have acquired access to this data. In principle, the later counter could
/// overflow in the presence of 512+ concurrent readers, all accessing the same
/// buffer without a single update happening in meantime. This scenario is
/// highly implausible on current hardware architectures (even many-core ones),
/// but we nevertheless account for it by adding an overflow bit, whose value is
/// checked in debug builds. A thread which detects such overflow should panic.
///
/// TODO: Switch to U16 / AtomicU16 once the later is stable
///
type BufferIndex = usize;
const INVALID_INDEX: usize = 0xffff;
//
type Refcount = usize;
const UNKNOWN_REFCOUNT: usize = 0xffff;
//
type AtomicRefcount = AtomicUsize;
//
type AtomicSharedIndex = AtomicUsize;
const SHARED_READCOUNT_MASK:   usize = 0b0000_0001_1111_1111; // < 512 readers
const SHARED_OVERFLOW_BIT:     usize = 0b0000_0010_0000_0000;
const SHARED_INDEX_MASK:       usize = 0b1111_1100_0000_0000; // <= 64 buffers
const SHARED_INDEX_MULTIPLIER: usize = 0b0000_0100_0000_0000;

// TODO: Add tests
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Mostly complete SPMC buffer implementation, only lacking consumer smart-refs<commit_after>use std::cell::UnsafeCell;
use std::ops::BitAnd;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

/// A single-producer multiple-consumer buffer, useful for thread-safe data
/// sharing. More general variant of triple buffering for multiple consumers.
///
/// Triple buffering is an extremely efficient synchronization protocol when
/// a producer thread wants to constantly update a value that is visible by a
/// single consumer thread. However, it is not safe to use in the presence of
/// multiple consumers, because the consumer thread can no longer assume that
/// it is the only thread having access to the read buffer.
///
/// Reference counting techniques can be used to build a multi-consumer variant
/// of triple buffering which works for multiple consumers, remains provably
/// wait-free if one extra buffer per extra consumer is added, and degrades
/// gracefully when a smaller amount of buffers is used. I call the resulting
/// construct an SPMC buffer.
///
pub struct SPMCBuffer<T: Clone> {
    /// Input object used by the producer to send updates
    input: SPMCBufferInput<T>,

    /// Clonable output object, used by consumers to read the current value
    output: SPMCBufferOutput<T>,
}
//
impl<T: Clone> SPMCBuffer<T> {
    /// Construct an SPMC buffer allowing for wait-free writes under up to N
    /// concurrent readouts to distinct buffers, and with some initial content.
    pub fn new(max_conc_readers: usize, initial: T) -> Self {
        // Translate max_conc_readers into an actual buffer count
        let num_buffers = max_conc_readers + 2;

        // Start with the shared state...
        let shared_state = Arc::new(
            SPMCBufferSharedState {
                buffers: vec![
                    Buffer {
                        data: UnsafeCell::new(initial),
                        done_readers: AtomicRefCount::new(0),
                    };
                    num_buffers
                ],
                latest_buf: AtomicSharedIndex::new(0),
            }
        );

        // ...then construct the input and output structs. Any consumer should
        // be initialized with an invalid read index so that it increments the
        // refcount of the latest buffer on its first read.
        let mut result = SPMCBuffer {
            input: SPMCBufferInput {
                shared: shared_state.clone(),
                reference_counts: vec![0; num_buffers],
            },
            output: SPMCBufferOutput {
                shared: shared_state,
                shared_read_idx: INVALID_SHARED_INDEX,
            },
        };

        // Don't forget to mark the currently published buffer as busy, so that
        // the producer doesn't get the silly idea of writing into it.
        result.input.reference_counts[0] = UNKNOWN_REFCOUNT;

        // Return the resulting valid SPMC buffer
        result
    }

    /// Extract input and output of the SPMC buffer
    pub fn split(self) -> (SPMCBufferInput<T>, SPMCBufferOutput<T>) {
        (self.input, self.output)
    }
}

/// Producer interface to SPMC buffers
///
/// The producer can use this struct to submit updates to the SPMC buffer
/// whenever he likes. These updates may or may not be nonblocking depending
/// on the buffer size and the readout pattern.
///
pub struct SPMCBufferInput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Amount of readers who potentially have access to each buffer.
    /// The latest buffer has an infinite reference count to clarify that its
    /// actual number of readers is unknown and potentially very high.
    reference_counts: Vec<RefCount>,
}
//
impl<T: Clone> SPMCBufferInput<T> {
    /// Write a new value into the SPMC buffer
    pub fn write(&mut self, value: T) {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Go into a spin-loop, looking for an "old" buffer with no live reader
        let mut write_pos: Option<usize> = None;
        while write_pos == None {
            // We want to iterate over both buffers and associated refcounts
            let mut buf_rc_iter =
                shared_state.buffers.iter()
                                    .zip(self.reference_counts.iter());

            // We want to find an unreachable buffer in which all readers are
            // gone. We are guaranteed not to find the latest buffer here
            // because its reference count is set to an "infinite" value.
            write_pos = buf_rc_iter.position(|tuple| {
                let (buffer, refcount) = tuple;
                let done_readers = buffer.done_readers.load(Ordering::Relaxed);
                done_readers == *refcount
            });
        }
        let write_idx = write_pos.unwrap();

        // The buffer that we just obtained is provably unused by any reader and
        // unreachable by new readers, so we can safely use it as a write
        // buffer and put our data in it
        let write_ptr = shared_state.buffers[write_idx].data.get();
        unsafe { *write_ptr = value; }

        // Publish our write buffer as the new latest buffer, and retrieve
        // the old buffer's shared index
        let former_latest_buf = shared_state.latest_buf.swap(
            write_idx * SHARED_INDEX_MULTIPLIER,
            Ordering::Release  // Publish all buffer updates to the readers
        );

        // In debug mode, make sure that overflow did not occur
        debug_assert!(former_latest_buf.bitand(SHARED_OVERFLOW_BIT) == 0);

        // Decode the information contained in the former shared index
        let former_idx = former_latest_buf.bitand(SHARED_INDEX_MASK)
                                          / SHARED_INDEX_MULTIPLIER;
        let former_readcount = former_latest_buf.bitand(SHARED_READCOUNT_MASK);

        // Write down the former buffer's refcount, and set the latest buffer's
        // refcount to infinity so that we don't accidentally write to it
        self.reference_counts[former_idx] = former_readcount;
        self.reference_counts[write_idx] = UNKNOWN_REFCOUNT;
    }
}

/// Consumer interface to SPMC buffers
///
/// A consumer of data can use this struct to access the latest published update
/// from the producer whenever he likes. Readout is nonblocking: a collision
/// between the producer and a consumer will result cache contention induced
/// slowdown, but deadlocks and scheduling-induced slowdowns cannot happen.
///
pub struct SPMCBufferOutput<T: Clone> {
    /// Reference-counted shared state
    shared: Arc<SPMCBufferSharedState<T>>,

    /// Index of the buffer which the consumer is currently reading from,
    /// in the shared-index format corresponding to a reader count of zero
    shared_read_idx: SharedIndex,
}
//
impl<T: Clone> SPMCBufferOutput<T> {
    /// Access the latest value from the SPMC buffer. This invalidates any
    /// previously emitted SPMCRef, so make sure that you drop these before
    /// calling read() again. Or else this function will panic in your face.
    pub fn read(&mut self) -> SPMCRef<Self> {
        // Access the shared state
        let ref shared_state = *self.shared;

        // Check if the producer has submitted an update
        let init_latest_buf = shared_state.latest_buf.load(Ordering::Relaxed);
        let update_available =
            init_latest_buf.bitand(SHARED_INDEX_MASK) != self.shared_read_idx;

        // If so, exchange our current read buffer with the latest buffer
        if update_available {
            // Start by dropping our current read buffer...
            let read_idx = self.shared_read_idx / SHARED_INDEX_MULTIPLIER;
            shared_state.buffers[read_idx].done_readers.fetch_add(
                1,
                Ordering::Relaxed
            );

            // ...then acquire access to the latest buffer, incrementing its
            // refcount to tell the producer that we have access to it
            let latest_buf = shared_state.latest_buf.fetch_add(
                1,
                Ordering::Acquire  // Synchronize with buffer updates
            );

            // In debug mode, make sure that overflow did not occur
            debug_assert!((latest_buf+1).bitand(SHARED_OVERFLOW_BIT) == 0);

            // Extract the index of our new read buffer
            self.shared_read_idx = latest_buf.bitand(SHARED_INDEX_MASK);
        }

        // Access data from the current (read-only) read buffer
        let read_idx = self.shared_read_idx / SHARED_INDEX_MULTIPLIER;
        let read_ptr = shared_state.buffers[read_idx].data.get();
        SPMCRef::new(self, unsafe { &*read_ptr })

        // TODO: Make sure that we automatically drop the current read buffer
        //       on thread exit by returning a smart reference which does that
        //          + Make sure that a reader that reads twice without dropping
        //            the smart-reference first gets appropriate punishment.
    }
}
//
impl<T: Clone> Clone for SPMCBufferOutput<T> {
    // Create a new reader associated with a given SPMC buffer
    fn clone(&self) -> Self {
        SPMCBufferOutput {
            shared: self.shared.clone(),
            shared_read_idx: INVALID_SHARED_INDEX,
        }
    }
}

/// Shared state for SPMC buffers
///
/// This struct provides both a set of shared buffers for single-producer
/// multiple-consumer broadcast communication and
///
/// The number of buffers N is a design tradeoff: the larger it is, the more
/// robust the primitive is against contention, at the cost of increased memory
/// usage. An SPMC buffer is provably wait-free for both readers and writers if
/// N >= Nreaders + 2, where Nreaders is the amount of data consumers, but it
/// can work correctly in a degraded regime which is wait-free for readers and
/// potentially blocking for writers as long as N >= 2.
///
struct SPMCBufferSharedState<T: Clone> {
    /// Data storage buffers
    buffers: Vec<Buffer<T>>,

    /// Combination of reader count and latest buffer index (see below)
    latest_buf: AtomicSharedIndex,
}
//
struct Buffer<T: Clone> {
    /// Actual data must be in an UnsafeCell so that Rust knows it's mutable
    data: UnsafeCell<T>,

    /// Amount of readers who are done with this buffer and switched to another
    done_readers: AtomicRefCount,
}
//
impl<T: Clone> Clone for Buffer<T> {
    /// WARNING: Buffers are NOT safe to clone, because a writer might be
    ///          concurrently writing to them. The only reason why I'm not
    ///          marking this function as unsafe is that Rust won't allow me to
    ///          while staying compatible with the vec! single-item constructor
    fn clone(&self) -> Self {
        Buffer {
            data: UnsafeCell::new(
                unsafe { (*self.data.get()).clone() }
            ),
            done_readers: AtomicRefCount::new(
                self.done_readers.load(Ordering::Relaxed)
            ),
        }
    }
}

/// Atomic "shared index", combining "latest buffer" and "reader count" info
/// in a single large integer through silly bit tricks.
///
/// At the start of the readout process, a reader must atomically announce
/// itself as in the process of reading the current buffer (so that said buffer
/// does not get reclaimed) and determine which buffer is the current buffer.
///
/// Here is why these operations cannot be separated:
///
/// - Assume that the reader announces that it is reading, then determines which
///   buffer is the current buffer. In this case, the reader can only make the
///   generic announcement that it is reading "some" buffer, because it does not
///   know yet which buffer it'll be reading. This means that other threads do
///   not know which buffers are busy, and no buffer can be liberated until the
///   reader clarifies its intent or goes away. This way of operating is thus
///   effectively equivalent to a reader-directed update lock.
/// - Assume that the reader determines which buffer is the current buffer, then
///   announces itself as being in the process of reading this specific buffer.
///   Inbetween these two actions, the current buffer may have changed, so the
///   reader may increment the wrong refcount. Furthermore, the buffer that is
///   now targeted by the reader may have already be tagged as safe for reuse or
///   deletion by the writer, so if the reader proceeds with reading it, it may
///   accidentally end up in a data race w/ the writer. This follows the
///   classical rule of thumb that one should always reserve resources before
///   accessing them, however lightly.
///
/// To combine latest buffer index readout and reader count increment, we need
/// to pack both of these quantities into a single shared integer variable that
/// we can manipulate through a atomic operations. For refcounting, fetch_add
/// sounds like a good choice, so we want an atomic integer type whose low-order
/// bits act as a refcount and whose high-order bit act as a buffer index.
/// Here's an example for a 16-bit unsigned integer, allowing up to 64 buffers
/// and 511 concurrent readers on each buffer:
///
///   bit (high-order first):       15 .. 10  9  8 .. 0
///                                +--------+--+-------+
///   Contents:                    |BUFFERID|OF|READCNT|
///                                +--------+--+-------+
///
/// In this scheme, BUFFERID is the index of the "latest buffer", which contains
/// the newest data from the writer, and READCNT is the amount of readers who
/// have acquired access to this data. In principle, the later counter could
/// overflow in the presence of 512+ concurrent readers, all accessing the same
/// buffer without a single update happening in meantime. This scenario is
/// highly implausible on current hardware architectures (even many-core ones),
/// but we nevertheless account for it by adding an overflow bit, whose value is
/// checked in debug builds. A thread which detects such overflow should panic.
///
/// TODO: Switch to U16 / AtomicU16 once the later is stable
///
type RefCount = usize;
const UNKNOWN_REFCOUNT: RefCount = 0xffff;
type AtomicRefCount = AtomicUsize;
//
type SharedIndex = usize;
type AtomicSharedIndex = AtomicUsize;
const SHARED_READCOUNT_MASK:   SharedIndex = 0b0000_0001_1111_1111;
const SHARED_OVERFLOW_BIT:     SharedIndex = 0b0000_0010_0000_0000;
const SHARED_INDEX_MASK:       SharedIndex = 0b1111_1100_0000_0000;
const SHARED_INDEX_MULTIPLIER: SharedIndex = 0b0000_0100_0000_0000;
const INVALID_SHARED_INDEX:    SharedIndex = 0b1111_1111_1111_1111;

// TODO: Add tests
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate petgraph;

// XXX: Self-loops?

use petgraph::{Graph, Directed};
use petgraph::graph::{NodeIndex, IndexType};
use std::collections::HashSet;
use std::mem;

#[cfg(test)]
extern crate test;

#[repr(u8)]
#[derive(Debug)]
pub enum TriadType {
    T003 = 0,
    T012,
    T102,
    T021D,

    T021U,
    T021C,
    T111D,
    T111U,

    T030T,
    T030C,
    T201,
    T120D,

    T120U,
    T120C,
    T210,
    T300,
}

impl TriadType {
    #[inline(always)]
    fn from_u8(i: u8) -> TriadType {
        assert!(i < 16);
        unsafe { mem::transmute(i) }
    }
}

pub type NodeIdx = usize;

/// Interface required for Triadic Census.
/// Nodes are externally represented by `NodeIdx`.
pub trait DirectedGraph {
    fn node_count(&self) -> NodeIdx;
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool;
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, callback: F);
}

fn tricode<G: DirectedGraph>(graph: &G, v: NodeIdx, u: NodeIdx, w: NodeIdx) -> usize {
    let mut tricode = 0;
    if graph.has_edge(v, u) {
        tricode |= 1 << 0;
    }
    if graph.has_edge(u, v) {
        tricode |= 1 << 1;
    }
    if graph.has_edge(v, w) {
        tricode |= 1 << 2;
    }
    if graph.has_edge(w, v) {
        tricode |= 1 << 3;
    }
    if graph.has_edge(u, w) {
        tricode |= 1 << 4;
    }
    if graph.has_edge(w, u) {
        tricode |= 1 << 5;
    }
    return tricode;
}

const TRITYPES: [u8; 64] = [0, 1, 1, 2, 1, 3, 5, 7, 1, 5, 4, 6, 2, 7, 6, 10, 1, 5, 3, 7, 4, 8, 8,
                            12, 5, 9, 8, 13, 6, 13, 11, 14, 1, 4, 5, 6, 5, 8, 9, 13, 3, 8, 8, 11,
                            7, 12, 13, 14, 2, 6, 7, 10, 6, 11, 13, 14, 7, 13, 12, 14, 10, 14, 14,
                            15];

#[derive(Debug)]
pub struct TriadicCensus {
    census: [u64; 16],
}

impl TriadicCensus {
    /// Calculates the `distance` between two TriadicCensus structs, treated as
    /// points in a 16-dimensional space.
    pub fn distance(a: &TriadicCensus, b: &TriadicCensus) -> f64 {
        let mut sum = 0.0f64;
        for i in 0..16 {
            let va = a.census[i];
            let vb = b.census[i];
            let diff = (if va > vb {
                va - vb
            } else {
                vb - va
            }) as f64;
            sum += diff * diff;
        }
        sum.sqrt()
    }

    #[inline(always)]
    fn new() -> TriadicCensus {
        TriadicCensus { census: [0; 16] }
    }

    #[inline(always)]
    fn add(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] += cnt;
    }

    #[inline(always)]
    fn set(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] = cnt;
    }

    #[inline(always)]
    pub fn get(&self, triad_type: TriadType) -> u64 {
        self.census[triad_type as usize]
    }

    #[inline(always)]
    pub fn as_slice<'a>(&'a self) -> &'a [u64] {
        &self.census[..]
    }

    /// XXX: Optimize: find_edge() is O(k) with k the number of edges.
    pub fn from_graph<G: DirectedGraph>(graph: &G) -> TriadicCensus {
        let n = graph.node_count();

        let mut census = TriadicCensus::new();
        let mut neighbors_v = HashSet::new();
        let mut s = HashSet::new(); // XXX: Use bitset? // reuse

        for v in 0..n {
            neighbors_v.clear();
            graph.each_undirected_neighbor(v, |u| {
                if u > v {
                    neighbors_v.insert(u);
                }
            });

            for &u in neighbors_v.iter() {
                s.clear();
                graph.each_undirected_neighbor(u, |nu| {
                    s.insert(nu);
                });
                graph.each_undirected_neighbor(v, |nv| {
                    s.insert(nv);
                });
                let _ = s.remove(&u);
                let _ = s.remove(&v);

                let tri_type = if graph.has_edge(v, u) && graph.has_edge(u, v) {
                    TriadType::T102
                } else {
                    TriadType::T012
                };

                let cnt = n as i64 - s.len() as i64 - 2;
                assert!(cnt >= 0);
                census.add(tri_type, cnt as u64);
                for &w in s.iter() {
                    if u < w ||
                       (v < w && w < u && !(graph.has_edge(v, w) || graph.has_edge(w, v))) {
                        let tri_type = TriadType::from_u8(TRITYPES[tricode(graph, v, u, w)]);
                        census.add(tri_type, 1);
                    }
                }
            }
        }

        let mut sum = 0;
        for &cnt in &census.as_slice()[1..] {
            sum += cnt;
        }
        let n = n as u64;
        // Integer division below is guaranteed to produce an integral result
        census.set(TriadType::T003, (n * (n - 1) * (n - 2)) / 6 - sum);
        return census;
    }
}

pub struct SimpleDiGraph {
    g: Graph<(), (), Directed>,
}

impl SimpleDiGraph {
    pub fn new() -> SimpleDiGraph {
        SimpleDiGraph { g: Graph::new() }
    }

    pub fn add_node(&mut self) -> NodeIdx {
        self.g.add_node(()).index()
    }

    pub fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx) {
        self.g.add_edge(NodeIndex::new(src), NodeIndex::new(dst), ());
    }

    pub fn from(num_nodes: usize, edge_list: &[(NodeIdx, NodeIdx)]) -> SimpleDiGraph {
        let mut g = SimpleDiGraph::new();
        for _ in 0..num_nodes {
            let _ = g.add_node();
        }
        for &(src, dst) in edge_list {
            g.add_edge(src, dst);
        }
        g
    }
}

impl DirectedGraph for SimpleDiGraph {
    fn node_count(&self) -> NodeIdx {
        self.g.node_count()
    }

    #[inline]
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool {
        self.g.find_edge(NodeIndex::new(src), NodeIndex::new(dst)).is_some()
    }

    #[inline]
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, mut callback: F) {
        for n in self.g.neighbors_undirected(NodeIndex::new(node)) {
            callback(n.index())
        }
    }
}

#[test]
fn test_simple() {
    let mut g = SimpleDiGraph::new();

    let n1 = g.add_node();
    let n2 = g.add_node();
    let n3 = g.add_node();

    let c1 = TriadicCensus::from_graph(&g);
    assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c1.as_slice());

    g.add_edge(n1, n3);
    let c2 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c2.as_slice());

    let d = TriadicCensus::distance(&c1, &c2); // should be sqrt(2)
    assert!(d > 1.414 && d < 1.415);

    g.add_edge(n3, n1);
    let c3 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c3.as_slice());

    g.add_edge(n2, n3);
    let c4 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c4.as_slice());
}

#[cfg(test)]
fn line_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let mut prev = g.add_node();
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    return g;
}

#[cfg(test)]
fn circular_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let first = g.add_node();
    let mut prev = first;
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    g.add_edge(prev, first);
    return g;
}

#[test]
fn test_line_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&line_graph(20));
    assert_eq!(&[816, 306, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&line_graph(40));
    assert_eq!(&[8436, 1406, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());
}

#[test]
fn test_circular_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&circular_graph(20));
    assert_eq!(&[800, 320, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&circular_graph(40));
    assert_eq!(&[8400, 1440, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

}

#[cfg(test)]
mod example_graphs;

#[bench]
fn bench_erdos_renyi_graph(b: &mut test::Bencher) {
    let g = SimpleDiGraph::from(example_graphs::GRAPH1_NODES, &example_graphs::GRAPH1_EDGES);
    b.iter(|| {
        let _c = TriadicCensus::from_graph(&g);
    });
}
<commit_msg>Add optimized graph representation, which is 2x faster<commit_after>#![feature(test)]
extern crate petgraph;

// XXX: Self-loops?

use petgraph::{Graph, Directed};
use petgraph::graph::{NodeIndex, IndexType};
use std::collections::HashSet;
use std::mem;
use std::collections::BTreeMap;

#[cfg(test)]
extern crate test;

#[repr(u8)]
#[derive(Debug)]
pub enum TriadType {
    T003 = 0,
    T012,
    T102,
    T021D,

    T021U,
    T021C,
    T111D,
    T111U,

    T030T,
    T030C,
    T201,
    T120D,

    T120U,
    T120C,
    T210,
    T300,
}

impl TriadType {
    #[inline(always)]
    fn from_u8(i: u8) -> TriadType {
        assert!(i < 16);
        unsafe { mem::transmute(i) }
    }
}

pub type NodeIdx = usize;

/// Interface required for Triadic Census.
/// Nodes are externally represented by `NodeIdx`.
pub trait DirectedGraph {
    fn node_count(&self) -> NodeIdx;
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool;
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, callback: F);
}

fn tricode<G: DirectedGraph>(graph: &G, v: NodeIdx, u: NodeIdx, w: NodeIdx) -> usize {
    let mut tricode = 0;
    if graph.has_edge(v, u) {
        tricode |= 1 << 0;
    }
    if graph.has_edge(u, v) {
        tricode |= 1 << 1;
    }
    if graph.has_edge(v, w) {
        tricode |= 1 << 2;
    }
    if graph.has_edge(w, v) {
        tricode |= 1 << 3;
    }
    if graph.has_edge(u, w) {
        tricode |= 1 << 4;
    }
    if graph.has_edge(w, u) {
        tricode |= 1 << 5;
    }
    return tricode;
}

const TRITYPES: [u8; 64] = [0, 1, 1, 2, 1, 3, 5, 7, 1, 5, 4, 6, 2, 7, 6, 10, 1, 5, 3, 7, 4, 8, 8,
                            12, 5, 9, 8, 13, 6, 13, 11, 14, 1, 4, 5, 6, 5, 8, 9, 13, 3, 8, 8, 11,
                            7, 12, 13, 14, 2, 6, 7, 10, 6, 11, 13, 14, 7, 13, 12, 14, 10, 14, 14,
                            15];

#[derive(Debug)]
pub struct TriadicCensus {
    census: [u64; 16],
}

impl TriadicCensus {
    /// Calculates the `distance` between two TriadicCensus structs, treated as
    /// points in a 16-dimensional space.
    pub fn distance(a: &TriadicCensus, b: &TriadicCensus) -> f64 {
        let mut sum = 0.0f64;
        for i in 0..16 {
            let va = a.census[i];
            let vb = b.census[i];
            let diff = (if va > vb {
                va - vb
            } else {
                vb - va
            }) as f64;
            sum += diff * diff;
        }
        sum.sqrt()
    }

    #[inline(always)]
    fn new() -> TriadicCensus {
        TriadicCensus { census: [0; 16] }
    }

    #[inline(always)]
    fn add(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] += cnt;
    }

    #[inline(always)]
    fn set(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] = cnt;
    }

    #[inline(always)]
    pub fn get(&self, triad_type: TriadType) -> u64 {
        self.census[triad_type as usize]
    }

    #[inline(always)]
    pub fn as_slice<'a>(&'a self) -> &'a [u64] {
        &self.census[..]
    }

    /// XXX: Optimize: find_edge() is O(k) with k the number of edges.
    pub fn from_graph<G: DirectedGraph>(graph: &G) -> TriadicCensus {
        let n = graph.node_count();

        let mut census = TriadicCensus::new();
        let mut neighbors_v = HashSet::new();
        let mut s = HashSet::new(); // XXX: Use bitset? // reuse

        for v in 0..n {
            neighbors_v.clear();
            graph.each_undirected_neighbor(v, |u| {
                if u > v {
                    neighbors_v.insert(u);
                }
            });

            for &u in neighbors_v.iter() {
                s.clear();
                graph.each_undirected_neighbor(u, |nu| {
                    s.insert(nu);
                });
                graph.each_undirected_neighbor(v, |nv| {
                    s.insert(nv);
                });
                let _ = s.remove(&u);
                let _ = s.remove(&v);

                let tri_type = if graph.has_edge(v, u) && graph.has_edge(u, v) {
                    TriadType::T102
                } else {
                    TriadType::T012
                };

                let cnt = n as i64 - s.len() as i64 - 2;
                assert!(cnt >= 0);
                census.add(tri_type, cnt as u64);
                for &w in s.iter() {
                    if u < w ||
                       (v < w && w < u && !(graph.has_edge(v, w) || graph.has_edge(w, v))) {
                        let tri_type = TriadType::from_u8(TRITYPES[tricode(graph, v, u, w)]);
                        census.add(tri_type, 1);
                    }
                }
            }
        }

        let mut sum = 0;
        for &cnt in &census.as_slice()[1..] {
            sum += cnt;
        }
        let n = n as u64;
        // Integer division below is guaranteed to produce an integral result
        census.set(TriadType::T003, (n * (n - 1) * (n - 2)) / 6 - sum);
        return census;
    }
}

pub struct SimpleDiGraph {
    g: Graph<(), (), Directed>,
}

impl SimpleDiGraph {
    pub fn new() -> SimpleDiGraph {
        SimpleDiGraph { g: Graph::new() }
    }

    pub fn add_node(&mut self) -> NodeIdx {
        self.g.add_node(()).index()
    }

    pub fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx) {
        self.g.add_edge(NodeIndex::new(src), NodeIndex::new(dst), ());
    }

    pub fn from(num_nodes: usize, edge_list: &[(NodeIdx, NodeIdx)]) -> SimpleDiGraph {
        let mut g = SimpleDiGraph::new();
        for _ in 0..num_nodes {
            let _ = g.add_node();
        }
        for &(src, dst) in edge_list {
            g.add_edge(src, dst);
        }
        g
    }
}

impl DirectedGraph for SimpleDiGraph {
    fn node_count(&self) -> NodeIdx {
        self.g.node_count()
    }

    #[inline]
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool {
        self.g.find_edge(NodeIndex::new(src), NodeIndex::new(dst)).is_some()
    }

    #[inline]
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, mut callback: F) {
        for n in self.g.neighbors_undirected(NodeIndex::new(node)) {
            callback(n.index())
        }
    }
}

pub struct OptimizedDiGraph {
    g: SimpleDiGraph,
    edges: BTreeMap<usize, u64>,
}

#[inline]
fn calc_index(n: usize, src: NodeIdx, dst: NodeIdx) -> (usize, u64) {
    assert!(src < n && dst < n);
    let idx = src * n + dst;
    let idx_64 = idx / 64;
    let bit_idx = idx % 64;
    (idx_64, 1u64 << bit_idx as u64)
}

impl OptimizedDiGraph {
    pub fn from(graph: SimpleDiGraph) -> OptimizedDiGraph {
        let n = graph.node_count();

        let mut edges: BTreeMap<usize, u64> = BTreeMap::new();

        for edge in graph.g.raw_edges().iter() {
            let src = edge.source().index();
            let dst = edge.target().index();

            // treat as adjacency matrix (with `src` using rows and `dst` columns)
            let (idx, bit_pattern) = calc_index(n, src, dst);

            let entry = edges.entry(idx);
            *entry.or_insert(0) |= bit_pattern;
        }

        OptimizedDiGraph {g: graph, edges: edges}
    }
}

impl DirectedGraph for OptimizedDiGraph {
    fn node_count(&self) -> NodeIdx {
        self.g.node_count()
    }

    #[inline]
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool {
        let (idx, bit_pattern) = calc_index(self.g.node_count(), src, dst);

        match self.edges.get(&idx) {
            Some(&v) => {
                (v & bit_pattern) != 0
            }
            _ => false
        }
    }

    #[inline]
    fn each_undirected_neighbor<F: FnMut(NodeIdx)>(&self, node: NodeIdx, callback: F) {
        self.g.each_undirected_neighbor(node, callback);
    }
}

#[test]
fn test_simple() {
    let mut g = SimpleDiGraph::new();

    let n1 = g.add_node();
    let n2 = g.add_node();
    let n3 = g.add_node();

    let c1 = TriadicCensus::from_graph(&g);
    assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c1.as_slice());

    g.add_edge(n1, n3);
    let c2 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c2.as_slice());

    let d = TriadicCensus::distance(&c1, &c2); // should be sqrt(2)
    assert!(d > 1.414 && d < 1.415);

    g.add_edge(n3, n1);
    let c3 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c3.as_slice());

    g.add_edge(n2, n3);
    let c4 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c4.as_slice());
}

#[cfg(test)]
fn line_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let mut prev = g.add_node();
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    return g;
}

#[cfg(test)]
fn circular_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let first = g.add_node();
    let mut prev = first;
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    g.add_edge(prev, first);
    return g;
}

#[test]
fn test_line_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&OptimizedDiGraph::from(line_graph(20)));
    assert_eq!(&[816, 306, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&OptimizedDiGraph::from(line_graph(40)));
    assert_eq!(&[8436, 1406, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());
}

#[test]
fn test_circular_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&circular_graph(20));
    assert_eq!(&[800, 320, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&circular_graph(40));
    assert_eq!(&[8400, 1440, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

}

#[cfg(test)]
mod example_graphs;

#[bench]
fn bench_erdos_renyi_graph(b: &mut test::Bencher) {
    let g = SimpleDiGraph::from(example_graphs::GRAPH1_NODES, &example_graphs::GRAPH1_EDGES);
    b.iter(|| {
        let c = TriadicCensus::from_graph(&g);
        assert_eq!(&[2484, 14525, 7954, 7156, 7237, 14346, 15426, 15413, 14041, 4778, 8454, 7492, 7614, 15161, 16641, 2978], c.as_slice());
    });
}

#[bench]
fn bench_erdos_renyi_graph_opt(b: &mut test::Bencher) {
    let g = SimpleDiGraph::from(example_graphs::GRAPH1_NODES, &example_graphs::GRAPH1_EDGES);
    let g = OptimizedDiGraph::from(g);
    b.iter(|| {
        let c = TriadicCensus::from_graph(&g);
        assert_eq!(&[2484, 14525, 7954, 7156, 7237, 14346, 15426, 15413, 14041, 4778, 8454, 7492, 7614, 15161, 16641, 2978], c.as_slice());
    });
}
<|endoftext|>


<commit_before>
pub struct Context<'a> {
    pub test: Option<Box<FnMut() -> () + 'a>>
}

impl<'a> Context<'a> {
    pub fn describe<F>(&mut self, _name: &'a str, mut body: F)
        where F : 'a + FnMut(&mut Context) -> () {
        body(self)
    }

    pub fn it<F>(&mut self, _name: &'a str, mut body: F)
        where F : 'a + FnMut() -> () {

        self.test = Some(Box::new(body))
    }
}

pub fn describe<'a, 'b, F>(_block_name: &'b str, mut body: F) -> Runner<'a>
    where F : 'a + FnOnce(&mut Context<'a>) -> () {

    let mut c = Context { test: None };
    body(&mut c);
    Runner { describe: c }
}

pub struct Runner<'a> {
    describe: Context<'a>
}

impl<'a> Runner<'a> {
    pub fn run(&mut self) -> Result<(), ()> {
        if let Some(ref mut test_function) = self.describe.test {
            test_function()
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    pub use super::*;
    #[test]
    fn it_has_a_root_describe_functio() {
        describe("A Test", |_ctx|{});
    }

    #[test]
    fn it_can_call_describe_inside_describe_body() {
        describe("A Root", |ctx| {
            ctx.describe("nested describe", |_ctx| {})
        });
    }

    #[test]
    fn it_can_call_it_inside_describe_body() {
        describe("A root", |ctx| {
            ctx.it("is a test", || {})
        });
    }

    #[test]
    fn it_create_a_runner_that_can_be_runned() {
        let mut runner = describe("A root", |ctx| {
            ctx.it("is expected to run", || {
                assert_eq!(true, true)
            })
        });
        assert_eq!(Ok(()), runner.run())
    }

    #[test]
    fn runner_efectively_run_tests() {
        let ran = &mut false;

        {
            let mut runner = describe("A root", |ctx| {
                ctx.it("is expected to run", || {
                    *ran = true
                })
            });
            assert_eq!(Ok(()), runner.run());
        }

        assert_eq!(true, *ran)
    }
}
<commit_msg> multiple tests<commit_after>
pub struct Context<'a> {
    pub tests: Vec<Box<FnMut() -> () + 'a>>
}

impl<'a> Context<'a> {
    pub fn describe<F>(&mut self, _name: &'a str, mut body: F)
        where F : 'a + FnMut(&mut Context) -> () {
        body(self)
    }

    pub fn it<F>(&mut self, _name: &'a str, mut body: F)
        where F : 'a + FnMut() -> () {

        self.tests.push(Box::new(body))
    }
}

pub fn describe<'a, 'b, F>(_block_name: &'b str, mut body: F) -> Runner<'a>
    where F : 'a + FnOnce(&mut Context<'a>) -> () {

    let mut c = Context { tests: vec!() };
    body(&mut c);
    Runner { describe: c }
}

pub struct Runner<'a> {
    describe: Context<'a>
}

impl<'a> Runner<'a> {
    pub fn run(&mut self) -> Result<(), ()> {

        for test_function in self.describe.tests.iter_mut() {
            test_function()
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    pub use super::*;
    #[test]
    fn it_has_a_root_describe_functio() {
        describe("A Test", |_ctx|{});
    }

    #[test]
    fn it_can_call_describe_inside_describe_body() {
        describe("A Root", |ctx| {
            ctx.describe("nested describe", |_ctx| {})
        });
    }

    #[test]
    fn it_can_call_it_inside_describe_body() {
        describe("A root", |ctx| {
            ctx.it("is a test", || {})
        });
    }

    #[test]
    fn it_create_a_runner_that_can_be_runned() {
        let mut runner = describe("A root", |ctx| {
            ctx.it("is expected to run", || {
                assert_eq!(true, true)
            })
        });
        assert_eq!(Ok(()), runner.run())
    }

    #[test]
    fn runner_effectively_run_tests() {
        let ran = &mut false;

        {
            let mut runner = describe("A root", |ctx| {
                ctx.it("is expected to run", || {
                    *ran = true
                })
            });
            assert_eq!(Ok(()), runner.run());
        }

        assert_eq!(true, *ran)
    }

    #[test]
    fn runner_effectively_run_two_tests() {
        use std::sync::atomic::{AtomicUsize, Ordering};
        let ran_counter = &mut AtomicUsize::new(0);

        {
            let mut runner = describe("A root", |ctx| {
                ctx.it("first run",  || { ran_counter.fetch_add(1, Ordering::Relaxed); });
                ctx.it("second run", || { ran_counter.fetch_add(1, Ordering::Relaxed); });
            });
            let _ = runner.run();
        }

        assert_eq!(2, ran_counter.load(Ordering::Relaxed))
    }
}
<|endoftext|>