<commit_before>#![feature(quote, rustc_private)]
#![feature(box_syntax)]

extern crate syntax;
extern crate rustc;
extern crate rustc_driver;

#[cfg(test)]
mod test {
    use std::io::Write;
    use syntax::ext::base::ExtCtxt;

    use syntax::ast;
    use syntax::parse;
    use syntax::ext;
    use syntax::print;

    use rustc::session::{build_session,Session};
    use rustc::session::config::{build_session_options,build_configuration, Input};
    use rustc_driver::{handle_options,diagnostics_registry};
    use rustc_driver::driver::{phase_1_parse_input, source_name};

    fn pprint(sess: Session, krate: &ast::Crate, src_name: String) {
        let src = sess.codemap().get_filemap(&src_name[..])
                            .src
                            .as_ref()
                            .unwrap()
                            .as_bytes()
                            .to_vec();
        let mut rdr = &src[..];

        let mut out = Vec::new();
        let ann = print::pprust::NoAnn;
        {
            let out_w: &mut Write = &mut out;
            print::pprust::print_crate(sess.codemap(),
                                            sess.diagnostic(),
                                            krate,
                                            src_name,
                                            &mut rdr,
                                            box out_w,
                                            &ann,
                                            false);
        }
        print!("{}", String::from_utf8(out).unwrap());
    }

    #[test]
    fn it_works() {
        let crate_src = "fn main(){}".to_string();

        let matches = match handle_options(vec!["".to_string(), "-".to_string()]) {
            Some(matches) => matches,
            None => unreachable!()
        };

        let descriptions = diagnostics_registry();
        let sopts = build_session_options(&matches);

        let sess = build_session(sopts, None, descriptions);
        let cfg = build_configuration(&sess);
        let input = Input::Str(crate_src);
        let krate = phase_1_parse_input(&sess, cfg, &input);
        println!("{:#?}", krate);

        let src_name = source_name(&input);
        pprint(sess, &krate, src_name);

        panic!("Lõpp");
        // let exc = ext::expand::ExpansionConfig::default(cratenam);
        // let cx = ExtCtxt::new(
        //     &sess.parse_sess,
        //     cfg,
        //     exc,
        // );
        // //
        // let x = quote_expr!(&cx, 1 + 2);
        // stringify!(x);
        // // println!("{:?}", );
    }

}
<commit_msg>test ast modification<commit_after>#![feature(quote, rustc_private)]
#![feature(box_syntax)]

extern crate syntax;
extern crate rustc;
extern crate rustc_driver;

#[cfg(test)]
mod test {
    use std::io::Write;
    use syntax::ext::base::ExtCtxt;

    use syntax::ast;
    use syntax::parse;
    use syntax::ext;
    use syntax::print;
    use syntax::codemap::{ExpnId, ExpnInfo, CompilerExpansion, NameAndSpan};

    use rustc::session::{build_session,Session};
    use rustc::session::config::{build_session_options,build_configuration, Input};
    use rustc_driver::{handle_options,diagnostics_registry};
    use rustc_driver::driver::{phase_1_parse_input, source_name};

    fn pprint(sess: &Session, krate: &ast::Crate, src_name: String) {
        let src = sess.codemap().get_filemap(&src_name[..])
                            .src
                            .as_ref()
                            .unwrap()
                            .as_bytes()
                            .to_vec();
        let mut rdr = &src[..];

        let mut out = Vec::new();
        let ann = print::pprust::NoAnn;
        {
            let out_w: &mut Write = &mut out;
            print::pprust::print_crate(sess.codemap(),
                                            sess.diagnostic(),
                                            krate,
                                            src_name,
                                            &mut rdr,
                                            box out_w,
                                            &ann,
                                            false);
        }
        print!("{}", String::from_utf8(out).unwrap());
    }

    #[test]
    fn it_works() {
        let crate_src = "fn main(){}".to_string();

        let matches = match handle_options(vec!["".to_string(), "-".to_string()]) {
            Some(matches) => matches,
            None => unreachable!()
        };

        let descriptions = diagnostics_registry();
        let sopts = build_session_options(&matches);

        let sess = build_session(sopts, None, descriptions);
        let cfg = build_configuration(&sess);
        let input = Input::Str(crate_src);
        let src_name = source_name(&input);

        let features = sess.features.borrow();
        let ecfg = ext::expand::ExpansionConfig {
            crate_name: src_name.clone(),
            features: Some(&features),
            recursion_limit: sess.recursion_limit.get(),
            trace_mac: sess.opts.debugging_opts.trace_macros,
        };

        let mut krate = phase_1_parse_input(&sess, cfg.clone(), &input);
        // println!("{:#?}", krate);
        {
            let mut cx = ExtCtxt::new(&sess.parse_sess, cfg, ecfg);
            cx.backtrace = ExpnId::from_u32(0);
            cx.codemap().record_expansion(
                ExpnInfo {
                    call_site: krate.span,
                    callee: NameAndSpan {
                        name: "mattis".to_string(),
                        format: CompilerExpansion,
                        allow_internal_unstable: true,
                        span: None,
                    },
                }
            );

            let x = quote_item!(&cx,
                fn foo() -> u32 {
                    let sum = 2 + 2;
                    sum
                }
            ).unwrap();
            krate.module.items.push(x);
        }
        println!("{:#?}", krate);

        pprint(&sess, &krate, src_name);

        panic!("Lõpp");
    }

}
<|endoftext|>


<commit_before>#![feature(str_char)]

#[derive(Debug, PartialEq)]
enum Atom {
    // Unquoted string
    Str(String),

    // Quoted string
    QStr(String),

    // Unsigned 64-bit integer
    UInt(u64),

    // Signed 64-bit integer
    SInt(i64),

    // 64-bit floating point number
    Float(f64),
}

#[derive(Debug, PartialEq)]
enum Expr {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Atom>),

    // [ ... ]
    Array(Vec<Atom>),

    // { key val ... }
    Map(Vec<(Atom, Atom)>),
}

#[derive(Debug, PartialEq)]
enum ParseError {
    PrematureEOS,
}

impl Atom {
    fn from_str(s: &str) -> Result<(Atom, &str), ParseError> {
        let delim: &[_] = &[' ', '\n', '\t', '(', ')', '[', ']', '{', '}'];
        match s.find(delim) {
            Some(pos) => Ok((Atom::Str(s[..pos].to_string()), &s[pos..])),
            None => {
                // complete string
                Ok((Atom::Str(s.to_string()), ""))
            }
        }
    }
}

