<commit_before>use std::collections::HashMap;

struct LSystem {
    alphabet: Vec<char>,
    constants: Vec<char>,
    start: String,
    rules: HashMap<char, String>,
}

impl LSystem {
    /// Some guarantees of a LSystem:
    /// 1. Every char in start is in alphabet
    /// 2. Given a rule X -> Y, X and Y are in alphabet
    /// 3. Each char in alphabet has a rule that maps it to something else
    ///   -> by default a char maps to itself, but this can be overriden with
    ///   the `push` method

    pub fn new(start: String) -> LSystem {
        // push chars in start to alphabet
        // and make them map to themselves in a rule
        let mut alphabet: Vec<char> = Vec::new();
        let mut rules: HashMap<char, String> = HashMap::new();
        for c in start.chars() {
            if !alphabet.contains(&c) {
                alphabet.push(c);
                rules.insert(c, c.to_string());
            }
        }

        LSystem {
            alphabet: alphabet,
            constants: Vec::new(),
            start: start,
            rules: rules,
        }
    }

    pub fn next(&mut self) -> LSystem {
        let mut next = String::from("");
        for c in self.start.chars() {
            next.push_str(self.get(c));
        }

        LSystem {
            alphabet: self.alphabet.clone(),
            constants: self.constants.clone(),
            start: next,
            rules: self.rules.clone(),
        }
    }

    fn add_char(&mut self, c: char) {
        if !self.alphabet.contains(&c) {
            self.alphabet.push(c);
            self.rules.insert(c, c.to_string());
        }
    }

    pub fn push(&mut self, rule: HashMap<char, String>) {
        for (key, value) in &rule {
            // Make sure that key, value is in alphabet
            for c in value.chars() {
                self.add_char(c);
            }
            if !self.rules.contains_key(key) {
                self.add_char(*key);
            }
            // Add key value pair
            *self.rules.get_mut(key).unwrap() = value.to_owned();
        }
    }

    /// Returns the value that key maps to
    pub fn get(&self, key: char) -> &String {
        &self.rules[&key]
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use LSystem;

    #[test]
    fn test_new_should_have_correct_alphabet() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert!(lsys.alphabet.contains(&'A'));
    }

    #[test]
    fn test_new_should_have_correct_start() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.start, "AB");
    }

    #[test]
    fn test_new_should_not_have_duplicate_alphabet_chars() {
        let lsys: LSystem = LSystem::new("AA".to_string());
        assert_eq!(lsys.alphabet.len(), 1);
    }

    #[test]
    fn test_new_should_add_default_rules() {
        let lsys: LSystem = LSystem::new("A".to_string());
        assert_eq!(*lsys.get('A'), "A");
    }

    #[test]
    fn test_push_should_override_existing_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('A'), "B");
    }

    #[test]
    fn test_push_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_push_should_add_default_rules_for_new_chars() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_push_should_work_with_multiple_rules() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "A");
        assert_eq!(*lsys.get('A'), "AB");
    }

    #[test]
    fn test_next_with_simple_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "B");
    }

    #[test]
    fn test_next_with_complex_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "ABA");
    }
}
<commit_msg>Add to_string() methid for LSystems<commit_after>use std::collections::HashMap;

struct LSystem {
    alphabet: Vec<char>,
    constants: Vec<char>,
    start: String,
    rules: HashMap<char, String>,
}

impl LSystem {
    /// Some guarantees of a LSystem:
    /// 1. Every char in start is in alphabet
    /// 2. Given a rule X -> Y, X and Y are in alphabet
    /// 3. Each char in alphabet has a rule that maps it to something else
    ///   -> by default a char maps to itself, but this can be overriden with
    ///   the `push` method

    pub fn new(start: String) -> LSystem {
        // push chars in start to alphabet
        // and make them map to themselves in a rule
        let mut alphabet: Vec<char> = Vec::new();
        let mut rules: HashMap<char, String> = HashMap::new();
        for c in start.chars() {
            if !alphabet.contains(&c) {
                alphabet.push(c);
                rules.insert(c, c.to_string());
            }
        }

        LSystem {
            alphabet: alphabet,
            constants: Vec::new(),
            start: start,
            rules: rules,
        }
    }

    pub fn to_string(&self) -> String {
        self.start.clone()
    }

    pub fn next(&mut self) -> LSystem {
        let mut next = String::from("");
        for c in self.start.chars() {
            next.push_str(self.get(c));
        }

        LSystem {
            alphabet: self.alphabet.clone(),
            constants: self.constants.clone(),
            start: next,
            rules: self.rules.clone(),
        }
    }

    fn add_char(&mut self, c: char) {
        if !self.alphabet.contains(&c) {
            self.alphabet.push(c);
            self.rules.insert(c, c.to_string());
        }
    }

    pub fn push(&mut self, rule: HashMap<char, String>) {
        for (key, value) in &rule {
            // Make sure that key, value is in alphabet
            for c in value.chars() {
                self.add_char(c);
            }
            if !self.rules.contains_key(key) {
                self.add_char(*key);
            }
            // Add key value pair
            *self.rules.get_mut(key).unwrap() = value.to_owned();
        }
    }

    /// Returns the value that key maps to
    pub fn get(&self, key: char) -> &String {
        &self.rules[&key]
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use LSystem;

    #[test]
    fn test_new_should_have_correct_alphabet() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert!(lsys.alphabet.contains(&'A'));
    }

    #[test]
    fn test_new_should_have_correct_start() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.start, "AB");
    }

    #[test]
    fn test_new_should_not_have_duplicate_alphabet_chars() {
        let lsys: LSystem = LSystem::new("AA".to_string());
        assert_eq!(lsys.alphabet.len(), 1);
    }

    #[test]
    fn test_new_should_add_default_rules() {
        let lsys: LSystem = LSystem::new("A".to_string());
        assert_eq!(*lsys.get('A'), "A");
    }

    #[test]
    fn test_push_should_override_existing_rule() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('A'), "B");
    }

    #[test]
    fn test_push_should_add_to_alphabet() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert!(lsys.alphabet.contains(&'B'));
    }

    #[test]
    fn test_push_should_add_default_rules_for_new_chars() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "B");
    }

    #[test]
    fn test_push_should_work_with_multiple_rules() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        assert_eq!(*lsys.get('B'), "A");
        assert_eq!(*lsys.get('A'), "AB");
    }

    #[test]
    fn test_next_with_simple_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("A".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "B".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "B");
    }

    #[test]
    fn test_next_with_complex_rules_should_have_correct_start() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next();
        assert_eq!(next.start, "ABA");
    }

    #[test]
    fn test_next_should_work_in_chains() {
        let mut lsys: LSystem = LSystem::new("AB".to_string());
        let mut rule: HashMap<char, String> = HashMap::new();
        rule.insert('A', "AB".to_string());
        rule.insert('B', "A".to_string());
        lsys.push(rule);
        let next: LSystem = lsys.next().next();
        assert_eq!(next.start, "ABAAB");
    }

    #[test]
    fn test_to_string_should_return_start_string() {
        let lsys: LSystem = LSystem::new("AB".to_string());
        assert_eq!(lsys.to_string(), "AB");
    }
}
<|endoftext|>


<commit_before>extern crate conduit;

use std::error::Error;

use conduit::{Request, Response, Handler};