#[derive(Debug, PartialEq)]
enum Token<'a> {
    Str(&'a str),
    QStr(&'a str),

    OpenBracket,
    CloseBracket,
    OpenBrace,
    CloseBrace,
    OpenCurly,
    CloseCurly,

    Int(&'a str),
    Float(&'a str),
}

const WHITESPACE: &'static [char] = &[' ', '\r', '\n', '\t'];
const TOKEN_DELIM: &'static [char] = &[' ', '\r', '\n', '\t', '(', ')', '[', ']', '{', '}', '"'];

fn skip_ws(s: &str) -> &str {
    s.trim_left_matches(WHITESPACE)
}

// ; comment
fn next_token<'a>(s: &'a str) -> Option<(Token<'a>, &'a str)> {
    let s = skip_ws(s);
    match s.slice_shift_char() {
        None => None,
        Some((c, s2)) => {
            match c {
                '(' => Some((Token::OpenBrace, s2)),
                ')' => Some((Token::CloseBrace, s2)),

                '[' => Some((Token::OpenBracket, s2)),
                ']' => Some((Token::CloseBracket, s2)),

                '{' => Some((Token::OpenCurly, s2)),
                '}' => Some((Token::CloseCurly, s2)),

                '"' => {
                    // TODO: QStr
                    None
                }

                '+' | '-' => {
                    // TODO
                    None
                }

                '0'...'9' => {
                    // Int, Float

                    match s.find(|c: char| !c.is_numeric()) {
                        Some(pos) => {
                            let (a, b) = s.split_at(pos);
                            match b.slice_shift_char() {
                                Some(('.', s2)) => {
                                    // integer continues
                                    match s2.find(|c: char| !c.is_numeric()) {
                                        None => Some((Token::Float(s), "")),
                                        Some(pos2) => {
                                            let (a, b) = s.split_at(pos + pos2 + 1);
                                            Some((Token::Float(a), b))
                                        }
                                    }
                                }
                                _ => Some((Token::Int(a), b)),
                            }
                        }
                        None => Some((Token::Int(s), "")),
                    }
                }

                _ => {
                    // Str
                    match s.find(TOKEN_DELIM) {
                        Some(pos) => {
                            let (a, b) = s.split_at(pos);
                            Some((Token::Str(a), b))
                        }
                        None => {
                            // complete string
                            Some((Token::Str(s), ""))
                        }
                    }
                }
            }
        }
    }
}

#[test]
fn test_tokenize() {
    assert_eq!(Some((Token::Str("abc"), "")), next_token("  abc"));
    assert_eq!(Some((Token::Str("abc"), "")), next_token("abc"));
    assert_eq!(Some((Token::Str("abc"), "(")), next_token("abc("));

    assert_eq!(Some((Token::OpenBrace, ")")), next_token("()"));

    assert_eq!(Some((Token::Int("12345"), "")), next_token("12345"));
    assert_eq!(Some((Token::Int("12345"), " ")), next_token("12345 "));
    assert_eq!(Some((Token::Int("12345"), "+")), next_token("12345+"));
    assert_eq!(Some((Token::Float("12345.123"), "")),
               next_token("12345.123"));
    assert_eq!(Some((Token::Float("12345.123"), "(")),
               next_token("12345.123("));
}
<commit_msg>Simplify the tokenizing<commit_after>#![feature(str_char)]

use std::char;

#[derive(Debug, PartialEq)]
enum Atom {
    // Unquoted string
    Str(String),

    // Quoted string
    QStr(String),

    // Unsigned 64-bit integer
    UInt(u64),

    // Signed 64-bit integer
    SInt(i64),

    // 64-bit floating point number
    Float(f64),
}

#[derive(Debug, PartialEq)]
enum Expr {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Atom>),

    // [ ... ]
    Array(Vec<Atom>),

    // { key val ... }
    Map(Vec<(Atom, Atom)>),
}

#[derive(Debug, PartialEq)]
enum ParseError {
    PrematureEOS,
}

impl Atom {
    fn from_str(s: &str) -> Result<(Atom, &str), ParseError> {
        let delim: &[_] = &[' ', '\n', '\t', '(', ')', '[', ']', '{', '}'];
        match s.find(delim) {
            Some(pos) => Ok((Atom::Str(s[..pos].to_string()), &s[pos..])),
            None => {
                // complete string
                Ok((Atom::Str(s.to_string()), ""))
            }
        }
    }
}

#[derive(Debug, PartialEq)]
enum Token<'a> {
    Error,

    Str(&'a str),
    QStr(&'a str),

    OpenBracket,
    CloseBracket,
    OpenBrace,
    CloseBrace,
    OpenCurly,
    CloseCurly,

    Int(&'a str),
    Float(&'a str),
}

#[inline]
fn scan<F: Fn(char) -> bool>(s: &str, cond: F) -> (&str, &str) {
    // split at the first non-"cond" character
    match s.find(|c: char| !cond(c)) {
        None => (s, ""),
        Some(pos) => s.split_at(pos),
    }
}

#[inline]
fn is_token_delim(c: char) -> bool {
    c.is_whitespace() || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' ||
    c == '"'
}

fn skip_ws(s: &str) -> &str {
    scan(s, char::is_whitespace).1
}

// ; comment
fn next_token<'a>(s: &'a str) -> Option<(Token<'a>, &'a str)> {
    let s = skip_ws(s);
    match s.slice_shift_char() {
        None => None,
        Some((c, s2)) => {
            match c {
                '(' => Some((Token::OpenBrace, s2)),
                ')' => Some((Token::CloseBrace, s2)),

                '[' => Some((Token::OpenBracket, s2)),
                ']' => Some((Token::CloseBracket, s2)),

                '{' => Some((Token::OpenCurly, s2)),
                '}' => Some((Token::CloseCurly, s2)),

                '"' => {
                    // TODO: QStr
                    None
                }

                '+' | '-' => {
                    // TODO
                    None
                }

                '0'...'9' => {
                    // Int, Float

                    let (basis, rest) = scan(s, char::is_numeric);
                    match rest.slice_shift_char() {
                        Some(('.', mantisse)) => {
                            // integer followed by "." => float
                            let (mantisse, _) = scan(mantisse, char::is_numeric);
                            let (full_float, rest) = s.split_at(basis.len() + 1 + mantisse.len());

                            Some((Token::Float(full_float), rest))
                        }
                        _ => Some((Token::Int(basis), rest)),
                    }
                }

                _ => {
                    // Str
                    let (string, rest) = scan(s, |c| !is_token_delim(c));
                    Some((Token::Str(string), rest))
                }
            }
        }
    }
}

#[test]
fn test_tokenize() {
    assert_eq!(Some((Token::Str("abc"), "")), next_token("  abc"));
    assert_eq!(Some((Token::Str("abc"), "")), next_token("abc"));
    assert_eq!(Some((Token::Str("abc"), "(")), next_token("abc("));

    assert_eq!(Some((Token::OpenBrace, ")")), next_token("()"));

    assert_eq!(Some((Token::Int("12345"), "")), next_token("12345"));
    assert_eq!(Some((Token::Int("12345"), " ")), next_token("12345 "));
    assert_eq!(Some((Token::Int("12345"), "+")), next_token("12345+"));
    assert_eq!(Some((Token::Float("12345.123"), "")),
               next_token("12345.123"));
    assert_eq!(Some((Token::Float("12345.123"), "(")),
               next_token("12345.123("));
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate unicase;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::status;
use iron::headers::{Origin,
					ContentType,
                    AccessControlRequestMethod,
                    AccessControlAllowOrigin,
                    AccessControlAllowHeaders,
                    AccessControlMaxAge,
                    AccessControlAllowMethods};
use iron::middleware::{AroundMiddleware, Handler};

struct CorsMiddleware;
impl AroundMiddleware for CorsMiddleware {

    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move | req: &mut Request | {
            let allowed_headers: Vec<unicase::UniCase<String>> = vec![
                    // To allow application/json
                    UniCase("Content-Type".to_owned()),
                    // Set by some js libs
                    UniCase("X-Requested-With".to_owned()),
                    ];
            let allowed_methods: Vec<Method> = vec![ Method::Get, Method::Put, Method::Post ];
            if req.method == Method::Options &&
                req.headers.get::<AccessControlRequestMethod>().is_some() {
                // Preflight request
                // 1.If the Origin header is not present terminate this set of steps. The request is
                // outside the scope of this specification.
                let maybe_origin = req.headers.get::<Origin>();
                if maybe_origin.is_none() {
                    let resp = Response::with((status::BadRequest,
                                               "Preflight request without Origin header"));
                    return Ok(resp);
                }
                let origin = maybe_origin.unwrap();
                let mut res = Response::with((status::NoContent));
                //
                // 2.If the value of the Origin header is not a case-sensitive match for any of the
                // values in list of origins do not set any additional headers and terminate this
                // set of steps.
                //
                // Note: Always matching is acceptable since the list of origins can be unbounded.
                //
                // Note: The Origin header can only contain a single origin as the user agent
                //       will not follow redirects.
                //
                // 3. Let method be the value as result of parsing the Access-Control-Request-Method
                // header.
                //
                // If there is no Access-Control-Request-Method header or if parsing failed, do not
                // set any additional headers and terminate this set of steps. The request is
                // outside the scope of this specification.
                //
                // 4. Let header field-names be the values as result of parsing the
                // Access-Control-Request-Headers headers.
                //
                // If there are no Access-Control-Request-Headers headers let header field-names be
                // the empty list.
                //
                // If parsing failed do not set any additional headers and terminate this set of
                // steps. The request is outside the scope of this specification.
                //
                // 5.If method is not a case-sensitive match for any of the values in list of
                //   methods do not set any additional headers and terminate this set of steps.
                //
                // Always matching is acceptable since the list of methods can be unbounded.
                //
                // 6. If any of the header field-names is not a ASCII case-insensitive match for any
                // of the values in list of headers do not set any additional headers and terminate
                // this set of steps.
                //
                // Always matching is acceptable since the list of headers can be unbounded.
                //
                // 7. If the resource supports credentials add a single Access-Control-Allow-Origin
                // header, with the value of the Origin header as value, and add a single
                // Access-Control-Allow-Credentials header with the case-sensitive string "true" as
                // value.
                //
                // Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // value of the Origin header or the string "*" as value.
                res.headers.set(AccessControlAllowOrigin::Value(format!("{}", origin)));
                //
                // The string "*" cannot be used for a resource that supports credentials.
                //
                // 8. Optionally add a single Access-Control-Max-Age header with as value the amount
                // of seconds the user agent is allowed to cache the result of the request.
                res.headers.set(AccessControlMaxAge(60*60));
                //
                // 9. If method is a simple method this step may be skipped.
                //
                // Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
                // the list of methods.
                res.headers.set(AccessControlAllowMethods(allowed_methods));
                //
                // If a method is a simple method it does not need to be listed, but this is not
                // prohibited.
                //
                // Since the list of methods can be unbounded, simply returning the method
                // indicated by Access-Control-Request-Method (if supported) can be enough.
                //
                // 10.If each of the header field-names is a simple header and none is Content-Type,
                // this step may be skipped.
                //
                // Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
                // the list of headers.
                res.headers.set(AccessControlAllowHeaders(allowed_headers));
                //
                // If a header field name is a simple header and is not Content-Type, it is not
                // required to be listed. Content-Type is to be listed as only a subset of its
                // values makes it qualify as simple header.
                //
                // Since the list of headers can be unbounded, simply returning supported headers
                // from Access-Control-Allow-Headers can be enough.
                Ok(res)
            } else {
                // Normal request
                // 1.If the Origin header is not present terminate this set of steps. The request is
                // outside the scope of this specification.
                let has_origin = req.headers.get::<Origin>().is_some();
                if !has_origin {
                    return handler.handle(req);
                }
                //
                // 2.If the value of the Origin header is not a case-sensitive match for any of the
                // values in list of origins, do not set any additional headers and terminate this
                // set of steps.
                //
                // Note: Always matching is acceptable since the list of origins can be unbounded.
                //
                // 3. If the resource supports credentials add a single Access-Control-Allow-Origin
                // header, with the value of the Origin header as value, and add a single
                // Access-Control-Allow-Credentials header with the case-sensitive string "true" as
                // value.
                //
                // Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // value of the Origin header or the string "*" as value.
                //
                // Note: The string "*" cannot be used for a resource that supports credentials.
                //
                // 4. If the list of exposed headers is not empty add one or more
                // Access-Control-Expose-Headers headers, with as values the header field names
                // given in the list of exposed headers.
                let result = handler.handle(req);
                match result {
                    Ok(mut res) => {
                        // And set CORS headers
                        let origin = req.headers.get::<Origin>().unwrap();
                        res.headers.set(AccessControlAllowOrigin::Value(format!("{}", origin)));
                        Ok(res)
                    }
                    _ => result
                }
            }
        })
    }
}

#[cfg(test)]
mod tests {
	extern crate router;
	extern crate hyper;
	use iron::Listening;
	use self::router::Router;
	use iron::prelude::*;
	use iron::status;
	use self::hyper::Client;
	use self::hyper::header::Headers;
	use std::io::Read;
    use iron::headers::{Origin,
					ContentType,
                    AccessControlRequestMethod,
                    AccessControlAllowOrigin,
                    AccessControlAllowHeaders,
                    AccessControlMaxAge,
                    AccessControlAllowMethods};
    use iron::middleware::{AroundMiddleware, Handler};
    use iron::method::Method;
    use super::CorsMiddleware;
    use std::str::FromStr;

	struct AutoServer {
		listening: Listening,
		port: u16
	}

	impl AutoServer {
		pub fn new() -> AutoServer {
			let mut router = Router::new();
			router.get("/a",
               |_: &mut Request| Ok(Response::with((status::ImATeapot, ""))),
               "get_a");
            let mut chain = Chain::new(router);
            chain.link_around(CorsMiddleware);
    		let l = Iron::new(chain).http(format!("localhost:0")).unwrap();
			let p = l.socket.port();
			AutoServer { listening: l, port: p }
		}
	}

	impl Drop for AutoServer {
		fn drop(&mut self) {
			// Workaround for https://github.com/hyperium/hyper/issues/338
			self.listening.close().unwrap();
		}
	}

    #[test]
    fn normal_request_possible() {
		let server = AutoServer::new();
		let client = Client::new();
		let res = client.get(&format!("http://127.0.0.1:{}/a", server.port)).send().unwrap();
		assert_eq!(res.status, status::ImATeapot);
	}

    #[test]
    fn preflight_without_origin_is_bad_request() {
		let server = AutoServer::new();
		let client = Client::new();
		let mut headers = Headers::new();
		headers.set(AccessControlRequestMethod(Method::Get));
		let mut res = client
				.request(Method::Options, &format!("http://127.0.0.1:{}/a", server.port))
				.headers(headers)
				.send().unwrap();
		assert_eq!(res.status, status::BadRequest);
        let mut payload = String::new();
        res.read_to_string(&mut payload).unwrap();
        assert_eq!(payload, "Preflight request without Origin header");
	}

    #[test]
    fn preflight_with_origin_accepts_same_origin() {
		let server = AutoServer::new();
		let client = Client::new();
		let mut headers = Headers::new();
		headers.set(AccessControlRequestMethod(Method::Get));
		headers.set(Origin::from_str("http://www.a.com:8080").unwrap());
		let mut res = client
				.request(Method::Options, &format!("http://127.0.0.1:{}/a", server.port))
				.headers(headers)
				.send().unwrap();
		assert_eq!(res.status, status::NoContent);
        let allow_origin = res.headers.get::<AccessControlAllowOrigin>().unwrap();
        assert_eq!(format!("{}", allow_origin) , "http://www.a.com:8080");
        let allow_headers = res.headers.get::<AccessControlAllowHeaders>().unwrap();
        assert_eq!(format!("{}", allow_headers) , "Content-Type, X-Requested-With");
        let allow_methods = res.headers.get::<AccessControlAllowMethods>().unwrap();
        assert_eq!(format!("{}", allow_methods) , "GET, PUT, POST");
        let max_age = res.headers.get::<AccessControlMaxAge>().unwrap();
        assert_eq!(max_age.0, 60*60u32);
	}
}
<commit_msg>working<commit_after>extern crate iron;
extern crate unicase;

use unicase::UniCase;
use iron::prelude::*;
use iron::method::Method;
use iron::status;
use iron::headers::{Origin,
					ContentType,
                    AccessControlRequestMethod,
                    AccessControlAllowOrigin,
                    AccessControlAllowHeaders,
                    AccessControlMaxAge,
                    AccessControlAllowMethods};
use iron::middleware::{AroundMiddleware, Handler};

struct CorsMiddleware;
impl AroundMiddleware for CorsMiddleware {

    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(move | req: &mut Request | {
            let allowed_headers: Vec<unicase::UniCase<String>> = vec![
                    // To allow application/json
                    UniCase("Content-Type".to_owned()),
                    // Set by some js libs
                    UniCase("X-Requested-With".to_owned()),
                    ];
            let allowed_methods: Vec<Method> = vec![ Method::Get, Method::Put, Method::Post ];
            if req.method == Method::Options &&
                req.headers.get::<AccessControlRequestMethod>().is_some() {
                // Preflight request
                // 1.If the Origin header is not present terminate this set of steps. The request is
                // outside the scope of this specification.
                let maybe_origin = req.headers.get::<Origin>();
                if maybe_origin.is_none() {
                    let resp = Response::with((status::BadRequest,
                                               "Preflight request without Origin header"));
                    return Ok(resp);
                }
                let origin = maybe_origin.unwrap();
                let mut res = Response::with((status::NoContent));
                //
                // 2.If the value of the Origin header is not a case-sensitive match for any of the
                // values in list of origins do not set any additional headers and terminate this
                // set of steps.
                //
                // Note: Always matching is acceptable since the list of origins can be unbounded.
                //
                // Note: The Origin header can only contain a single origin as the user agent
                //       will not follow redirects.
                //
                // 3. Let method be the value as result of parsing the Access-Control-Request-Method
                // header.
                //
                // If there is no Access-Control-Request-Method header or if parsing failed, do not
                // set any additional headers and terminate this set of steps. The request is
                // outside the scope of this specification.
                //
                // 4. Let header field-names be the values as result of parsing the
                // Access-Control-Request-Headers headers.
                //
                // If there are no Access-Control-Request-Headers headers let header field-names be
                // the empty list.
                //
                // If parsing failed do not set any additional headers and terminate this set of
                // steps. The request is outside the scope of this specification.
                //
                // 5.If method is not a case-sensitive match for any of the values in list of
                //   methods do not set any additional headers and terminate this set of steps.
                //
                // Always matching is acceptable since the list of methods can be unbounded.
                //
                // 6. If any of the header field-names is not a ASCII case-insensitive match for any
                // of the values in list of headers do not set any additional headers and terminate
                // this set of steps.
                //
                // Always matching is acceptable since the list of headers can be unbounded.
                //
                // 7. If the resource supports credentials add a single Access-Control-Allow-Origin
                // header, with the value of the Origin header as value, and add a single
                // Access-Control-Allow-Credentials header with the case-sensitive string "true" as
                // value.
                //
                // Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // value of the Origin header or the string "*" as value.
                res.headers.set(AccessControlAllowOrigin::Value(format!("{}", origin)));
                //
                // The string "*" cannot be used for a resource that supports credentials.
                //
                // 8. Optionally add a single Access-Control-Max-Age header with as value the amount
                // of seconds the user agent is allowed to cache the result of the request.
                res.headers.set(AccessControlMaxAge(60*60));
                //
                // 9. If method is a simple method this step may be skipped.
                //
                // Add one or more Access-Control-Allow-Methods headers consisting of (a subset of)
                // the list of methods.
                res.headers.set(AccessControlAllowMethods(allowed_methods));
                //
                // If a method is a simple method it does not need to be listed, but this is not
                // prohibited.
                //
                // Since the list of methods can be unbounded, simply returning the method
                // indicated by Access-Control-Request-Method (if supported) can be enough.
                //
                // 10.If each of the header field-names is a simple header and none is Content-Type,
                // this step may be skipped.
                //
                // Add one or more Access-Control-Allow-Headers headers consisting of (a subset of)
                // the list of headers.
                res.headers.set(AccessControlAllowHeaders(allowed_headers));
                //
                // If a header field name is a simple header and is not Content-Type, it is not
                // required to be listed. Content-Type is to be listed as only a subset of its
                // values makes it qualify as simple header.
                //
                // Since the list of headers can be unbounded, simply returning supported headers
                // from Access-Control-Allow-Headers can be enough.
                Ok(res)
            } else {
                // Normal request
                // 1.If the Origin header is not present terminate this set of steps. The request is
                // outside the scope of this specification.
                let has_origin = req.headers.get::<Origin>().is_some();
                if !has_origin {
                    return handler.handle(req);
                }
                //
                // 2.If the value of the Origin header is not a case-sensitive match for any of the
                // values in list of origins, do not set any additional headers and terminate this
                // set of steps.
                //
                // Note: Always matching is acceptable since the list of origins can be unbounded.
                //
                // 3. If the resource supports credentials add a single Access-Control-Allow-Origin
                // header, with the value of the Origin header as value, and add a single
                // Access-Control-Allow-Credentials header with the case-sensitive string "true" as
                // value.
                //
                // Otherwise, add a single Access-Control-Allow-Origin header, with either the
                // value of the Origin header or the string "*" as value.
                //
                // Note: The string "*" cannot be used for a resource that supports credentials.
                //
                // 4. If the list of exposed headers is not empty add one or more
                // Access-Control-Expose-Headers headers, with as values the header field names
                // given in the list of exposed headers.
                let result = handler.handle(req);
                match result {
                    Ok(mut res) => {
                        // And set CORS headers
                        let origin = req.headers.get::<Origin>().unwrap();
                        res.headers.set(AccessControlAllowOrigin::Value(format!("{}", origin)));
                        Ok(res)
                    }
                    _ => result
                }
            }
        })
    }
}

#[cfg(test)]
mod tests {
	extern crate router;
	extern crate hyper;
	use iron::Listening;
	use self::router::Router;
	use iron::prelude::*;
	use iron::status;
	use self::hyper::Client;
	use self::hyper::header::Headers;
	use std::io::Read;
    use iron::headers::{Origin,
					ContentType,
                    AccessControlRequestMethod,
                    AccessControlAllowOrigin,
                    AccessControlAllowHeaders,
                    AccessControlMaxAge,
                    AccessControlAllowMethods};
    use iron::middleware::{AroundMiddleware, Handler};
    use iron::method::Method;
    use super::CorsMiddleware;
    use std::str::FromStr;

	struct AutoServer {
		listening: Listening,
		port: u16
	}

	impl AutoServer {
		pub fn new() -> AutoServer {
			let mut router = Router::new();
			router.get("/a",
               |_: &mut Request| Ok(Response::with((status::ImATeapot, ""))),
               "get_a");
            let mut chain = Chain::new(router);
            chain.link_around(CorsMiddleware);
    		let l = Iron::new(chain).http(format!("localhost:0")).unwrap();
			let p = l.socket.port();
			AutoServer { listening: l, port: p }
		}
	}

	impl Drop for AutoServer {
		fn drop(&mut self) {
			// Workaround for https://github.com/hyperium/hyper/issues/338
			self.listening.close().unwrap();
		}
	}

    #[test]
    fn normal_request_possible() {
		let server = AutoServer::new();
		let client = Client::new();
		let res = client.get(&format!("http://127.0.0.1:{}/a", server.port)).send().unwrap();
		assert_eq!(res.status, status::ImATeapot);
	}

    #[test]
    fn preflight_without_origin_is_bad_request() {
		let server = AutoServer::new();
		let client = Client::new();
		let mut headers = Headers::new();
		headers.set(AccessControlRequestMethod(Method::Get));
		let mut res = client
				.request(Method::Options, &format!("http://127.0.0.1:{}/a", server.port))
				.headers(headers)
				.send().unwrap();
		assert_eq!(res.status, status::BadRequest);
        let mut payload = String::new();
        res.read_to_string(&mut payload).unwrap();
        assert_eq!(payload, "Preflight request without Origin header");
	}

    #[test]
    fn preflight_with_origin_accepts_same_origin() {
		let server = AutoServer::new();
		let client = Client::new();
		let mut headers = Headers::new();
		headers.set(AccessControlRequestMethod(Method::Get));
		headers.set(Origin::from_str("http://www.a.com:8080").unwrap());
		let mut res = client
				.request(Method::Options, &format!("http://127.0.0.1:{}/a", server.port))
				.headers(headers)
				.send().unwrap();
		assert_eq!(res.status, status::NoContent);
        let allow_origin = res.headers.get::<AccessControlAllowOrigin>().unwrap();
        assert_eq!(format!("{}", allow_origin) , "http://www.a.com:8080");
        let allow_headers = res.headers.get::<AccessControlAllowHeaders>().unwrap();
        assert_eq!(format!("{}", allow_headers) , "Content-Type, X-Requested-With");
        let allow_methods = res.headers.get::<AccessControlAllowMethods>().unwrap();
        assert_eq!(format!("{}", allow_methods) , "GET, PUT, POST");
        let max_age = res.headers.get::<AccessControlMaxAge>().unwrap();
        assert_eq!(max_age.0, 60*60u32);
	}

    #[test]
    fn normal_request_allows_origin() {
		let server = AutoServer::new();
		let client = Client::new();
		let mut headers = Headers::new();
		headers.set(Origin::from_str("http://www.a.com:8080").unwrap());
		let res = client
            .get(&format!("http://127.0.0.1:{}/a", server.port))
            .headers(headers)
            .send().unwrap();
		assert_eq!(res.status, status::ImATeapot);
        let allow_origin = res.headers.get::<AccessControlAllowOrigin>().unwrap();
        assert_eq!(format!("{}", allow_origin) , "http://www.a.com:8080");
        assert!(res.headers.get::<AccessControlAllowHeaders>().is_none());
        assert!(res.headers.get::<AccessControlAllowMethods>().is_none());
        assert!(res.headers.get::<AccessControlMaxAge>().is_none());
	}

    #[test]
    fn normal_request_without_origin_is_passthrough() {
		let server = AutoServer::new();
		let client = Client::new();
		let res = client
            .get(&format!("http://127.0.0.1:{}/a", server.port))
            .send().unwrap();
		assert_eq!(res.status, status::ImATeapot);
        assert!(res.headers.get::<AccessControlAllowOrigin>().is_none());
        assert!(res.headers.get::<AccessControlAllowHeaders>().is_none());
        assert!(res.headers.get::<AccessControlAllowMethods>().is_none());
        assert!(res.headers.get::<AccessControlMaxAge>().is_none());
	}

}
<|endoftext|>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

    matrix[(n, m)] as u32
}

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

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

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

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

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

    let mut last_row = BTreeMap::new();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        b.iter(|| damerau_levenshtein(text1, text2))
    }*/
}
<commit_msg>And tests should build on stable<commit_after>//! Txtdist is small utility crate for calculating the distance between two strings.

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

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

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

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

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

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

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

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

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

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

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

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

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

    matrix[(n, m)] as u32
}

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

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

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

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

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

    let mut last_row = BTreeMap::new();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