pub trait Middleware: Send + Sync + 'static {
    fn before(&self, _: &mut dyn Request) -> Result<(), Box<dyn Error+Send>> {
        Ok(())
    }

    fn after(&self, _: &mut dyn Request, res: Result<Response, Box<dyn Error+Send>>)
             -> Result<Response, Box<dyn Error+Send>>
    {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<dyn Handler>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<dyn Middleware>>,
    handler: Option<Box<dyn Handler>>
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec!(),
            handler: Some(Box::new(handler) as Box<dyn Handler>)
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares.push(Box::new(middleware) as Box<dyn Middleware>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(Box::new(middleware) as Box<dyn Handler>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error+Send>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = &self.middlewares[..i];
                run_afters(middlewares, req, Err(err))
            },
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = &self.middlewares;

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(middleware: &[Box<dyn Middleware>],
                  req: &mut dyn Request,
                  res: Result<Response, Box<dyn Error+Send>>)
                  -> Result<Response, Box<dyn Error+Send>>
{
    middleware.iter().rev().fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {MiddlewareBuilder, Middleware, AroundMiddleware};

    use std::any::Any;
    use std::collections::HashMap;
    use std::error::Error;
    use std::io::{self, Cursor};
    use std::io::prelude::*;
    use std::net::SocketAddr;

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

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method
    }

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

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method.clone() }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str { &self.path }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_addr(&self) -> SocketAddr { unimplemented!() }
        fn content_length(&self) -> Option<u64> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a dyn Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut dyn Read { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut dyn Request) -> Result<(), Box<dyn Error+Send>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(&self, _: &mut dyn Request, res: Result<Response, Box<dyn Error+Send>>)
                     -> Result<Response, Box<dyn Error+Send>>
        {
            res.or_else(|e| {
                let e = e.to_string();
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: Box::new(Cursor::new(e.into_bytes()))
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut dyn Request) -> Result<(), Box<dyn Error+Send>> {
            Err(Box::new(io::Error::new(io::ErrorKind::Other, "")))
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(&self, _: &mut dyn Request, _: Result<Response, Box<dyn Error+Send>>)
                     -> Result<Response, Box<dyn Error+Send>>
        {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(Cursor::new(vec!()))
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<dyn Handler>>
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<dyn Handler>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error+Send>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    fn get_extension<'a, T: Any>(req: &'a dyn Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(Cursor::new(string.into_bytes()))
        }
    }

    fn handler(req: &mut dyn Request) -> io::Result<Response> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut dyn Request) -> io::Result<Response> {
        Err(io::Error::new(io::ErrorKind::Other, "Error in handler"))
    }

    fn middle_handler(req: &mut dyn Request) -> io::Result<Response> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"hello");
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"Error in handler");
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"hello hello");
    }
}
<commit_msg>`cargo fmt`<commit_after>extern crate conduit;

use std::error::Error;

use conduit::{Handler, Request, Response};

pub trait Middleware: Send + Sync + 'static {
    fn before(&self, _: &mut dyn Request) -> Result<(), Box<dyn Error + Send>> {
        Ok(())
    }

    fn after(
        &self,
        _: &mut dyn Request,
        res: Result<Response, Box<dyn Error + Send>>,
    ) -> Result<Response, Box<dyn Error + Send>> {
        res
    }
}

pub trait AroundMiddleware: Handler {
    fn with_handler(&mut self, handler: Box<dyn Handler>);
}

pub struct MiddlewareBuilder {
    middlewares: Vec<Box<dyn Middleware>>,
    handler: Option<Box<dyn Handler>>,
}

impl MiddlewareBuilder {
    pub fn new<H: Handler>(handler: H) -> MiddlewareBuilder {
        MiddlewareBuilder {
            middlewares: vec![],
            handler: Some(Box::new(handler) as Box<dyn Handler>),
        }
    }

    pub fn add<M: Middleware>(&mut self, middleware: M) {
        self.middlewares
            .push(Box::new(middleware) as Box<dyn Middleware>);
    }

    pub fn around<M: AroundMiddleware>(&mut self, mut middleware: M) {
        let handler = self.handler.take().unwrap();
        middleware.with_handler(handler);
        self.handler = Some(Box::new(middleware) as Box<dyn Handler>);
    }
}

impl Handler for MiddlewareBuilder {
    fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let mut error = None;

        for (i, middleware) in self.middlewares.iter().enumerate() {
            match middleware.before(req) {
                Ok(_) => (),
                Err(err) => {
                    error = Some((err, i));
                    break;
                }
            }
        }

        match error {
            Some((err, i)) => {
                let middlewares = &self.middlewares[..i];
                run_afters(middlewares, req, Err(err))
            }
            None => {
                let res = { self.handler.as_ref().unwrap().call(req) };
                let middlewares = &self.middlewares;

                run_afters(middlewares, req, res)
            }
        }
    }
}

fn run_afters(
    middleware: &[Box<dyn Middleware>],
    req: &mut dyn Request,
    res: Result<Response, Box<dyn Error + Send>>,
) -> Result<Response, Box<dyn Error + Send>> {
    middleware
        .iter()
        .rev()
        .fold(res, |res, m| m.after(req, res))
}

#[cfg(test)]
mod tests {
    extern crate semver;

    use {AroundMiddleware, Middleware, MiddlewareBuilder};

    use std::any::Any;
    use std::collections::HashMap;
    use std::error::Error;
    use std::io::prelude::*;
    use std::io::{self, Cursor};
    use std::net::SocketAddr;

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

    struct RequestSentinel {
        path: String,
        extensions: TypeMap,
        method: Method,
    }

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

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version {
            unimplemented!()
        }
        fn conduit_version(&self) -> semver::Version {
            unimplemented!()
        }
        fn method(&self) -> Method {
            self.method.clone()
        }
        fn scheme(&self) -> Scheme {
            unimplemented!()
        }
        fn host<'a>(&'a self) -> Host<'a> {
            unimplemented!()
        }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> {
            unimplemented!()
        }
        fn path<'a>(&'a self) -> &'a str {
            &self.path
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> {
            unimplemented!()
        }
        fn remote_addr(&self) -> SocketAddr {
            unimplemented!()
        }
        fn content_length(&self) -> Option<u64> {
            unimplemented!()
        }
        fn headers<'a>(&'a self) -> &'a dyn Headers {
            unimplemented!()
        }
        fn body<'a>(&'a mut self) -> &'a mut dyn Read {
            unimplemented!()
        }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    struct MyMiddleware;

    impl Middleware for MyMiddleware {
        fn before<'a>(&self, req: &'a mut dyn Request) -> Result<(), Box<dyn Error + Send>> {
            req.mut_extensions().insert("hello".to_string());
            Ok(())
        }
    }

    struct ErrorRecovery;

    impl Middleware for ErrorRecovery {
        fn after(
            &self,
            _: &mut dyn Request,
            res: Result<Response, Box<dyn Error + Send>>,
        ) -> Result<Response, Box<dyn Error + Send>> {
            res.or_else(|e| {
                let e = e.to_string();
                Ok(Response {
                    status: (500, "Internal Server Error"),
                    headers: HashMap::new(),
                    body: Box::new(Cursor::new(e.into_bytes())),
                })
            })
        }
    }

    struct ProducesError;

    impl Middleware for ProducesError {
        fn before(&self, _: &mut dyn Request) -> Result<(), Box<dyn Error + Send>> {
            Err(Box::new(io::Error::new(io::ErrorKind::Other, "")))
        }
    }

    struct NotReached;

    impl Middleware for NotReached {
        fn after(
            &self,
            _: &mut dyn Request,
            _: Result<Response, Box<dyn Error + Send>>,
        ) -> Result<Response, Box<dyn Error + Send>> {
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: Box::new(Cursor::new(vec![])),
            })
        }
    }

    struct MyAroundMiddleware {
        handler: Option<Box<dyn Handler>>,
    }

    impl MyAroundMiddleware {
        fn new() -> MyAroundMiddleware {
            MyAroundMiddleware { handler: None }
        }
    }

    impl Middleware for MyAroundMiddleware {}

    impl AroundMiddleware for MyAroundMiddleware {
        fn with_handler(&mut self, handler: Box<dyn Handler>) {
            self.handler = Some(handler)
        }
    }

    impl Handler for MyAroundMiddleware {
        fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
            req.mut_extensions().insert("hello".to_string());
            self.handler.as_ref().unwrap().call(req)
        }
    }

    fn get_extension<'a, T: Any>(req: &'a dyn Request) -> &'a T {
        req.extensions().find::<T>().unwrap()
    }

    fn response(string: String) -> Response {
        Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: Box::new(Cursor::new(string.into_bytes())),
        }
    }

    fn handler(req: &mut dyn Request) -> io::Result<Response> {
        let hello = get_extension::<String>(req);
        Ok(response(hello.clone()))
    }

    fn error_handler(_: &mut dyn Request) -> io::Result<Response> {
        Err(io::Error::new(io::ErrorKind::Other, "Error in handler"))
    }

    fn middle_handler(req: &mut dyn Request) -> io::Result<Response> {
        let hello = get_extension::<String>(req);
        let middle = get_extension::<String>(req);

        Ok(response(format!("{} {}", hello, middle)))
    }

    #[test]
    fn test_simple_middleware() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(MyMiddleware);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"hello");
    }

    #[test]
    fn test_error_recovery() {
        let mut builder = MiddlewareBuilder::new(handler);
        builder.add(ErrorRecovery);
        builder.add(ProducesError);
        // the error bubbles up from ProducesError and shouldn't reach here
        builder.add(NotReached);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
    }

    #[test]
    fn test_error_recovery_in_handlers() {
        let mut builder = MiddlewareBuilder::new(error_handler);
        builder.add(ErrorRecovery);

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("Error not handled");

        assert_eq!(res.status, (500, "Internal Server Error"));
        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"Error in handler");
    }

    #[test]
    fn test_around_middleware() {
        let mut builder = MiddlewareBuilder::new(middle_handler);
        builder.add(MyMiddleware);
        builder.around(MyAroundMiddleware::new());

        let mut req = RequestSentinel::new(Method::Get, "/");
        let mut res = builder.call(&mut req).ok().expect("No response");

        let mut s = Vec::new();
        res.body.write_body(&mut s).unwrap();
        assert_eq!(s, b"hello hello");
    }
}
<|endoftext|>