<commit_before>#![feature(custom_derive)]
#![feature(proc_macro)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

extern crate slog_stdlog;
extern crate slog_envlogger;

use serde_json::Value;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::slice::Iter;

#[derive(Deserialize, Debug)]
pub struct Response {
    took: u64,
    timed_out: bool,
    _shards: Shards,
    hits: Hits,
    aggregations: Option<Aggregations>,
    status: Option<u16>
}

#[derive(Deserialize, Debug)]
pub struct Aggregations(Value);

//QUESTION: Why do lifetimes go where they go, what am I missing?
//          What happens when lifetimes shadow each other?
//          Mental model for this?
//          Below works thanks to `misdreavus` on IRC, but I don't quite know why
impl<'a> IntoIterator for &'a Aggregations {
    //    type Item = BTreeMap<&'a String, &'a Value>;
    type Item = BTreeMap<Cow<'a, String>, &'a Value>;
    type IntoIter = AggregationIterator<'a>;

    fn into_iter(self) -> AggregationIterator<'a> {
        AggregationIterator::new(self)
    }
}

//FIXME: can this be run as a state-machine (ala https://hoverbear.org/2016/10/12/rust-state-machine-pattern/)
//#[derive(Debug)]
//enum AggStates {
//    AtRoot,
//    AtName,
//    InBuckets,
//    AtValues,
//    RowFinished
//}

#[derive(Debug)]
pub struct AggregationIterator<'a> {
    current_row: Option<BTreeMap<Cow<'a, String>, &'a Value>>,
    current_row_finished: bool,
    //QUESTION: Tracking traversal usng a stack of Iterators make sense? Is Vec right for this?
    iter_stack: Vec<(Option<&'a String>, Iter<'a, Value>)>,
    aggregations: &'a Aggregations
}

impl<'a> AggregationIterator<'a> {
    fn new(a: &'a Aggregations) -> AggregationIterator<'a> {
        let v = match a {
            &Aggregations(ref v) => v
        };

        let mut s: Vec<(Option<&String>, Iter<Value>)> = Vec::new();

        match *v {
            Value::Object(ref o) => {
                for (key, child) in o {
                    if let Value::Object(ref c) = *child {
                        if c.contains_key("buckets") {
                            if let Value::Array(ref a) = c["buckets"] {
                                let i = a.iter();
                                s.push((Some(&key), i));
                            }
                        }
                    }
                }
            },
            _ => {
                //FIXME: Bad for lib
                panic!("Not implemented, we only cater for bucket objects");
            }
        };

        AggregationIterator {
            current_row: None,
            current_row_finished: false,
            iter_stack: s,
            aggregations: a
        }
    }
}

macro_rules! insert_value {
    ($fieldname:expr, $json_object:ident, $keyname:ident, $rowdata:ident) => ({
      if $json_object.contains_key($fieldname) {
          let v = $json_object.get($fieldname);
          let field_name = format!("{}_{}", $keyname, $fieldname);
          debug! ("ITER: Insert value! {} {:?}", field_name, v.unwrap());
          $rowdata.insert(Cow::Owned(field_name), v.unwrap());
       }
	})
}

impl<'a> Iterator for AggregationIterator<'a> {
    type Item = BTreeMap<Cow<'a, String>, &'a Value>;