<commit_before>//! A crate that implements [editorconfig](http://editorconfig.org/).
extern crate regex;

extern crate ordermap;

mod ini;
use regex::{Regex, Captures};

use ordermap::OrderMap;

use std::path::{Path, PathBuf};
use std::error::Error;

/// Finds all possible `conffile`s starting from `path` until root.
fn crawl_paths(path: &Path, conffile: &str) -> Result<Vec<PathBuf>, Box<Error>> {
    let mut path = if path.exists() {
        path.canonicalize()?
    } else {
        path.to_path_buf()
    };

    let mut result = vec![];
    while path.parent().is_some() {
        let mut adjacent_file = path.clone();
        adjacent_file.set_file_name(conffile);
        path.pop();
        if !adjacent_file.exists() {
            continue;
        }
        result.push(adjacent_file);
    }
    return Ok(result);
}

fn has_imbalanced_braces(text: &str) -> bool {
    let mut depth = 0i32;
    let escaped_brace_regex = Regex::new(r"\\(\{|\})").unwrap();
    let text = escaped_brace_regex.replace_all(text, "");
    for c in text.chars() {
        if c == '{' {
            depth += 1;
        } else if c == '}' {
            depth -= 1;
            if depth < 0 {
                return true;
            }
        }
    }
    return depth != 0;
}

fn translate_alternation(caps: &Captures) -> String {
    if has_imbalanced_braces(&caps[1]) {
        // println!("\"{}\" has imbalanced braces", &caps[1]);
        return format!("{{{}}}", &caps[1].replace("{", r"\{").replace("}", r"\}"));
    }
    let padded_cases = format!(",{},", &caps[1]);
    let quantifier = if padded_cases.contains(",,") { "?" } else { "" };
    let cases = caps[1].replace(",", "|");
    // println!(" 1 {}", cases);
    let escaped_comma_regex = Regex::new(r"(^|[^\\])\\\|").unwrap();
    let cases = escaped_comma_regex.replace(&cases, "$1,");
    // println!(" 2 {}", cases);
    format!("(?:{}){}", cases, quantifier)
}