    fn next(&mut self) -> Option<BTreeMap<Cow<'a, String>, &'a Value>> {
        match self.current_row {
            None => {
                //New row
                self.current_row = Some(BTreeMap::new())
            },
            Some(_) => ()
        };

        loop {
            match self.iter_stack.pop() {
                None => {
                    debug! ("ITER: Done!");
                    match self.current_row {
                        Some(_) => {
                            self.current_row = None
                        },
                        _ => ()
                    };
                    break;
                },
                Some(mut i) => {
                    let n = i.1.next();
                    //FIXME: can this fail?
                    let active_name = &i.0.unwrap();

                    //Iterate down?
                    let mut has_buckets = false;
                    //Save
                    self.iter_stack.push(i);

                    debug! ("ITER: Depth {}", self.iter_stack.len());
                    //FIXME: Move this, to be able to process first line too
                    match n {
                        None => {
                            //Was nothing here, exit
                            debug! ("ITER: Exit!");
                            self.iter_stack.pop();
                            continue;
                        },
                        Some(n) => {
                            //QUESTION: Destructuring/matching to this extent the right strategy?
                            match self.current_row {
                                Some(ref mut row) => {
                                    debug! ("ITER: Row: {:?}", row);

                                    let o = match *n {
                                        Value::Object(ref o) => o,
                                        _ => panic!("Shouldn't get here!")
                                    };
                                    for (key, value) in o {
                                        match *value {
                                            Value::Object(ref c) => {
                                                //Child Aggregation
                                                if c.contains_key("buckets") {
                                                    has_buckets = true;
                                                    if let Value::Array(ref a) = c["buckets"] {
                                                        let i = a.iter();
                                                        self.iter_stack.push((Some(key), i));
                                                    }
                                                    continue;
                                                }
                                                //Simple Value Aggregation Name
                                                if c.contains_key("value") {
                                                    let v = c.get("value");
                                                    //FIXME: Can this fail?
                                                    debug! ("ITER: Insert value! {} {:?}", key, v.unwrap());
                                                    //QUESTION: Cow right for this use-case? See below
                                                    row.insert(Cow::Borrowed(key), v.unwrap());
                                                    continue;
                                                }
                                                //Stats
                                                //FIXME: Can be done in loop?

                                                //Stats fields
                                                insert_value!("count",c,key,row);
                                                insert_value!("min",c,key,row);
                                                insert_value!("max",c,key,row);
                                                insert_value!("avg",c,key,row);
                                                insert_value!("sum",c,key,row);
                                                insert_value!("sum_of_squares",c,key,row);
                                                insert_value!("variance",c,key,row);
                                                insert_value!("std_deviation",c,key,row);

                                                //TODO: std_deviation_bounds
//                                                if c.contains_key("std_deviation_bounds") {
//                                                    let u = c.get("std_deviation_bounds").unwrap().get("upper");
//                                                    let l = c.get("std_deviation_bounds").unwrap().get("lower");
//                                                    let un = format!("{}_std_deviation_bounds_upper", key);
//                                                    let ln = format!("{}_std_deviation_bounds_lower", key);
//                                                    debug! ("ITER: Insert std_dev_bounds! {} {} u: {:?} l: {:?}", un, ln, u.unwrap(), l.unwrap());
//                                                    row.insert(Cow::Owned(un), u.unwrap());
//                                                    row.insert(Cow::Owned(ln), l.unwrap());
//                                                }
                                            },
                                            _ => ()
                                        }
                                        //Bucket Aggregation Name
                                        if key == "key" {
                                            debug! ("ITER: Insert bucket! {} {:?}", active_name, value);
                                            row.insert(Cow::Borrowed(active_name), value);
                                        }
                                        //Bucket Aggregation Count
                                        if key == "doc_count" {
                                            debug! ("ITER: Insert bucket count! {} {:?}", active_name, value);
                                            let field_name = format!("{}_doc_count", active_name);
                                            row.insert(Cow::Owned(field_name), value);
                                        }
                                    }
                                    //Return here?
                                    if !has_buckets {
                                        return Some(row.clone());
                                    }
                                },
                                _ => ()
                            }
                        }
                    }

                    if !has_buckets {
                        debug! ("ITER: Bucketless!");
                        break;
                    } else {
                        debug! ("ITER: Dive!");
                    }
                }
            };
        }

        match self.current_row {
            //FIXME: Refactor to avoid this clone()
            Some(ref x) => Some(x.clone()),
            None => None
        }
    }
}

#[derive(Deserialize, Debug)]
struct Shards {
    total: u32,
    successful: u32,
    failed: u32
}

#[derive(Deserialize, Debug)]
pub struct Hits {
    total: u64,
    max_score: u64,
    hits: Vec<Value>
}

impl Response {
    pub fn hits(&self) -> &Vec<Value> {
        &self.hits.hits()
    }

    pub fn aggs(self) -> std::option::Option<Aggregations> {
        self.aggregations
    }
}

impl Hits {
    pub fn hits(&self) -> &Vec<Value> {
        &self.hits
    }
}

#[derive(Deserialize, Debug)]
struct Hit {
    _index: String
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Minor cleanup<commit_after>#![feature(custom_derive)]
#![feature(proc_macro)]

#[macro_use]
extern crate log;

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

extern crate slog_stdlog;
extern crate slog_envlogger;

use serde_json::Value;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::slice::Iter;

#[derive(Deserialize, Debug)]
pub struct Response {
    took: u64,
    timed_out: bool,
    _shards: Shards,
    hits: Hits,
    aggregations: Option<Aggregations>,
    status: Option<u16>
}

#[derive(Deserialize, Debug)]
pub struct Aggregations(Value);

//QUESTION: Why do lifetimes go where they go, what am I missing?
//          What happens when lifetimes shadow each other?
//          Mental model for this?
//          Below works thanks to `misdreavus` on IRC, but I don't quite know why
impl<'a> IntoIterator for &'a Aggregations {
    type Item = BTreeMap<Cow<'a, String>, &'a Value>;
    type IntoIter = AggregationIterator<'a>;

    fn into_iter(self) -> AggregationIterator<'a> {
        AggregationIterator::new(self)
    }
}

//FIXME: can this be run as a state-machine (ala https://hoverbear.org/2016/10/12/rust-state-machine-pattern/)
//#[derive(Debug)]
//enum AggStates {
//    AtRoot,
//    AtName,
//    InBuckets,
//    AtValues,
//    RowFinished
//}

#[derive(Debug)]
pub struct AggregationIterator<'a> {
    current_row: Option<BTreeMap<Cow<'a, String>, &'a Value>>,
    current_row_finished: bool,
    //QUESTION: Tracking traversal usng a stack of Iterators make sense? Is Vec right for this?
    iter_stack: Vec<(Option<&'a String>, Iter<'a, Value>)>,
    aggregations: &'a Aggregations
}