fn glob_match(pattern: &String, candidate: &String) -> bool {
    let orig_had_slash = pattern.contains('/');
    // Step 1. Escape the crap out of the existing pattern
    // println!("B: {}", pattern);
    let pattern = pattern.replace(".", r"\.");
    let unmatched_open_bracket_regex = Regex::new(r"\[([^\]]*)$").unwrap();
    let pattern = unmatched_open_bracket_regex.replace_all(&pattern, r"\[$1")
        .to_string();
    // Step 2. Convert sh globs to regexes
    let pattern = pattern.replace("?", ".");
    let bracketed_slash_regex = Regex::new(r"\[(.*/.*)\]").unwrap();
    let pattern = bracketed_slash_regex.replace_all(&pattern, r"\[$1\]");
    // Handling * and ** is weird but this actually works
    let pattern = pattern.replace("*", "[^/]*");
    let pattern = pattern.replace("[^/]*[^/]*", ".*");
    // Store numeric ranges separately and replace with capture groups for numbers
    // Since all other input groups are non-capturing, just make sure every capture group in the output
    // matches the corresponding range.
    let numeric_range_regex = Regex::new(r"\{(-?\d+\\\.\\\.-?\d+)\}").unwrap();
    let has_numeric_ranges = numeric_range_regex.is_match(&pattern);
    // println!("D: {} <- {}", pattern, numeric_range_regex);
    let numeric_ranges: Vec<_> = numeric_range_regex.captures_iter(&pattern).collect();
    let pattern = numeric_range_regex.replace_all(&pattern, r"(0|-?[1-9]\d*)");
    // If we had /**/, make the directory and leading / optional
    let pattern = pattern.replace("/.*/", "(?:/.*)?/");
    let pattern = pattern.replace("[!", "[^");
    // Handle single-option "alternation" manually earlier
    let fake_alternation_regex = Regex::new(r"\{([^,]+)\}").unwrap();
    let pattern = fake_alternation_regex.replace_all(&pattern, r"\{$1\}").to_string();
    let mut pattern = pattern;
    // Can use , or | between cases, no } directly after opening {, no backslash before final }
    let alternation_regex = Regex::new(r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}").unwrap();
    // Since nesting can be infinite, run until there is no more alternation
    while alternation_regex.is_match(&pattern) {
        // println!("{} matches {} at {}", pattern, alternation_regex, alternation_regex.captures(&pattern).unwrap().get(0).unwrap().as_str());
        pattern = alternation_regex.replace_all(&pattern, translate_alternation).to_string();
        // println!("D: {}", pattern);
    }
    let leading_slash_regex = Regex::new(r"^/").unwrap();
    let pattern = leading_slash_regex.replace(&pattern, "^");
    // Yes, this is a bit complex, but I don't want "\{" to become "\\{"
    let unescaped_brace_regex = Regex::new(r"(^|[^\\])(\{|\})").unwrap();
    let pattern = unescaped_brace_regex.replace_all(&pattern, r"$1\$2");
    // Run it again to catch overlaps ({{)
    let pattern = unescaped_brace_regex.replace_all(&pattern, r"$1\$2");
    let pattern = pattern.replace("||", "|");
    let pattern = pattern.replace("(?:|", "(?:");
    let pattern = pattern.replace("|)", ")");
    // Only allow subdirectories if no directory was specified to begin with
    let leading_expr = if orig_had_slash {
        ""
    } else {
        "(?:.*?/)?"
    };
    let pattern = format!("^{}{}$", leading_expr, pattern);
    // println!("A: {} / {}", pattern, candidate);
    // Step 3. Actually do the testing
    let final_regex = Regex::new(&pattern).unwrap();
    if has_numeric_ranges && final_regex.is_match(candidate) {
        let caps: Vec<_> = final_regex.captures_iter(candidate).collect();
        for (num, range_spec) in caps.iter().zip(numeric_ranges.iter()) {
            if let Ok(num) = num.get(1).unwrap().as_str().parse::<i32>() {
                let ends: Vec<Result<i32, _>> = range_spec.get(1).unwrap().as_str().split(r"\.\.").map(|x| x.parse()).collect();
                if let Ok(min) = ends[0] {
                    if let Ok(max) = ends[1] {
                        if min > num || num > max {
                            return false;
                        }
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }
    return final_regex.is_match(candidate);
}

fn parse_config(target: &Path, conf_file: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    let context = conf_file.parent().unwrap();
    let ini_data = ini::Ini::load_from_file(conf_file)?;
    let mut result = OrderMap::new();
    if let Some(general) = ini_data.section::<String>(None) {
        if let Some(root) = general.get("root") {
            if root.to_lowercase() == "true" {
                result.insert("root".to_string(), "true".to_string());
            }
        }
    }
    let target = target.strip_prefix(&context)?;
    let target = target.as_os_str().to_os_string().into_string().unwrap();
    #[cfg(windows)]
    let target = target.replace("\\", "/");
    for (label, data) in ini_data.iter() {
        if let Some(ref label) = *label {
            if label.len() > 4096 {
                continue;
            }
            if glob_match(label, &target) {
                for (k, v) in data.iter() {
                    result.insert(k.clone(), v.clone());
                }
            }
        }
    }

    // Preprocessing may or may not actually be part of the spec
    // so I'm stealing this from editorconfig-core-py
    if let Some(indent_style) = result.clone().get("indent_style") {
        if indent_style == "tab" {
            if result.get("indent_size").is_none() {
                result.insert("indent_size".to_string(), "tab".to_string());
            }
        }
    }
    if let Some(indent_size) = result.clone().get("indent_size") {
        if indent_size != "tab" {
            if result.get("tab_width").is_none() {
                result.insert("tab_width".to_string(), indent_size.clone());
            }
        } else {
            if let Some(tab_width) = result.clone().get("tab_width") {
                result.insert("indent_size".to_string(), tab_width.clone());
            }
        }
    }
    Ok(result)
}

fn is_known_key(key: &str) -> bool {
    let known_keys = ["indent_style",
                      "indent_size",
                      "tab_width",
                      "end_of_line",
                      "charset",
                      "trim_trailing_whitespace",
                      "insert_final_newline"];
    known_keys.contains(&key)
}

/// Finds the configuration that applies to the file passed in `file_path`.
///
/// The `file_path` argument is the path to a file.
///
/// It looks for a file named `.editorconfig` in the file's directory and in every parent directory.
/// A search for `.editorconfig` files will stop if root (`/`) is reached or an `.editorconfig` file with `root=true` is found.
///
/// # Example
/// ```
/// use std::path::Path;
///
/// let path = Path::new("./test_files/simple/file.txt");
/// let path = path.canonicalize().unwrap();
/// let res = editorconfig::get_config(&path).unwrap();
/// for (k, v) in res.iter() {
///     println!("{}={}", *k, *v);
/// }
/// ```
/// # Errors
///  It returns an error:
///
/// - when it can't parse it
///
/// - when the `file_path` is malformed (check `std::fs::canonicalize` docs) or is a directory.
///
pub fn get_config(file_path: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    get_config_conffile(file_path, ".editorconfig")
}

/// Finds actual configuration that applies to file with given path.
/// # MAINLY USED FOR TESTING AND INTERNAL USE, CHECK `get_config`.
///
/// Looks for config data in given filename; in normal operation this will be ".editorconfig".
pub fn get_config_conffile(file_path: &Path,
                           conffile: &str)
                           -> Result<OrderMap<String, String>, Box<Error>> {
    let paths = crawl_paths(file_path, conffile)?;

    let mut result = OrderMap::new();
    for conf_path in paths {
        let options = parse_config(file_path, &conf_path)?;
        let old_result = result;
        result = OrderMap::new();
        for (k, v) in options.iter() {
            let k = k.to_lowercase();
            let v = if is_known_key(&k) {
                v.to_lowercase()
            } else {
                v.clone()
            };
            if k.len() > 50 || v.len() > 255 {
                continue;
            }
            if !result.contains_key(&k) && k != "root" {
                result.insert(k, v);
            }
        }
        for (k, v) in old_result.iter() {
            result.insert(k.clone(), v.clone());
        }
        if let Some(root) = options.get("root") {
            if root.to_lowercase() == "true" {
                break;
            }
        }
    }
    return Ok(result);
}

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

    #[test]
    fn works_with_multi_level_directories() {
        let path = Path::new("./test_files/multi_level/foo/bar/file.txt");
        let path = path.canonicalize().unwrap();
        let cfg = get_config(&path).unwrap();
        let mut map = OrderMap::new();
        map.insert("end_of_line".to_owned(), "lf".to_owned());
        map.insert("insert_final_newline".to_owned(), "true".to_owned());
        assert_eq!(cfg, map);
    }

    #[test]
    fn get_editorconfig_for_non_existing_file() {
        assert!(get_config(Path::new("./test_files/diocano")).is_ok());
    }
}
<commit_msg>Remove debugging code<commit_after>//! A crate that implements [editorconfig](http://editorconfig.org/).
extern crate regex;

extern crate ordermap;

mod ini;
use regex::{Regex, Captures};

use ordermap::OrderMap;

use std::path::{Path, PathBuf};
use std::error::Error;

/// Finds all possible `conffile`s starting from `path` until root.
fn crawl_paths(path: &Path, conffile: &str) -> Result<Vec<PathBuf>, Box<Error>> {
    let mut path = if path.exists() {
        path.canonicalize()?
    } else {
        path.to_path_buf()
    };

    let mut result = vec![];
    while path.parent().is_some() {
        let mut adjacent_file = path.clone();
        adjacent_file.set_file_name(conffile);
        path.pop();
        if !adjacent_file.exists() {
            continue;
        }
        result.push(adjacent_file);
    }
    return Ok(result);
}

fn has_imbalanced_braces(text: &str) -> bool {
    let mut depth = 0i32;
    let escaped_brace_regex = Regex::new(r"\\(\{|\})").unwrap();
    let text = escaped_brace_regex.replace_all(text, "");
    for c in text.chars() {
        if c == '{' {
            depth += 1;
        } else if c == '}' {
            depth -= 1;
            if depth < 0 {
                return true;
            }
        }
    }
    return depth != 0;
}

fn translate_alternation(caps: &Captures) -> String {
    if has_imbalanced_braces(&caps[1]) {
        return format!("{{{}}}", &caps[1].replace("{", r"\{").replace("}", r"\}"));
    }
    let padded_cases = format!(",{},", &caps[1]);
    let quantifier = if padded_cases.contains(",,") { "?" } else { "" };
    let cases = caps[1].replace(",", "|");
    let escaped_comma_regex = Regex::new(r"(^|[^\\])\\\|").unwrap();
    let cases = escaped_comma_regex.replace(&cases, "$1,");
    format!("(?:{}){}", cases, quantifier)
}

fn glob_match(pattern: &String, candidate: &String) -> bool {
    let orig_had_slash = pattern.contains('/');
    // Step 1. Escape the crap out of the existing pattern
    let pattern = pattern.replace(".", r"\.");
    let unmatched_open_bracket_regex = Regex::new(r"\[([^\]]*)$").unwrap();
    let pattern = unmatched_open_bracket_regex.replace_all(&pattern, r"\[$1")
        .to_string();
    // Step 2. Convert sh globs to regexes
    let pattern = pattern.replace("?", ".");
    let bracketed_slash_regex = Regex::new(r"\[(.*/.*)\]").unwrap();
    let pattern = bracketed_slash_regex.replace_all(&pattern, r"\[$1\]");
    // Handling * and ** is weird but this actually works
    let pattern = pattern.replace("*", "[^/]*");
    let pattern = pattern.replace("[^/]*[^/]*", ".*");
    // Store numeric ranges separately and replace with capture groups for numbers
    // Since all other input groups are non-capturing, just make sure every capture group in the output
    // matches the corresponding range.
    let numeric_range_regex = Regex::new(r"\{(-?\d+\\\.\\\.-?\d+)\}").unwrap();
    let has_numeric_ranges = numeric_range_regex.is_match(&pattern);
    let numeric_ranges: Vec<_> = numeric_range_regex.captures_iter(&pattern).collect();
    let pattern = numeric_range_regex.replace_all(&pattern, r"(0|-?[1-9]\d*)");
    // If we had /**/, make the directory and leading / optional
    let pattern = pattern.replace("/.*/", "(?:/.*)?/");
    let pattern = pattern.replace("[!", "[^");
    // Handle single-option "alternation" manually earlier
    let fake_alternation_regex = Regex::new(r"\{([^,]+)\}").unwrap();
    let pattern = fake_alternation_regex.replace_all(&pattern, r"\{$1\}").to_string();
    let mut pattern = pattern;
    // Can use , or | between cases, no } directly after opening {, no backslash before final }
    let alternation_regex = Regex::new(r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}").unwrap();
    // Since nesting can be infinite, run until there is no more alternation
    while alternation_regex.is_match(&pattern) {
        pattern = alternation_regex.replace_all(&pattern, translate_alternation).to_string();
    }
    let leading_slash_regex = Regex::new(r"^/").unwrap();
    let pattern = leading_slash_regex.replace(&pattern, "^");
    // Yes, this is a bit complex, but I don't want "\{" to become "\\{"
    let unescaped_brace_regex = Regex::new(r"(^|[^\\])(\{|\})").unwrap();
    let pattern = unescaped_brace_regex.replace_all(&pattern, r"$1\$2");
    // Run it again to catch overlaps ({{)
    let pattern = unescaped_brace_regex.replace_all(&pattern, r"$1\$2");
    let pattern = pattern.replace("||", "|");
    let pattern = pattern.replace("(?:|", "(?:");
    let pattern = pattern.replace("|)", ")");
    // Only allow subdirectories if no directory was specified to begin with
    let leading_expr = if orig_had_slash {
        ""
    } else {
        "(?:.*?/)?"
    };
    let pattern = format!("^{}{}$", leading_expr, pattern);
    // Step 3. Actually do the testing
    let final_regex = Regex::new(&pattern).unwrap();
    if has_numeric_ranges && final_regex.is_match(candidate) {
        let caps: Vec<_> = final_regex.captures_iter(candidate).collect();
        for (num, range_spec) in caps.iter().zip(numeric_ranges.iter()) {
            if let Ok(num) = num.get(1).unwrap().as_str().parse::<i32>() {
                let ends: Vec<Result<i32, _>> = range_spec.get(1).unwrap().as_str().split(r"\.\.").map(|x| x.parse()).collect();
                if let Ok(min) = ends[0] {
                    if let Ok(max) = ends[1] {
                        if min > num || num > max {
                            return false;
                        }
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }
    return final_regex.is_match(candidate);
}

fn parse_config(target: &Path, conf_file: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    let context = conf_file.parent().unwrap();
    let ini_data = ini::Ini::load_from_file(conf_file)?;
    let mut result = OrderMap::new();
    if let Some(general) = ini_data.section::<String>(None) {
        if let Some(root) = general.get("root") {
            if root.to_lowercase() == "true" {
                result.insert("root".to_string(), "true".to_string());
            }
        }
    }
    let target = target.strip_prefix(&context)?;
    let target = target.as_os_str().to_os_string().into_string().unwrap();
    #[cfg(windows)]
    let target = target.replace("\\", "/");
    for (label, data) in ini_data.iter() {
        if let Some(ref label) = *label {
            if label.len() > 4096 {
                continue;
            }
            if glob_match(label, &target) {
                for (k, v) in data.iter() {
                    result.insert(k.clone(), v.clone());
                }
            }
        }
    }

    // Preprocessing may or may not actually be part of the spec
    // so I'm stealing this from editorconfig-core-py
    if let Some(indent_style) = result.clone().get("indent_style") {
        if indent_style == "tab" {
            if result.get("indent_size").is_none() {
                result.insert("indent_size".to_string(), "tab".to_string());
            }
        }
    }
    if let Some(indent_size) = result.clone().get("indent_size") {
        if indent_size != "tab" {
            if result.get("tab_width").is_none() {
                result.insert("tab_width".to_string(), indent_size.clone());
            }
        } else {
            if let Some(tab_width) = result.clone().get("tab_width") {
                result.insert("indent_size".to_string(), tab_width.clone());
            }
        }
    }
    Ok(result)
}

fn is_known_key(key: &str) -> bool {
    let known_keys = ["indent_style",
                      "indent_size",
                      "tab_width",
                      "end_of_line",
                      "charset",
                      "trim_trailing_whitespace",
                      "insert_final_newline"];
    known_keys.contains(&key)
}

/// Finds the configuration that applies to the file passed in `file_path`.
///
/// The `file_path` argument is the path to a file.
///
/// It looks for a file named `.editorconfig` in the file's directory and in every parent directory.
/// A search for `.editorconfig` files will stop if root (`/`) is reached or an `.editorconfig` file with `root=true` is found.
///
/// # Example
/// ```
/// use std::path::Path;
///
/// let path = Path::new("./test_files/simple/file.txt");
/// let path = path.canonicalize().unwrap();
/// let res = editorconfig::get_config(&path).unwrap();
/// for (k, v) in res.iter() {
///     println!("{}={}", *k, *v);
/// }
/// ```
/// # Errors
///  It returns an error:
///
/// - when it can't parse it
///
/// - when the `file_path` is malformed (check `std::fs::canonicalize` docs) or is a directory.
///
pub fn get_config(file_path: &Path) -> Result<OrderMap<String, String>, Box<Error>> {
    get_config_conffile(file_path, ".editorconfig")
}

/// Finds actual configuration that applies to file with given path.
/// # MAINLY USED FOR TESTING AND INTERNAL USE, CHECK `get_config`.
///
/// Looks for config data in given filename; in normal operation this will be ".editorconfig".
pub fn get_config_conffile(file_path: &Path,
                           conffile: &str)
                           -> Result<OrderMap<String, String>, Box<Error>> {
    let paths = crawl_paths(file_path, conffile)?;

    let mut result = OrderMap::new();
    for conf_path in paths {
        let options = parse_config(file_path, &conf_path)?;
        let old_result = result;
        result = OrderMap::new();
        for (k, v) in options.iter() {
            let k = k.to_lowercase();
            let v = if is_known_key(&k) {
                v.to_lowercase()
            } else {
                v.clone()
            };
            if k.len() > 50 || v.len() > 255 {
                continue;
            }
            if !result.contains_key(&k) && k != "root" {
                result.insert(k, v);
            }
        }
        for (k, v) in old_result.iter() {
            result.insert(k.clone(), v.clone());
        }
        if let Some(root) = options.get("root") {
            if root.to_lowercase() == "true" {
                break;
            }
        }
    }
    return Ok(result);
}

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

    #[test]
    fn works_with_multi_level_directories() {
        let path = Path::new("./test_files/multi_level/foo/bar/file.txt");
        let path = path.canonicalize().unwrap();
        let cfg = get_config(&path).unwrap();
        let mut map = OrderMap::new();
        map.insert("end_of_line".to_owned(), "lf".to_owned());
        map.insert("insert_final_newline".to_owned(), "true".to_owned());
        assert_eq!(cfg, map);
    }

    #[test]
    fn get_editorconfig_for_non_existing_file() {
        assert!(get_config(Path::new("./test_files/diocano")).is_ok());
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![doc(html_root_url = "https://docs.rs/reqwest/0.10.8")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP
//! [`Client`][client].
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Async and [blocking](blocking) Clients
//! - Plain bodies, [JSON](#json), [urlencoded](#forms), [multipart](multipart)
//! - Customizable [redirect policy](#redirect-policies)
//! - HTTP [Proxies](#proxies)
//! - Uses system-native [TLS](#tls)
//! - Cookies
//!
//! The [`reqwest::Client`][client] is asynchronous. For applications wishing
//! to only make a few HTTP requests, the [`reqwest::blocking`](blocking) API
//! may be more convenient.
//!
//! Additional learning resources include:
//!
//! - [The Rust Cookbook](https://rust-lang-nursery.github.io/rust-cookbook/web/clients.html)
//! - [Reqwest Repository Examples](https://github.com/seanmonstar/reqwest/tree/master/examples)
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! # async fn run() -> Result<(), reqwest::Error> {
//! let body = reqwest::get("https://www.rust-lang.org")
//!     .await?
//!     .text()
//!     .await?;
//!
//! println!("body = {:?}", body);
//! # Ok(())
//! # }
//! ```
//!
//! **NOTE**: If you plan to perform multiple requests, it is best to create a
//! [`Client`][client] and reuse it, taking advantage of keep-alive connection
//! pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! type, you can use the `reqwest::Body` constructors.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .body("the exact body that is sent")
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .form(&params)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON. The feature `json` is required.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # #[cfg(feature = "json")]
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .json(&map)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Redirect Policies
//!
//! By default, a `Client` will automatically handle HTTP redirects, having a
//! maximum redirect chain of 10 hops. To customize this behavior, a
//! [`redirect::Policy`][redirect] can be used with a `ClientBuilder`.
//!
//! ## Cookies
//!
//! The automatic storing and sending of session cookies can be enabled with
//! the [`cookie_store`][ClientBuilder::cookie_store] method on `ClientBuilder`.
//!
//! ## Proxies
//!
//! **NOTE**: System proxies are enabled by default.
//!
//! System proxies look in environment variables to set HTTP or HTTPS proxies.
//!
//! `HTTP_PROXY` or `http_proxy` provide http proxies for http connections while
//! `HTTPS_PROXY` or `https_proxy` provide HTTPS proxies for HTTPS connections.
//!
//! These can be overwritten by adding a [`Proxy`](Proxy) to `ClientBuilder`
//! i.e. `let proxy = reqwest::Proxy::http("https://secure.example")?;`
//! or disabled by calling `ClientBuilder::no_proxy()`.
//!
//! `socks` feature is required if you have configured socks proxy like this:
//!
//! ```bash
//! export https_proxy=socks5://127.0.0.1:1086
//! ```
//!
//! ## TLS
//!
//! By default, a `Client` will make use of system-native transport layer
//! security to connect to HTTPS destinations. This means schannel on Windows,
//! Security-Framework on macOS, and OpenSSL on Linux.
//!
//! - Additional X509 certificates can be configured on a `ClientBuilder` with the
//!   [`Certificate`](Certificate) type.
//! - Client certificates can be add to a `ClientBuilder` with the
//!   [`Identity`][Identity] type.
//! - Various parts of TLS can also be configured or even disabled on the
//!   `ClientBuilder`.
//!
//! ## Optional Features
//!
//! The following are a list of [Cargo features][cargo-features] that can be
//! enabled or disabled:
//!
//! - **default-tls** *(enabled by default)*: Provides TLS support to connect
//!   over HTTPS.
//! - **native-tls**: Enables TLS functionality provided by `native-tls`.
//! - **native-tls-vendored**: Enables the `vendored` feature of `native-tls`.
//! - **rustls-tls**: Enables TLS functionality provided by `rustls`.
//! - **blocking**: Provides the [blocking][] client API.
//! - **cookies**: Provides cookie session support.
//! - **gzip**: Provides response body gzip decompression.
//! - **brotli**: Provides response body brotli decompression.
//! - **json**: Provides serialization and deserialization for JSON bodies.
//! - **stream**: Adds support for `futures::Stream`.
//! - **socks**: Provides SOCKS5 proxy support.
//! - **trust-dns**: Enables a trust-dns async resolver instead of default
//!   threadpool using `getaddrinfo`.
//!
//!
//! [hyper]: http://hyper.rs
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./struct.RequestBuilder.html
//! [serde]: http://serde.rs
//! [redirect]: crate::redirect
//! [Proxy]: ./struct.Proxy.html
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

macro_rules! if_wasm {
    ($($item:item)*) => {$(
        #[cfg(target_arch = "wasm32")]
        $item
    )*}
}

macro_rules! if_hyper {
    ($($item:item)*) => {$(
        #[cfg(not(target_arch = "wasm32"))]
        $item
    )*}
}

pub use http::header;
pub use http::Method;
pub use http::{StatusCode, Version};
pub use url::Url;

// universal mods
#[macro_use]
mod error;
mod into_url;

pub use self::error::{Error, Result};
pub use self::into_url::IntoUrl;

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// **NOTE**: This function creates a new internal `Client` on each call,
/// and so should not be used if making many requests. Create a
/// [`Client`](./struct.Client.html) instead.
///
/// # Examples
///
/// ```rust
/// # async fn run() -> Result<(), reqwest::Error> {
/// let body = reqwest::get("https://www.rust-lang.org").await?
///     .text().await?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect limit was exhausted
pub async fn get<T: IntoUrl>(url: T) -> crate::Result<Response> {
    Client::builder().build()?.get(url).send().await
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    #[cfg(not(target_arch = "wasm32"))]
    {
        assert_send::<Response>();
    }

    assert_send::<Error>();
    assert_sync::<Error>();
}

if_hyper! {
    #[cfg(test)]
    #[macro_use]
    extern crate doc_comment;

    #[macro_use]
    extern crate lazy_static;

    #[cfg(test)]
    doctest!("../README.md");

    pub use self::async_impl::{
        multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt,
    };
    pub use self::proxy::Proxy;
    #[cfg(feature = "__tls")]
    pub use self::tls::{Certificate, Identity};

    mod async_impl;
    #[cfg(feature = "blocking")]
    pub mod blocking;
    mod connect;
    #[cfg(feature = "cookies")]
    pub mod cookie;
    #[cfg(feature = "trust-dns")]
    mod dns;
    mod proxy;
    pub mod redirect;
    #[cfg(feature = "__tls")]
    mod tls;
    mod util;
}

if_wasm! {
    mod wasm;
    mod util;

    pub use self::wasm::{multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response};
}
<commit_msg>chore(docs): fix missing link for 'blocking'<commit_after>#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![cfg_attr(test, deny(warnings))]
#![doc(html_root_url = "https://docs.rs/reqwest/0.10.8")]

//! # reqwest
//!
//! The `reqwest` crate provides a convenient, higher-level HTTP
//! [`Client`][client].
//!
//! It handles many of the things that most people just expect an HTTP client
//! to do for them.
//!
//! - Async and [blocking](blocking) Clients
//! - Plain bodies, [JSON](#json), [urlencoded](#forms), [multipart](multipart)
//! - Customizable [redirect policy](#redirect-policies)
//! - HTTP [Proxies](#proxies)
//! - Uses system-native [TLS](#tls)
//! - Cookies
//!
//! The [`reqwest::Client`][client] is asynchronous. For applications wishing
//! to only make a few HTTP requests, the [`reqwest::blocking`](blocking) API
//! may be more convenient.
//!
//! Additional learning resources include:
//!
//! - [The Rust Cookbook](https://rust-lang-nursery.github.io/rust-cookbook/web/clients.html)
//! - [Reqwest Repository Examples](https://github.com/seanmonstar/reqwest/tree/master/examples)
//!
//! ## Making a GET request
//!
//! For a single request, you can use the [`get`][get] shortcut method.
//!
//! ```rust
//! # async fn run() -> Result<(), reqwest::Error> {
//! let body = reqwest::get("https://www.rust-lang.org")
//!     .await?
//!     .text()
//!     .await?;
//!
//! println!("body = {:?}", body);
//! # Ok(())
//! # }
//! ```
//!
//! **NOTE**: If you plan to perform multiple requests, it is best to create a
//! [`Client`][client] and reuse it, taking advantage of keep-alive connection
//! pooling.
//!
//! ## Making POST requests (or setting request bodies)
//!
//! There are several ways you can set the body of a request. The basic one is
//! by using the `body()` method of a [`RequestBuilder`][builder]. This lets you set the
//! exact raw bytes of what the body should be. It accepts various types,
//! including `String`, `Vec<u8>`, and `File`. If you wish to pass a custom
//! type, you can use the `reqwest::Body` constructors.
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .body("the exact body that is sent")
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Forms
//!
//! It's very common to want to send form data in a request body. This can be
//! done with any type that can be serialized into form data.
//!
//! This can be an array of tuples, or a `HashMap`, or a custom type that
//! implements [`Serialize`][serde].
//!
//! ```rust
//! # use reqwest::Error;
//! #
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `foo=bar&baz=quux`
//! let params = [("foo", "bar"), ("baz", "quux")];
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .form(&params)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### JSON
//!
//! There is also a `json` method helper on the [`RequestBuilder`][builder] that works in
//! a similar fashion the `form` method. It can take any value that can be
//! serialized into JSON. The feature `json` is required.
//!
//! ```rust
//! # use reqwest::Error;
//! # use std::collections::HashMap;
//! #
//! # #[cfg(feature = "json")]
//! # async fn run() -> Result<(), Error> {
//! // This will POST a body of `{"lang":"rust","body":"json"}`
//! let mut map = HashMap::new();
//! map.insert("lang", "rust");
//! map.insert("body", "json");
//!
//! let client = reqwest::Client::new();
//! let res = client.post("http://httpbin.org/post")
//!     .json(&map)
//!     .send()
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Redirect Policies
//!
//! By default, a `Client` will automatically handle HTTP redirects, having a
//! maximum redirect chain of 10 hops. To customize this behavior, a
//! [`redirect::Policy`][redirect] can be used with a `ClientBuilder`.
//!
//! ## Cookies
//!
//! The automatic storing and sending of session cookies can be enabled with
//! the [`cookie_store`][ClientBuilder::cookie_store] method on `ClientBuilder`.
//!
//! ## Proxies
//!
//! **NOTE**: System proxies are enabled by default.
//!
//! System proxies look in environment variables to set HTTP or HTTPS proxies.
//!
//! `HTTP_PROXY` or `http_proxy` provide http proxies for http connections while
//! `HTTPS_PROXY` or `https_proxy` provide HTTPS proxies for HTTPS connections.
//!
//! These can be overwritten by adding a [`Proxy`](Proxy) to `ClientBuilder`
//! i.e. `let proxy = reqwest::Proxy::http("https://secure.example")?;`
//! or disabled by calling `ClientBuilder::no_proxy()`.
//!
//! `socks` feature is required if you have configured socks proxy like this:
//!
//! ```bash
//! export https_proxy=socks5://127.0.0.1:1086
//! ```
//!
//! ## TLS
//!
//! By default, a `Client` will make use of system-native transport layer
//! security to connect to HTTPS destinations. This means schannel on Windows,
//! Security-Framework on macOS, and OpenSSL on Linux.
//!
//! - Additional X509 certificates can be configured on a `ClientBuilder` with the
//!   [`Certificate`](Certificate) type.
//! - Client certificates can be add to a `ClientBuilder` with the
//!   [`Identity`][Identity] type.
//! - Various parts of TLS can also be configured or even disabled on the
//!   `ClientBuilder`.
//!
//! ## Optional Features
//!
//! The following are a list of [Cargo features][cargo-features] that can be
//! enabled or disabled:
//!
//! - **default-tls** *(enabled by default)*: Provides TLS support to connect
//!   over HTTPS.
//! - **native-tls**: Enables TLS functionality provided by `native-tls`.
//! - **native-tls-vendored**: Enables the `vendored` feature of `native-tls`.
//! - **rustls-tls**: Enables TLS functionality provided by `rustls`.
//! - **blocking**: Provides the [blocking][] client API.
//! - **cookies**: Provides cookie session support.
//! - **gzip**: Provides response body gzip decompression.
//! - **brotli**: Provides response body brotli decompression.
//! - **json**: Provides serialization and deserialization for JSON bodies.
//! - **stream**: Adds support for `futures::Stream`.
//! - **socks**: Provides SOCKS5 proxy support.
//! - **trust-dns**: Enables a trust-dns async resolver instead of default
//!   threadpool using `getaddrinfo`.
//!
//!
//! [hyper]: http://hyper.rs
//! [blocking]: ./blocking/index.html
//! [client]: ./struct.Client.html
//! [response]: ./struct.Response.html
//! [get]: ./fn.get.html
//! [builder]: ./struct.RequestBuilder.html
//! [serde]: http://serde.rs
//! [redirect]: crate::redirect
//! [Proxy]: ./struct.Proxy.html
//! [cargo-features]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-features-section

macro_rules! if_wasm {
    ($($item:item)*) => {$(
        #[cfg(target_arch = "wasm32")]
        $item
    )*}
}

macro_rules! if_hyper {
    ($($item:item)*) => {$(
        #[cfg(not(target_arch = "wasm32"))]
        $item
    )*}
}

pub use http::header;
pub use http::Method;
pub use http::{StatusCode, Version};
pub use url::Url;

// universal mods
#[macro_use]
mod error;
mod into_url;

pub use self::error::{Error, Result};
pub use self::into_url::IntoUrl;

/// Shortcut method to quickly make a `GET` request.
///
/// See also the methods on the [`reqwest::Response`](./struct.Response.html)
/// type.
///
/// **NOTE**: This function creates a new internal `Client` on each call,
/// and so should not be used if making many requests. Create a
/// [`Client`](./struct.Client.html) instead.
///
/// # Examples
///
/// ```rust
/// # async fn run() -> Result<(), reqwest::Error> {
/// let body = reqwest::get("https://www.rust-lang.org").await?
///     .text().await?;
/// # Ok(())
/// # }
/// ```
///
/// # Errors
///
/// This function fails if:
///
/// - native TLS backend cannot be initialized
/// - supplied `Url` cannot be parsed
/// - there was an error while sending request
/// - redirect limit was exhausted
pub async fn get<T: IntoUrl>(url: T) -> crate::Result<Response> {
    Client::builder().build()?.get(url).send().await
}

fn _assert_impls() {
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    fn assert_clone<T: Clone>() {}

    assert_send::<Client>();
    assert_sync::<Client>();
    assert_clone::<Client>();

    assert_send::<Request>();
    assert_send::<RequestBuilder>();

    #[cfg(not(target_arch = "wasm32"))]
    {
        assert_send::<Response>();
    }

    assert_send::<Error>();
    assert_sync::<Error>();
}

if_hyper! {
    #[cfg(test)]
    #[macro_use]
    extern crate doc_comment;

    #[macro_use]
    extern crate lazy_static;

    #[cfg(test)]
    doctest!("../README.md");

    pub use self::async_impl::{
        multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response, ResponseBuilderExt,
    };
    pub use self::proxy::Proxy;
    #[cfg(feature = "__tls")]
    pub use self::tls::{Certificate, Identity};

    mod async_impl;
    #[cfg(feature = "blocking")]
    pub mod blocking;
    mod connect;
    #[cfg(feature = "cookies")]
    pub mod cookie;
    #[cfg(feature = "trust-dns")]
    mod dns;
    mod proxy;
    pub mod redirect;
    #[cfg(feature = "__tls")]
    mod tls;
    mod util;
}

if_wasm! {
    mod wasm;
    mod util;

    pub use self::wasm::{multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response};
}
<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate json_ipc_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use json_ipc_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("/tmp/json-ipc-test.ipc", &Arc::new(io));
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

extern crate mio;
extern crate jsonrpc_core;
extern crate bytes;
extern crate slab;

use mio::*;
use mio::unix::*;
use bytes::{Buf, ByteBuf, MutByteBuf};
use std::io;
use jsonrpc_core::IoHandler;
use std::sync::*;

const SERVER: Token = Token(0);

struct SocketConnection {
    socket: UnixStream,
    buf: Option<ByteBuf>,
    mut_buf: Option<MutByteBuf>,
    token: Option<Token>,
    interest: EventSet,
}

type Slab<T> = slab::Slab<T, Token>;

impl SocketConnection {
    fn new(sock: UnixStream) -> Self {
        SocketConnection {
            socket: sock,
            buf: None,
            mut_buf: Some(ByteBuf::mut_with_capacity(2048)),
            token: None,
            interest: EventSet::hup(),
        }
    }

    fn writable(&mut self, event_loop: &mut EventLoop<RpcServer>, _handler: &IoHandler) -> io::Result<()> {
        use std::io::Write;
        if let Some(buf) = self.buf.take() {
            try!(self.socket.write_all(&buf.bytes()));
        }

        self.interest.remove(EventSet::writable());
        self.interest.insert(EventSet::readable());

        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }

    fn readable(&mut self, event_loop: &mut EventLoop<RpcServer>, handler: &IoHandler) -> io::Result<()> {
        let mut buf = self.mut_buf.take().unwrap_or_else(|| panic!("unwrapping mutable buffer which is None"));

        match self.socket.try_read_buf(&mut buf) {
            Ok(None) => {
                self.mut_buf = Some(buf);
            }
            Ok(Some(_)) => {
                String::from_utf8(buf.bytes().to_vec())
                    .map(|rpc_msg| {
                        let response: Option<String> = handler.handle_request(&rpc_msg);
                        if let Some(response_str) = response {
                            let response_bytes = response_str.into_bytes();
                            self.buf = Some(ByteBuf::from_slice(&response_bytes));
                        }
                    }).unwrap();

                self.mut_buf = Some(buf);

                self.interest.remove(EventSet::readable());
                self.interest.insert(EventSet::writable());
            }
            Err(_) => {
                //warn!(target: "ipc", "Error receiving data: {:?}", e);
                self.interest.remove(EventSet::readable());
            }

        };

        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }
}

struct RpcServer {
    socket: UnixListener,
    connections: Slab<SocketConnection>,
    io_handler: Arc<IoHandler>,
}

pub struct Server {
    rpc_server: RwLock<RpcServer>,
    event_loop: RwLock<EventLoop<RpcServer>>,
}

impl Server {
    /// New server
    pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Server {
        let (server, event_loop) = RpcServer::start(socket_addr, io_handler);
        Server {
            rpc_server: RwLock::new(server),
            event_loop: RwLock::new(event_loop),
        }
    }

    /// Run server (blocking)
    pub fn run(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();
        event_loop.run(&mut server).unwrap();
    }

    /// Poll server requests
    pub fn poll(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();

        event_loop.run_once(&mut server, Some(100)).unwrap();
    }
}

impl RpcServer {

    /// start ipc rpc server (blocking)
    pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> (RpcServer, EventLoop<RpcServer>) {
        let mut event_loop = EventLoop::new().unwrap();
        ::std::fs::remove_file(addr).unwrap_or_else(|_| {} ); // ignore error (if no file)
        let socket = UnixListener::bind(&addr).unwrap();
        event_loop.register(&socket, SERVER, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
        let server = RpcServer {
            socket: socket,
            connections: Slab::new_starting_at(Token(1), 8),
            io_handler: io_handler.clone(),
        };
        (server, event_loop)
    }

    fn accept(&mut self, event_loop: &mut EventLoop<RpcServer>) -> io::Result<()> {
        let new_client_socket = self.socket.accept().unwrap().unwrap();
        let connection = SocketConnection::new(new_client_socket);
        let token = self.connections.insert(connection).ok().expect("fatal: Could not add connectiont o slab (memory issue?)");

        self.connections[token].token = Some(token);
        event_loop.register(
            &self.connections[token].socket,
            token,
            EventSet::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        ).ok().expect("could not register socket with event loop (memory issue?)");

        Ok(())
    }

    fn connection_readable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).readable(event_loop, &io_handler)
    }

    fn connection_writable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).writable(event_loop, &io_handler)
    }

    fn connection<'a>(&'a mut self, tok: Token) -> &'a mut SocketConnection {
        &mut self.connections[tok]
    }
}

impl Handler for RpcServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<RpcServer>, token: Token, events: EventSet) {
        if events.is_readable() {
            match token {
                SERVER => self.accept(event_loop).unwrap(),
                _ => self.connection_readable(event_loop, token).unwrap()
            };
        }

        if events.is_writable() {
            match token {
                SERVER => { },
                _ => self.connection_writable(event_loop, token).unwrap_or_else(|_| {}), // todo: disqualify connection from list on error
            };
        }
    }
}

#[cfg(test)]
fn dummy_request(addr: &str, buf: &[u8]) -> Vec<u8> {
    use std::io::{Read, Write};

    let mut poll = Poll::new().unwrap();
    let mut sock = UnixStream::connect(addr).unwrap();
    poll.register(&sock, Token(0), EventSet::writable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
    poll.poll(Some(500)).unwrap();
    sock.write_all(buf).unwrap();
    poll.reregister(&sock, Token(0), EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
    poll.poll(Some(500)).unwrap();

    let mut buf = Vec::new();
    sock.read_to_end(&mut buf).unwrap_or_else(|_| { 0 });
    buf
}

#[cfg(test)]
fn dummy_io_handler() -> Arc<IoHandler> {
    use std::sync::Arc;
    use jsonrpc_core::*;

    struct SayHello;
    impl MethodCommand for SayHello {
        fn execute(&self, _params: Params) -> Result<Value, Error> {
            Ok(Value::String("hello".to_string()))
        }
    }

    let io = IoHandler::new();
    io.add_method("say_hello", SayHello);
    Arc::new(io)
}

#[test]
pub fn test_reqrep() {
    let addr = "/tmp/test10";
    let io = dummy_io_handler();
    let server = Server::new(addr, &io);
    std::thread::spawn(move || {
        server.run()
    });

    let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

    assert_eq!(String::from_utf8(dummy_request(addr, request.as_bytes())).unwrap(), response.to_string());
}
#[test]
pub fn test_reqrep_poll() {
    let addr = "/tmp/test20";
    let io = dummy_io_handler();
    let server = Server::new(addr, &io);
    std::thread::spawn(move || {
        loop {
            server.poll();
        }
    });

    let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;
    assert_eq!(String::from_utf8(dummy_request(addr, request.as_bytes())).unwrap(), response.to_string());

    std::thread::sleep(std::time::Duration::from_millis(500));
}<commit_msg>error mapping<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate json_ipc_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use json_ipc_server::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("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

extern crate mio;
extern crate jsonrpc_core;
extern crate bytes;
extern crate slab;

use mio::*;
use mio::unix::*;
use bytes::{Buf, ByteBuf, MutByteBuf};
use std::io;
use jsonrpc_core::IoHandler;
use std::sync::*;

const SERVER: Token = Token(0);

struct SocketConnection {
    socket: UnixStream,
    buf: Option<ByteBuf>,
    mut_buf: Option<MutByteBuf>,
    token: Option<Token>,
    interest: EventSet,
}

type Slab<T> = slab::Slab<T, Token>;

impl SocketConnection {
    fn new(sock: UnixStream) -> Self {
        SocketConnection {
            socket: sock,
            buf: None,
            mut_buf: Some(ByteBuf::mut_with_capacity(2048)),
            token: None,
            interest: EventSet::hup(),
        }
    }

    fn writable(&mut self, event_loop: &mut EventLoop<RpcServer>, _handler: &IoHandler) -> io::Result<()> {
        use std::io::Write;
        if let Some(buf) = self.buf.take() {
            try!(self.socket.write_all(&buf.bytes()));
        }

        self.interest.remove(EventSet::writable());
        self.interest.insert(EventSet::readable());

        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }

    fn readable(&mut self, event_loop: &mut EventLoop<RpcServer>, handler: &IoHandler) -> io::Result<()> {
        let mut buf = self.mut_buf.take().unwrap_or_else(|| panic!("unwrapping mutable buffer which is None"));

        match self.socket.try_read_buf(&mut buf) {
            Ok(None) => {
                self.mut_buf = Some(buf);
            }
            Ok(Some(_)) => {
                String::from_utf8(buf.bytes().to_vec())
                    .map(|rpc_msg| {
                        let response: Option<String> = handler.handle_request(&rpc_msg);
                        if let Some(response_str) = response {
                            let response_bytes = response_str.into_bytes();
                            self.buf = Some(ByteBuf::from_slice(&response_bytes));
                        }
                    }).unwrap();

                self.mut_buf = Some(buf);

                self.interest.remove(EventSet::readable());
                self.interest.insert(EventSet::writable());
            }
            Err(_) => {
                //warn!(target: "ipc", "Error receiving data: {:?}", e);
                self.interest.remove(EventSet::readable());
            }

        };

        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }
}

struct RpcServer {
    socket: UnixListener,
    connections: Slab<SocketConnection>,
    io_handler: Arc<IoHandler>,
}

pub struct Server {
    rpc_server: RwLock<RpcServer>,
    event_loop: RwLock<EventLoop<RpcServer>>,
}

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
}

impl std::convert::From<std::io::Error> for Error {
    fn from(io_error: std::io::Error) -> Error {
        Error::Io(io_error)
    }
}

impl Server {
    /// New server
    pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Result<Server, Error> {
        let (server, event_loop) = try!(RpcServer::start(socket_addr, io_handler));
        Ok(Server {
            rpc_server: RwLock::new(server),
            event_loop: RwLock::new(event_loop),
        })
    }

    /// Run server (blocking)
    pub fn run(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();
        event_loop.run(&mut server).unwrap();
    }

    /// Poll server requests
    pub fn poll(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();

        event_loop.run_once(&mut server, Some(100)).unwrap();
    }
}

impl RpcServer {

    /// start ipc rpc server (blocking)
    pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> Result<(RpcServer, EventLoop<RpcServer>), Error> {
        let mut event_loop = try!(EventLoop::new());
        ::std::fs::remove_file(addr).unwrap_or_else(|_| {} ); // ignore error (if no file)
        let socket = try!(UnixListener::bind(&addr));
        event_loop.register(&socket, SERVER, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
        let server = RpcServer {
            socket: socket,
            connections: Slab::new_starting_at(Token(1), 8),
            io_handler: io_handler.clone(),
        };
        Ok((server, event_loop))
    }

    fn accept(&mut self, event_loop: &mut EventLoop<RpcServer>) -> io::Result<()> {
        let new_client_socket = self.socket.accept().unwrap().unwrap();
        let connection = SocketConnection::new(new_client_socket);
        let token = self.connections.insert(connection).ok().expect("fatal: Could not add connectiont o slab (memory issue?)");

        self.connections[token].token = Some(token);
        event_loop.register(
            &self.connections[token].socket,
            token,
            EventSet::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        ).ok().expect("could not register socket with event loop (memory issue?)");

        Ok(())
    }

    fn connection_readable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).readable(event_loop, &io_handler)
    }

    fn connection_writable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).writable(event_loop, &io_handler)
    }

    fn connection<'a>(&'a mut self, tok: Token) -> &'a mut SocketConnection {
        &mut self.connections[tok]
    }
}