impl<'a> AggregationIterator<'a> {
    fn new(a: &'a Aggregations) -> AggregationIterator<'a> {
        let v = match a {
            &Aggregations(ref v) => v
        };

        let mut s: Vec<(Option<&String>, Iter<Value>)> = Vec::new();

        match *v {
            Value::Object(ref o) => {
                for (key, child) in o {
                    if let Value::Object(ref c) = *child {
                        if c.contains_key("buckets") {
                            if let Value::Array(ref a) = c["buckets"] {
                                let i = a.iter();
                                s.push((Some(&key), i));
                            }
                        }
                    }
                }
            },
            _ => {
                //FIXME: Bad for lib
                panic!("Not implemented, we only cater for bucket objects");
            }
        };

        AggregationIterator {
            current_row: None,
            current_row_finished: false,
            iter_stack: s,
            aggregations: a
        }
    }
}

macro_rules! insert_value {
    ($fieldname:expr, $json_object:ident, $keyname:ident, $rowdata:ident) => ({
      if $json_object.contains_key($fieldname) {
          let v = $json_object.get($fieldname);
          let field_name = format!("{}_{}", $keyname, $fieldname);
          debug! ("ITER: Insert value! {} {:?}", field_name, v.unwrap());
          $rowdata.insert(Cow::Owned(field_name), v.unwrap());
       }
	})
}

impl<'a> Iterator for AggregationIterator<'a> {
    type Item = BTreeMap<Cow<'a, String>, &'a Value>;

    fn next(&mut self) -> Option<BTreeMap<Cow<'a, String>, &'a Value>> {
        match self.current_row {
            None => {
                //New row
                self.current_row = Some(BTreeMap::new())
            },
            Some(_) => ()
        };

        loop {
            match self.iter_stack.pop() {
                None => {
                    debug! ("ITER: Done!");
                    match self.current_row {
                        Some(_) => {
                            self.current_row = None
                        },
                        _ => ()
                    };
                    break;
                },
                Some(mut i) => {
                    let n = i.1.next();
                    //FIXME: can this fail?
                    let active_name = &i.0.unwrap();

                    //Iterate down?
                    let mut has_buckets = false;
                    //Save
                    self.iter_stack.push(i);

                    debug! ("ITER: Depth {}", self.iter_stack.len());
                    //FIXME: Move this, to be able to process first line too
                    match n {
                        None => {
                            //Was nothing here, exit
                            debug! ("ITER: Exit!");
                            self.iter_stack.pop();
                            continue;
                        },
                        Some(n) => {
                            //QUESTION: Destructuring/matching to this extent the right strategy?
                            match self.current_row {
                                Some(ref mut row) => {
                                    debug! ("ITER: Row: {:?}", row);

                                    let o = match *n {
                                        Value::Object(ref o) => o,
                                        _ => panic!("Shouldn't get here!")
                                    };
                                    for (key, value) in o {
                                        match *value {
                                            Value::Object(ref c) => {
                                                //Child Aggregation
                                                if c.contains_key("buckets") {
                                                    has_buckets = true;
                                                    if let Value::Array(ref a) = c["buckets"] {
                                                        let i = a.iter();
                                                        self.iter_stack.push((Some(key), i));
                                                    }
                                                    continue;
                                                }
                                                //Simple Value Aggregation Name
                                                if c.contains_key("value") {
                                                    let v = c.get("value");
                                                    //FIXME: Can this fail?
                                                    debug! ("ITER: Insert value! {} {:?}", key, v.unwrap());
                                                    //QUESTION: Cow right for this use-case? See below
                                                    row.insert(Cow::Borrowed(key), v.unwrap());
                                                    continue;
                                                }
                                                //Stats
                                                //FIXME: Can be done in loop?

                                                //Stats fields
                                                insert_value!("count",c,key,row);
                                                insert_value!("min",c,key,row);
                                                insert_value!("max",c,key,row);
                                                insert_value!("avg",c,key,row);
                                                insert_value!("sum",c,key,row);
                                                insert_value!("sum_of_squares",c,key,row);
                                                insert_value!("variance",c,key,row);
                                                insert_value!("std_deviation",c,key,row);

                                                //TODO: std_deviation_bounds
//                                                if c.contains_key("std_deviation_bounds") {
//                                                    let u = c.get("std_deviation_bounds").unwrap().get("upper");
//                                                    let l = c.get("std_deviation_bounds").unwrap().get("lower");
//                                                    let un = format!("{}_std_deviation_bounds_upper", key);
//                                                    let ln = format!("{}_std_deviation_bounds_lower", key);
//                                                    debug! ("ITER: Insert std_dev_bounds! {} {} u: {:?} l: {:?}", un, ln, u.unwrap(), l.unwrap());
//                                                    row.insert(Cow::Owned(un), u.unwrap());
//                                                    row.insert(Cow::Owned(ln), l.unwrap());
//                                                }
                                            },
                                            _ => ()
                                        }
                                        //Bucket Aggregation Name
                                        if key == "key" {
                                            debug! ("ITER: Insert bucket! {} {:?}", active_name, value);
                                            row.insert(Cow::Borrowed(active_name), value);
                                        }
                                        //Bucket Aggregation Count
                                        if key == "doc_count" {
                                            debug! ("ITER: Insert bucket count! {} {:?}", active_name, value);
                                            let field_name = format!("{}_doc_count", active_name);
                                            row.insert(Cow::Owned(field_name), value);
                                        }
                                    }
                                    //Return here?
                                    if !has_buckets {
                                        return Some(row.clone());
                                    }
                                },
                                _ => ()
                            }
                        }
                    }

                    if !has_buckets {
                        debug! ("ITER: Bucketless!");
                        break;
                    } else {
                        debug! ("ITER: Dive!");
                    }
                }
            };
        }

        match self.current_row {
            //FIXME: Refactor to avoid this clone()
            Some(ref x) => Some(x.clone()),
            None => None
        }
    }
}

#[derive(Deserialize, Debug)]
struct Shards {
    total: u32,
    successful: u32,
    failed: u32
}

#[derive(Deserialize, Debug)]
pub struct Hits {
    total: u64,
    max_score: u64,
    hits: Vec<Value>
}

impl Response {
    pub fn hits(&self) -> &Vec<Value> {
        &self.hits.hits()
    }

    pub fn aggs(self) -> std::option::Option<Aggregations> {
        self.aggregations
    }
}

impl Hits {
    pub fn hits(&self) -> &Vec<Value> {
        &self.hits
    }
}

#[derive(Deserialize, Debug)]
struct Hit {
    _index: String
}

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