impl Handler for RpcServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<RpcServer>, token: Token, events: EventSet) {
        if events.is_readable() {
            match token {
                SERVER => self.accept(event_loop).unwrap(),
                _ => self.connection_readable(event_loop, token).unwrap()
            };
        }

        if events.is_writable() {
            match token {
                SERVER => { },
                _ => self.connection_writable(event_loop, token).unwrap_or_else(|_| {}), // todo: disqualify connection from list on error
            };
        }
    }
}

#[cfg(test)]
fn dummy_request(addr: &str, buf: &[u8]) -> Vec<u8> {
    use std::io::{Read, Write};

    let mut poll = Poll::new().unwrap();
    let mut sock = UnixStream::connect(addr).unwrap();
    poll.register(&sock, Token(0), EventSet::writable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
    poll.poll(Some(500)).unwrap();
    sock.write_all(buf).unwrap();
    poll.reregister(&sock, Token(0), EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
    poll.poll(Some(500)).unwrap();

    let mut buf = Vec::new();
    sock.read_to_end(&mut buf).unwrap_or_else(|_| { 0 });
    buf
}

#[cfg(test)]
fn dummy_io_handler() -> Arc<IoHandler> {
    use std::sync::Arc;
    use jsonrpc_core::*;

    struct SayHello;
    impl MethodCommand for SayHello {
        fn execute(&self, _params: Params) -> Result<Value, Error> {
            Ok(Value::String("hello".to_string()))
        }
    }

    let io = IoHandler::new();
    io.add_method("say_hello", SayHello);
    Arc::new(io)
}

#[test]
pub fn test_reqrep() {
    let addr = "/tmp/test10";
    let io = dummy_io_handler();
    let server = Server::new(addr, &io).unwrap();
    std::thread::spawn(move || {
        server.run()
    });

    let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;

    assert_eq!(String::from_utf8(dummy_request(addr, request.as_bytes())).unwrap(), response.to_string());
}
#[test]
pub fn test_reqrep_poll() {
    let addr = "/tmp/test20";
    let io = dummy_io_handler();
    let server = Server::new(addr, &io).unwrap();
    std::thread::spawn(move || {
        loop {
            server.poll();
        }
    });

    let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":"hello","id":1}"#;
    assert_eq!(String::from_utf8(dummy_request(addr, request.as_bytes())).unwrap(), response.to_string());

    std::thread::sleep(std::time::Duration::from_millis(500));
}<|endoftext|>