<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::env;
use std::fs::File;
use std::path::PathBuf;
use std::io::prelude::*;
use chrono::{UTC, DateTime, TimeZone};
use std::time::{UNIX_EPOCH, SystemTime};
use response::{ToOutput, Response};
use request::Request;

/// Convenience method for creating a response from the basic components
/// required (a request body, content type, and response status).
///
/// # Examples
///
/// ```rust
/// use canteen::{Request, Response};
/// use canteen::utils;
///
/// fn handler(_: &Request) -> Response {
///     utils::make_response("Hello, world!", "text/plain", 200)
/// }
/// ```
pub fn make_response<T: ToOutput>(body: T, c_type: &str, status: u16) -> Response {
    let mut res = Response::new();

    res.set_status(status);
    res.set_content_type(c_type);
    res.append(body);

    res
}

/// Converts std::time::SystemTime to chrono::DateTime<UTC>
///
/// Code from: https://users.rust-lang.org/t/convert-std-time-systemtime-to-chrono-datetime-datetime/7684/4
fn _conv_systemtime(t: SystemTime) -> DateTime<UTC> {
    let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
        Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
        Err(e) => {
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());

            if nsec == 0 {
                (-sec, 0)
            } else {
                (-sec - 1, 1_000_000_000 - nsec)
            }
        },
    };

    UTC.timestamp(sec, nsec)
}

/// Replace the URI escape codes with their ASCII equivalents.
pub fn replace_escape(path: &str) -> String {
    let mut fixed = String::from(path);
    let replaces: [(&str, &str); 175] = [
        ("%20", " "),
        ("%21", "!"),
        ("%22", "\""),
        ("%23", "#"),
        ("%24", "$"),
        ("%25", "%"),
        ("%26", "&"),
        ("%27", "'"),
        ("%28", "("),
        ("%29", ")"),
        ("%2A", "*"),
        ("%2B", "+"),
        ("%2C", ","),
        ("%2D", "-"),
        ("%2E", "."),
        ("%2F", "/"),
        ("%30", "0"),
        ("%31", "1"),
        ("%32", "2"),
        ("%33", "3"),
        ("%34", "4"),
        ("%35", "5"),
        ("%36", "6"),
        ("%37", "7"),
        ("%38", "8"),
        ("%39", "9"),
        ("%3A", ":"),
        ("%3B", ";"),
        ("%3C", "<"),
        ("%3D", "="),
        ("%3E", ">"),
        ("%3F", "?"),
        ("%40", "@"),
        ("%41", "A"),
        ("%42", "B"),
        ("%43", "C"),
        ("%44", "D"),
        ("%45", "E"),
        ("%46", "F"),
        ("%47", "G"),
        ("%48", "H"),
        ("%49", "I"),
        ("%4A", "J"),
        ("%4B", "K"),
        ("%4C", "L"),
        ("%4D", "M"),
        ("%4E", "N"),
        ("%4F", "O"),
        ("%50", "P"),
        ("%51", "Q"),
        ("%52", "R"),
        ("%53", "S"),
        ("%54", "T"),
        ("%55", "U"),
        ("%56", "V"),
        ("%57", "W"),
        ("%58", "X"),
        ("%59", "Y"),
        ("%5A", "Z"),
        ("%5B", "["),
        ("%5C", "\\"),
        ("%5D", "]"),
        ("%5E", "^"),
        ("%5F", "_"),
        ("%60", "`"),
        ("%61", "a"),
        ("%62", "b"),
        ("%63", "c"),
        ("%64", "d"),
        ("%65", "e"),
        ("%66", "f"),
        ("%67", "g"),
        ("%68", "h"),
        ("%69", "i"),
        ("%6A", "j"),
        ("%6B", "k"),
        ("%6C", "l"),
        ("%6D", "m"),
        ("%6E", "n"),
        ("%6F", "o"),
        ("%70", "p"),
        ("%71", "q"),
        ("%72", "r"),
        ("%73", "s"),
        ("%74", "t"),
        ("%75", "u"),
        ("%76", "v"),
        ("%77", "w"),
        ("%78", "x"),
        ("%79", "y"),
        ("%7A", "z"),
        ("%7B", "{"),
        ("%7C", "|"),
        ("%7D", "}"),
        ("%7E", "~"),
        ("%A2", "¢"),
        ("%A3", "£"),
        ("%A5", "¥"),
        ("%A6", "|"),
        ("%A7", "§"),
        ("%AB", "«"),
        ("%AC", "¬"),
        ("%AD", "¯"),
        ("%B0", "º"),
        ("%B1", "±"),
        ("%B2", "ª"),
        ("%B4", ","),
        ("%B5", "µ"),
        ("%BB", "»"),
        ("%BC", "¼"),
        ("%BD", "½"),
        ("%BF", "¿"),
        ("%C0", "À"),
        ("%C1", "Á"),
        ("%C2", "Â"),
        ("%C3", "Ã"),
        ("%C4", "Ä"),
        ("%C5", "Å"),
        ("%C6", "Æ"),
        ("%C7", "Ç"),
        ("%C8", "È"),
        ("%C9", "É"),
        ("%CA", "Ê"),
        ("%CB", "Ë"),
        ("%CC", "Ì"),
        ("%CD", "Í"),
        ("%CE", "Î"),
        ("%CF", "Ï"),
        ("%D0", "Ð"),
        ("%D1", "Ñ"),
        ("%D2", "Ò"),
        ("%D3", "Ó"),
        ("%D4", "Ô"),
        ("%D5", "Õ"),
        ("%D6", "Ö"),
        ("%D8", "Ø"),
        ("%D9", "Ù"),
        ("%DA", "Ú"),
        ("%DB", "Û"),
        ("%DC", "Ü"),
        ("%DD", "Ý"),
        ("%DE", "Þ"),
        ("%DF", "ß"),
        ("%E0", "à"),
        ("%E1", "á"),
        ("%E2", "â"),
        ("%E3", "ã"),
        ("%E4", "ä"),
        ("%E5", "å"),
        ("%E6", "æ"),
        ("%E7", "ç"),
        ("%E8", "è"),
        ("%E9", "é"),
        ("%EA", "ê"),
        ("%EB", "ë"),
        ("%EC", "ì"),
        ("%ED", "í"),
        ("%EE", "î"),
        ("%EF", "ï"),
        ("%F0", "ð"),
        ("%F1", "ñ"),
        ("%F2", "ò"),
        ("%F3", "ó"),
        ("%F4", "ô"),
        ("%F5", "õ"),
        ("%F6", "ö"),
        ("%F7", "÷"),
        ("%F8", "ø"),
        ("%F9", "ù"),
        ("%FA", "ú"),
        ("%FB", "û"),
        ("%FC", "ü"),
        ("%FD", "ý"),
        ("%FE", "þ"),
        ("%FF", "ÿ"),
    ];

    if !fixed.contains("%") {
        return fixed;
    }

    for &(from, to) in replaces.iter() {
        fixed = fixed.replace(from, to);
    }

    fixed
}

fn err_body(message: &str, path: &str) -> String {
    format!("\
             \

Your request failed

{}: {}
", message, path)
}

/// Default handler function for HTTP 403 errors.
pub fn err_403(req: &Request) -> Response {
    make_response(err_body("forbidden", &req.path), "text/html", 403)
}

/// Default handler function for HTTP 403 errors for XHR.
pub fn err_403_json(message: &str) -> Response {
    make_response(format!("{{ message: 'forbidden: {}' }}", message), "application/json", 403)
}

/// Default handler function for HTTP 404 errors.
pub fn err_404(req: &Request) -> Response {
    make_response(err_body("not found", &req.path), "text/html", 404)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_404_json(message: &str) -> Response {
    make_response(format!("{{ message: 'not found: {}' }}", message), "application/json", 404)
}

/// Default handler function for HTTP 500 errors.
pub fn err_500(req: &Request) -> Response {
    make_response(err_body("internal server error", &req.path), "text/html", 500)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_500_json(message: &str) -> Response {
    make_response(format!("{{ message: 'internal server error: {}' }}", message), "application/json", 500)
}

/// Handler that sends static files relative to the current working directory.
pub fn static_file(req: &Request) -> Response {
    let mut res = Response::new();

    let cwd = env::current_dir().unwrap();
    let clean = replace_escape(&req.path);
    let mut fpath = PathBuf::from(&cwd);
    let mut fbuf: Vec<u8> = Vec::new();

    for chunk in clean.split('/') {
        if chunk == "" || chunk == "." || chunk == ".." {
            /* bzzzzt */
            continue;
        }

        fpath.push(&chunk);
    }

    let file = File::open(&fpath);

    match file {
        Ok(mut f)   => {
            let last = match f.metadata() {
                Err(_)  => UTC::now(),
                Ok(md)  => {
                    match md.modified() {
                        Err(_)  => UTC::now(), // should never happen...
                        Ok(st)  => _conv_systemtime(st),
                    }
                }
            };

            if let Some(hdr) = req.get_header("If-Modified-Since") {
                if let Ok(dt_utc) = UTC.datetime_from_str(&hdr, "%a, %d %b %Y, %H:%M:%S UTC") {
                    if dt_utc >= last {
                        // it hasn't been modified, return a 304
                        res.set_status(304);
                        return res;
                    }
                }
            }

            match f.read_to_end(&mut fbuf) {
                Ok(_)   => {
                    res.add_header("Last-Modified", &last.format("%a, %d %b %Y, %H:%M:%S %Z").to_string());
                    res.set_status(200);
                    res.set_content_type("text/plain");
                    res.append(fbuf);
                },
                Err(_)  => {
                    return err_500(&req);
                },
            }
        },
        Err(_)      => {
            return err_404(&req);
        }
    }

    res
}

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

    #[test]
    fn test_replace_escape() {
        let path = "%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F%70%71%72%73%74%75%76%77%78%79%7A";
        assert_eq!("abcdefghijklmnopqrstuvwxyz", replace_escape(&path));
    }
}
<commit_msg>make the HTTP escape codes go five on a line to save 140 lines (175 -> 35)<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::env;
use std::fs::File;
use std::path::PathBuf;
use std::io::prelude::*;
use chrono::{UTC, DateTime, TimeZone};
use std::time::{UNIX_EPOCH, SystemTime};
use response::{ToOutput, Response};
use request::Request;

/// Convenience method for creating a response from the basic components
/// required (a request body, content type, and response status).
///
/// # Examples
///
/// ```rust
/// use canteen::{Request, Response};
/// use canteen::utils;
///
/// fn handler(_: &Request) -> Response {
///     utils::make_response("Hello, world!", "text/plain", 200)
/// }
/// ```
pub fn make_response<T: ToOutput>(body: T, c_type: &str, status: u16) -> Response {
    let mut res = Response::new();

    res.set_status(status);
    res.set_content_type(c_type);
    res.append(body);

    res
}

/// Converts std::time::SystemTime to chrono::DateTime<UTC>
///
/// Code from: https://users.rust-lang.org/t/convert-std-time-systemtime-to-chrono-datetime-datetime/7684/4
fn _conv_systemtime(t: SystemTime) -> DateTime<UTC> {
    let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
        Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
        Err(e) => {
            let dur = e.duration();
            let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());

            if nsec == 0 {
                (-sec, 0)
            } else {
                (-sec - 1, 1_000_000_000 - nsec)
            }
        },
    };

    UTC.timestamp(sec, nsec)
}

/// Replace the URI escape codes with their ASCII equivalents.
pub fn replace_escape(path: &str) -> String {
    let mut fixed = String::from(path);
    let replaces: [(&str, &str); 175] = [
        ("%20", " "),  ("%21", "!"),  ("%22", "\""), ("%23", "#"),  ("%24", "$"),
        ("%25", "%"),  ("%26", "&"),  ("%27", "'"),  ("%28", "("),  ("%29", ")"),
        ("%2A", "*"),  ("%2B", "+"),  ("%2C", ","),  ("%2D", "-"),  ("%2E", "."),
        ("%2F", "/"),  ("%30", "0"),  ("%31", "1"),  ("%32", "2"),  ("%33", "3"),
        ("%34", "4"),  ("%35", "5"),  ("%36", "6"),  ("%37", "7"),  ("%38", "8"),
        ("%39", "9"),  ("%3A", ":"),  ("%3B", ";"),  ("%3C", "<"),  ("%3D", "="),
        ("%3E", ">"),  ("%3F", "?"),  ("%40", "@"),  ("%41", "A"),  ("%42", "B"),
        ("%43", "C"),  ("%44", "D"),  ("%45", "E"),  ("%46", "F"),  ("%47", "G"),
        ("%48", "H"),  ("%49", "I"),  ("%4A", "J"),  ("%4B", "K"),  ("%4C", "L"),
        ("%4D", "M"),  ("%4E", "N"),  ("%4F", "O"),  ("%50", "P"),  ("%51", "Q"),
        ("%52", "R"),  ("%53", "S"),  ("%54", "T"),  ("%55", "U"),  ("%56", "V"),
        ("%57", "W"),  ("%58", "X"),  ("%59", "Y"),  ("%5A", "Z"),  ("%5B", "["),
        ("%5C", "\\"), ("%5D", "]"),  ("%5E", "^"),  ("%5F", "_"),  ("%60", "`"),
        ("%61", "a"),  ("%62", "b"),  ("%63", "c"),  ("%64", "d"),  ("%65", "e"),
        ("%66", "f"),  ("%67", "g"),  ("%68", "h"),  ("%69", "i"),  ("%6A", "j"),
        ("%6B", "k"),  ("%6C", "l"),  ("%6D", "m"),  ("%6E", "n"),  ("%6F", "o"),
        ("%70", "p"),  ("%71", "q"),  ("%72", "r"),  ("%73", "s"),  ("%74", "t"),
        ("%75", "u"),  ("%76", "v"),  ("%77", "w"),  ("%78", "x"),  ("%79", "y"),
        ("%7A", "z"),  ("%7B", "{"),  ("%7C", "|"),  ("%7D", "}"),  ("%7E", "~"),
        ("%A2", "¢"),  ("%A3", "£"),  ("%A5", "¥"),  ("%A6", "|"),  ("%A7", "§"),
        ("%AB", "«"),  ("%AC", "¬"),  ("%AD", "¯"),  ("%B0", "º"),  ("%B1", "±"),
        ("%B2", "ª"),  ("%B4", ","),  ("%B5", "µ"),  ("%BB", "»"),  ("%BC", "¼"),
        ("%BD", "½"),  ("%BF", "¿"),  ("%C0", "À"),  ("%C1", "Á"),  ("%C2", "Â"),
        ("%C3", "Ã"),  ("%C4", "Ä"),  ("%C5", "Å"),  ("%C6", "Æ"),  ("%C7", "Ç"),
        ("%C8", "È"),  ("%C9", "É"),  ("%CA", "Ê"),  ("%CB", "Ë"),  ("%CC", "Ì"),
        ("%CD", "Í"),  ("%CE", "Î"),  ("%CF", "Ï"),  ("%D0", "Ð"),  ("%D1", "Ñ"),
        ("%D2", "Ò"),  ("%D3", "Ó"),  ("%D4", "Ô"),  ("%D5", "Õ"),  ("%D6", "Ö"),
        ("%D8", "Ø"),  ("%D9", "Ù"),  ("%DA", "Ú"),  ("%DB", "Û"),  ("%DC", "Ü"),
        ("%DD", "Ý"),  ("%DE", "Þ"),  ("%DF", "ß"),  ("%E0", "à"),  ("%E1", "á"),
        ("%E2", "â"),  ("%E3", "ã"),  ("%E4", "ä"),  ("%E5", "å"),  ("%E6", "æ"),
        ("%E7", "ç"),  ("%E8", "è"),  ("%E9", "é"),  ("%EA", "ê"),  ("%EB", "ë"),
        ("%EC", "ì"),  ("%ED", "í"),  ("%EE", "î"),  ("%EF", "ï"),  ("%F0", "ð"),
        ("%F1", "ñ"),  ("%F2", "ò"),  ("%F3", "ó"),  ("%F4", "ô"),  ("%F5", "õ"),
        ("%F6", "ö"),  ("%F7", "÷"),  ("%F8", "ø"),  ("%F9", "ù"),  ("%FA", "ú"),
        ("%FB", "û"),  ("%FC", "ü"),  ("%FD", "ý"),  ("%FE", "þ"),  ("%FF", "ÿ"),
    ];

    if !fixed.contains("%") {
        return fixed;
    }

    for &(from, to) in replaces.iter() {
        fixed = fixed.replace(from, to);
    }

    fixed
}

fn err_body(message: &str, path: &str) -> String {
    format!("\
             \

Your request failed

{}: {}
", message, path)
}

/// Default handler function for HTTP 403 errors.
pub fn err_403(req: &Request) -> Response {
    make_response(err_body("forbidden", &req.path), "text/html", 403)
}

/// Default handler function for HTTP 403 errors for XHR.
pub fn err_403_json(message: &str) -> Response {
    make_response(format!("{{ message: 'forbidden: {}' }}", message), "application/json", 403)
}

/// Default handler function for HTTP 404 errors.
pub fn err_404(req: &Request) -> Response {
    make_response(err_body("not found", &req.path), "text/html", 404)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_404_json(message: &str) -> Response {
    make_response(format!("{{ message: 'not found: {}' }}", message), "application/json", 404)
}

/// Default handler function for HTTP 500 errors.
pub fn err_500(req: &Request) -> Response {
    make_response(err_body("internal server error", &req.path), "text/html", 500)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_500_json(message: &str) -> Response {
    make_response(format!("{{ message: 'internal server error: {}' }}", message), "application/json", 500)
}

/// Handler that sends static files relative to the current working directory.
pub fn static_file(req: &Request) -> Response {
    let mut res = Response::new();

    let cwd = env::current_dir().unwrap();
    let clean = replace_escape(&req.path);
    let mut fpath = PathBuf::from(&cwd);
    let mut fbuf: Vec<u8> = Vec::new();

    for chunk in clean.split('/') {
        if chunk == "" || chunk == "." || chunk == ".." {
            /* bzzzzt */
            continue;
        }

        fpath.push(&chunk);
    }

    let file = File::open(&fpath);

    match file {
        Ok(mut f)   => {
            let last = match f.metadata() {
                Err(_)  => UTC::now(),
                Ok(md)  => {
                    match md.modified() {
                        Err(_)  => UTC::now(), // should never happen...
                        Ok(st)  => _conv_systemtime(st),
                    }
                }
            };

            if let Some(hdr) = req.get_header("If-Modified-Since") {
                if let Ok(dt_utc) = UTC.datetime_from_str(&hdr, "%a, %d %b %Y, %H:%M:%S UTC") {
                    if dt_utc >= last {
                        // it hasn't been modified, return a 304
                        res.set_status(304);
                        return res;
                    }
                }
            }

            match f.read_to_end(&mut fbuf) {
                Ok(_)   => {
                    res.add_header("Last-Modified", &last.format("%a, %d %b %Y, %H:%M:%S %Z").to_string());
                    res.set_status(200);
                    res.set_content_type("text/plain");
                    res.append(fbuf);
                },
                Err(_)  => {
                    return err_500(&req);
                },
            }
        },
        Err(_)      => {
            return err_404(&req);
        }
    }

    res
}

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

    #[test]
    fn test_replace_escape() {
        let path = "%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F%70%71%72%73%74%75%76%77%78%79%7A";
        assert_eq!("abcdefghijklmnopqrstuvwxyz", replace_escape(&path));
    }
}
<|endoftext|>


<commit_before>use serde_json::Value;
use regex::Regex;

pub fn unescape_tex_string(string: &str) -> String {
    lazy_static! {
        static ref ESCAPED_TEX_SPECIAL_CHARACTER: Regex = Regex::new(r"\\([&%$#_{}])").unwrap();
    }
    ESCAPED_TEX_SPECIAL_CHARACTER
        .replace_all(string, "$1")
        .to_string()
}

pub fn escape_tex_string(string: &str) -> String {
    lazy_static! {
        static ref TEX_SPECIAL_CHARACTER: Regex = Regex::new(r"([&%$#_{}])").unwrap();
    }
    TEX_SPECIAL_CHARACTER
        .replace_all(string, "\\$1")
        .to_string()
}

pub fn unescape_tex(json: Value) -> Value {
    transform_strings(json, &unescape_tex_string)
}

pub fn escape_tex(json: Value) -> Value {
    transform_strings(json, &escape_tex_string)
}

fn transform_strings(json: Value, callback: &Fn(&str) -> String) -> Value {
    match json {
        Value::String(s) => Value::String(callback(&s)),
        Value::Object(obj) => Value::Object(
            obj.into_iter()
                .map(|(k, v)| (k, transform_strings(v, callback)))
                .collect(),
        ),
        Value::Array(values) => Value::Array(
            values
                .into_iter()
                .map(|v| transform_strings(v, callback))
                .collect(),
        ),
        other => other,
    }
}

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

    #[test]
    fn escape_tex_does_not_alter_basic_json_strings() {
        let original = json!("abc");
        let expected = json!("abc");
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_does_not_alter_basic_json_numbers() {
        let original = json!(3);
        let expected = json!(3);
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_does_not_alter_basic_json_arrays() {
        let original = json!(["a", 33, null]);
        let expected = json!(["a", 33, null]);
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_escapes_latex_special_characters() {
        let original = json!(
            r##"## Ye$sterday,
            I ate 30% discounted M&M's 90% of the time, & it was {{ _sweet_ }} as hell
            ##"##
        );
        let expected = json!(
            r##"\#\# Ye\$sterday,
            I ate 30\% discounted M\&M's 90\% of the time, \& it was \{\{ \_sweet\_ \}\} as hell
            \#\#"##
        );
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_escapes_strings_in_arrays() {
        let original = json!(["M&Ms", "Ben & Jerry's"]);
        let expected = json!(["M\\&Ms", "Ben \\& Jerry's"]);
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_escapes_recursively_into_the_json_structure() {
        let original = json!({
            "deadEnd": null,
            "names": ["Jack & John", "Santa & Claus"],
            "discounts": {
                "alot": "70%",
                "commented": "33% # or thereabouts",
                "multiplicator": 3.32
            },
        });
        let expected = json!({
            "deadEnd": null,
            "names": ["Jack \\& John", "Santa \\& Claus"],
            "discounts": {
                "alot": "70\\%",
                "commented": "33\\% \\# or thereabouts",
                "multiplicator": 3.32
            },
        });
        assert_eq!(escape_tex(original), expected);
    }
}
<commit_msg>✅ Write generative test checking escape and unescape tex roundtrip<commit_after>use serde_json::Value;
use regex::Regex;

pub fn unescape_tex_string(string: &str) -> String {
    lazy_static! {
        static ref ESCAPED_TEX_SPECIAL_CHARACTER: Regex = Regex::new(r"\\([&%$#_{}])").unwrap();
    }
    ESCAPED_TEX_SPECIAL_CHARACTER
        .replace_all(string, "$1")
        .to_string()
}

pub fn escape_tex_string(string: &str) -> String {
    lazy_static! {
        static ref TEX_SPECIAL_CHARACTER: Regex = Regex::new(r"([&%$#_{}])").unwrap();
    }
    TEX_SPECIAL_CHARACTER
        .replace_all(string, "\\$1")
        .to_string()
}

pub fn unescape_tex(json: Value) -> Value {
    transform_strings(json, &unescape_tex_string)
}

pub fn escape_tex(json: Value) -> Value {
    transform_strings(json, &escape_tex_string)
}

fn transform_strings(json: Value, callback: &Fn(&str) -> String) -> Value {
    match json {
        Value::String(s) => Value::String(callback(&s)),
        Value::Object(obj) => Value::Object(
            obj.into_iter()
                .map(|(k, v)| (k, transform_strings(v, callback)))
                .collect(),
        ),
        Value::Array(values) => Value::Array(
            values
                .into_iter()
                .map(|v| transform_strings(v, callback))
                .collect(),
        ),
        other => other,
    }
}

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

    #[test]
    fn escape_tex_does_not_alter_basic_json_strings() {
        let original = json!("abc");
        let expected = json!("abc");
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_does_not_alter_basic_json_numbers() {
        let original = json!(3);
        let expected = json!(3);
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_does_not_alter_basic_json_arrays() {
        let original = json!(["a", 33, null]);
        let expected = json!(["a", 33, null]);
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_escapes_latex_special_characters() {
        let original = json!(
            r##"## Ye$sterday,
            I ate 30% discounted M&M's 90% of the time, & it was {{ _sweet_ }} as hell
            ##"##
        );
        let expected = json!(
            r##"\#\# Ye\$sterday,
            I ate 30\% discounted M\&M's 90\% of the time, \& it was \{\{ \_sweet\_ \}\} as hell
            \#\#"##
        );
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_escapes_strings_in_arrays() {
        let original = json!(["M&Ms", "Ben & Jerry's"]);
        let expected = json!(["M\\&Ms", "Ben \\& Jerry's"]);
        assert_eq!(escape_tex(original), expected);
    }

    #[test]
    fn escape_tex_escapes_recursively_into_the_json_structure() {
        let original = json!({
            "deadEnd": null,
            "names": ["Jack & John", "Santa & Claus"],
            "discounts": {
                "alot": "70%",
                "commented": "33% # or thereabouts",
                "multiplicator": 3.32
            },
        });
        let expected = json!({
            "deadEnd": null,
            "names": ["Jack \\& John", "Santa \\& Claus"],
            "discounts": {
                "alot": "70\\%",
                "commented": "33\\% \\# or thereabouts",
                "multiplicator": 3.32
            },
        });
        assert_eq!(escape_tex(original), expected);
    }

    quickcheck! {
        fn escape_tex_and_unescape_tex_roundtrip(input: String) -> bool {
            input == unescape_tex_string(&escape_tex_string(&input))
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::BufReader;
use std::fs::File;
use std::num::FromPrimitive;
use std::rc::Rc;

use display::Display;
use sdl2;
use player;
use player::Player;

#[derive(Clone)]
#[derive(FromPrimitive)]
#[derive(Hash)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum SquareType {
    EMPTY = 0isize,
    WALL = 1isize,
    BOX = 2isize,
    TARGET = 3isize,
    TARGETVALID = 4isize
}

pub struct Level {
    columns: isize,
    rows: isize,
    boxsize: isize,
    renderer: Display,
    textures: HashMap<SquareType, Rc<sdl2::render::Texture>>,
    player_textures: HashMap<player::Orientation, Rc<sdl2::render::Texture>>,
    grid: Vec<Vec<Square>>,
    start_position: (usize, usize)
}

impl Level {
    pub fn new() -> Level {
        let width = 20 * 34;
        let height = 20 * 34;
        let renderer = Display::new(width, height);

        Level {
            columns: 20,
            rows: 20,
            boxsize: 34,
            renderer: renderer,
            textures: HashMap::new(),
            player_textures: HashMap::new(),
            grid: Vec::new(),
            start_position: (0, 0)
        }
    }

    pub fn init(&mut self) {
        self.textures = self.renderer.get_grid_textures();
        self.player_textures = self.renderer.get_player_textures();
        let grid_content: Vec<Vec<SquareType>> = self.get_level_content();
        self.grid = Level::create_grid(grid_content);
    }

    pub fn get_start_position(&self) -> (usize, usize) {
        self.start_position
    }

    fn get_level_content(&mut self) -> Vec<Vec<SquareType>> {
        let level_path = Path::new("./resources/level.txt");
        let mut file = BufferedReader::new(File::open(&level_path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();

        let mut grid: Vec<Vec<SquareType>> = Vec::new();
        for line in lines.iter() {
            let mut row: Vec<SquareType> = Vec::new();
            let mut myline = line.clone();
            myline.pop();
            let slice: &str = myline.as_slice();
            for c in slice.chars() {
                if c == 'P' {
                    self.start_position = (row.len(), grid.len());
                }
                let code: isize = match c.to_digit(4) {
                    Some(d) => d as isize,
                    None => 0isize
                };
                let square_type = match FromPrimitive::from_int(code) {
                    Some(t) => t,
                    None => SquareType::EMPTY
                };
                row.push(square_type);
            }
            grid.push(row);
        }
        return grid;
    }

    fn create_grid(content: Vec<Vec<SquareType>>) -> Vec<Vec<Square>> {
        let mut grid: Vec<Vec<Square>> = Vec::new();
        let mut i = 0isize;

        for content_row in content.iter() {
            let mut row: Vec<Square> = Vec::new();
            let mut j = 0isize;
            for square_type in content_row.iter() {
                let s = create_square(j, i, square_type.clone());
                row.push(s);
                j += 1;
            }
            i += 1;
            grid.push(row);
        }
        return grid;
    }

    pub fn update_display(&self, player: &Player) {
        self.renderer.clear_screen();
        self.renderer.render_grid(&self.grid, self.boxsize as i32, &self.textures);
        let player_texture = match self.player_textures.get(&player.orientation) {
            Some(t) => t,
            None => panic!(format!("error on texture retrieval for player orientation {}", player.orientation.clone() as isize))
        };
        self.renderer.render_player(&**player_texture, player.get_position(), self.boxsize as i32);
        self.renderer.renderer.present();
    }

    pub fn is_move_allowed(&self, player: &Player, movement: (i8, i8)) -> bool {
        let (x, y) = player.get_position();
        let (dx, dy) = movement;
        let new_x = x as isize + dx as isize;
        let new_y = y as isize + dy as isize;

        match self.grid[new_y as usize][new_x as usize].square_type {
            SquareType::EMPTY => true,
            SquareType::WALL => false,
            SquareType::BOX | SquareType::TARGETVALID => {
                let pos = ((new_x + dx as isize) as usize, (new_y + dy as isize) as usize);
                self.is_free(pos)
            },
            SquareType::TARGET => true
        }
    }
    pub fn is_free(&self, position: (usize, usize)) -> bool {
        let (x, y) = position;
        match self.grid[y][x].square_type {
            SquareType::EMPTY | SquareType::TARGET => true,
            _ => false
        }
    }
    pub fn is_box_present(&self, position: (usize, usize)) -> bool {
        let (x, y) = position;
        match self.grid[y][x].square_type {
            SquareType::BOX | SquareType::TARGETVALID => true,
            _ => false
        }
    }

    pub fn move_box(&mut self, position: (usize, usize), delta: (i8, i8)) {
        let (x, y) = position;
        let (dx, dy) = delta;
        let new_x = (x as isize + dx as isize) as usize;
        let new_y = (y as isize + dy as isize) as usize;
        match self.grid[y][x].square_type {
            SquareType::BOX => self.grid[y][x].square_type = SquareType::EMPTY,
            SquareType::TARGETVALID => self.grid[y][x].square_type = SquareType::TARGET,
            _ => ()
        };

        match self.grid[new_y][new_x].square_type {
            SquareType::EMPTY => self.grid[new_y][new_x].square_type = SquareType::BOX,
            SquareType::TARGET => self.grid[new_y][new_x].square_type = SquareType::TARGETVALID,
            _ => ()
        };
    }
}

pub struct Square {
    pub x: isize,
    pub y: isize,
    pub square_type: SquareType,
}

pub fn create_square(x: isize, y: isize, square_type: SquareType) -> Square {
    Square{x:x, y:y, square_type: square_type}
}
<commit_msg>remove usage of old FromPrimitive trait<commit_after>use std::collections::HashMap;
use std::io::BufReader;
use std::fs::File;
use std::rc::Rc;

use display::Display;
use sdl2;
use player;
use player::Player;

#[derive(Clone)]
#[derive(Hash)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum SquareType {
    EMPTY = 0isize,
    WALL = 1isize,
    BOX = 2isize,
    TARGET = 3isize,
    TARGETVALID = 4isize
}

pub struct Level {
    columns: isize,
    rows: isize,
    boxsize: isize,
    renderer: Display,
    textures: HashMap<SquareType, Rc<sdl2::render::Texture>>,
    player_textures: HashMap<player::Orientation, Rc<sdl2::render::Texture>>,
    grid: Vec<Vec<Square>>,
    start_position: (usize, usize)
}

impl Level {
    pub fn new() -> Level {
        let width = 20 * 34;
        let height = 20 * 34;
        let renderer = Display::new(width, height);

        Level {
            columns: 20,
            rows: 20,
            boxsize: 34,
            renderer: renderer,
            textures: HashMap::new(),
            player_textures: HashMap::new(),
            grid: Vec::new(),
            start_position: (0, 0)
        }
    }

    pub fn init(&mut self) {
        self.textures = self.renderer.get_grid_textures();
        self.player_textures = self.renderer.get_player_textures();
        let grid_content: Vec<Vec<SquareType>> = self.get_level_content();
        self.grid = Level::create_grid(grid_content);
    }

    pub fn get_start_position(&self) -> (usize, usize) {
        self.start_position
    }

    fn get_level_content(&mut self) -> Vec<Vec<SquareType>> {
        let level_path = Path::new("./resources/level.txt");
        let mut file = BufferedReader::new(File::open(&level_path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();

        let mut grid: Vec<Vec<SquareType>> = Vec::new();
        for line in lines.iter() {
            let mut row: Vec<SquareType> = Vec::new();
            let mut myline = line.clone();
            myline.pop();
            let slice: &str = myline.as_slice();
            for c in slice.chars() {
                if c == 'P' {
                    self.start_position = (row.len(), grid.len());
                }
                let code: isize = match c.to_digit(4) {
                    Some(d) => d as isize,
                    None => 0isize
                };
                let square_type = match code {
                    0 => SquareType::EMPTY,
                    1 => SquareType::WALL,
                    2 => SquareType::BOX,
                    3 => SquareType::TARGET,
                    4 => SquareType::TARGETVALID,
                    _ => SquareType::EMPTY
                };

                row.push(square_type);
            }
            grid.push(row);
        }
        return grid;
    }

    fn create_grid(content: Vec<Vec<SquareType>>) -> Vec<Vec<Square>> {
        let mut grid: Vec<Vec<Square>> = Vec::new();
        let mut i = 0isize;

        for content_row in content.iter() {
            let mut row: Vec<Square> = Vec::new();
            let mut j = 0isize;
            for square_type in content_row.iter() {
                let s = create_square(j, i, square_type.clone());
                row.push(s);
                j += 1;
            }
            i += 1;
            grid.push(row);
        }
        return grid;
    }

    pub fn update_display(&self, player: &Player) {
        self.renderer.clear_screen();
        self.renderer.render_grid(&self.grid, self.boxsize as i32, &self.textures);
        let player_texture = match self.player_textures.get(&player.orientation) {
            Some(t) => t,
            None => panic!(format!("error on texture retrieval for player orientation {}", player.orientation.clone() as isize))
        };
        self.renderer.render_player(&**player_texture, player.get_position(), self.boxsize as i32);
        self.renderer.renderer.present();
    }

    pub fn is_move_allowed(&self, player: &Player, movement: (i8, i8)) -> bool {
        let (x, y) = player.get_position();
        let (dx, dy) = movement;
        let new_x = x as isize + dx as isize;
        let new_y = y as isize + dy as isize;

        match self.grid[new_y as usize][new_x as usize].square_type {
            SquareType::EMPTY => true,
            SquareType::WALL => false,
            SquareType::BOX | SquareType::TARGETVALID => {
                let pos = ((new_x + dx as isize) as usize, (new_y + dy as isize) as usize);
                self.is_free(pos)
            },
            SquareType::TARGET => true
        }
    }
    pub fn is_free(&self, position: (usize, usize)) -> bool {
        let (x, y) = position;
        match self.grid[y][x].square_type {
            SquareType::EMPTY | SquareType::TARGET => true,
            _ => false
        }
    }
    pub fn is_box_present(&self, position: (usize, usize)) -> bool {
        let (x, y) = position;
        match self.grid[y][x].square_type {
            SquareType::BOX | SquareType::TARGETVALID => true,
            _ => false
        }
    }

    pub fn move_box(&mut self, position: (usize, usize), delta: (i8, i8)) {
        let (x, y) = position;
        let (dx, dy) = delta;
        let new_x = (x as isize + dx as isize) as usize;
        let new_y = (y as isize + dy as isize) as usize;
        match self.grid[y][x].square_type {
            SquareType::BOX => self.grid[y][x].square_type = SquareType::EMPTY,
            SquareType::TARGETVALID => self.grid[y][x].square_type = SquareType::TARGET,
            _ => ()
        };

        match self.grid[new_y][new_x].square_type {
            SquareType::EMPTY => self.grid[new_y][new_x].square_type = SquareType::BOX,
            SquareType::TARGET => self.grid[new_y][new_x].square_type = SquareType::TARGETVALID,
            _ => ()
        };
    }
}

pub struct Square {
    pub x: isize,
    pub y: isize,
    pub square_type: SquareType,
}

pub fn create_square(x: isize, y: isize, square_type: SquareType) -> Square {
    Square{x:x, y:y, square_type: square_type}
}
<|endoftext|>


<commit_before>use std::fmt;
use std::rc::Rc;
use std::borrow::Cow;
use std::mem;
use std::char;
use ::interpreter::Interpreter;
use ::grammar;
use ::scope::Scope;
use ::string_interner::StringInterner;

#[derive(Debug, Clone, PartialEq)]
pub struct Value {
    val_ptr: Rc<ValueData>
}

macro_rules! check_type {
    ($unwrap_fn:path, $e:expr, $type_name:expr) =>
    ({
        match $unwrap_fn($e) {
            Some(x) => x,
            None => return Value::new_condition(Value::new_string(format!("expected {}, got {:?}", $type_name, $e))),
        }
    });
}

impl Value {
    fn new_with(data: ValueData) -> Self {
        Value { val_ptr: Rc::new(data) }
    }

    pub fn new_bool(x: bool) -> Self { Self::new_with(ValueData::Bool(x)) }
    pub fn new_char(x: char) -> Self { Self::new_with(ValueData::Char(x)) }
    pub fn new_integer(x: i64) -> Self { Self::new_with(ValueData::Integer(x)) }
    pub fn new_symbol(id: u64) -> Self { Self::new_with(ValueData::Symbol(id)) }
    pub fn new_string<'a, T: 'a + Into<Cow<'a, str>>>(x: T) -> Self { Self::new_with(ValueData::String(x.into().into_owned())) }
    pub fn new_pair(a: Value, b: Value) -> Self { Self::new_with(ValueData::Pair(a,b)) }
    pub fn new_condition(x: Value) -> Self { Self::new_with(ValueData::Condition(x)) }
    pub fn empty_list() -> Self { Self::new_with(ValueData::EmptyList) }
    pub fn new_native_proc(f: fn(&mut Interpreter, &mut [Value]) -> Value) -> Self {
        let raw: *const () = f as *const ();
        Self::new_with(ValueData::NativeProc(raw))
    }
    pub fn new_proc(name: Option<String>, parent_scope: Scope, bindings: Vec<u64>, code: Value) -> Self {
        let procedure = Proc {
            name: name,
            parent_scope: parent_scope,
            bindings: bindings,
            code: code,
        };
        Self::new_with(ValueData::Proc(procedure))
    }

    fn data(&self) -> &ValueData {
        &*self.val_ptr
    }

    pub fn get_empty_list(&self) -> Option<()> {
        if let &ValueData::EmptyList = self.data() { Some(()) } else { None }
    }

    pub fn get_list(&self) -> Option<Vec<Value>> {
        match self.data() {
            &ValueData::Pair(_, ref b) if b.get_pair().is_some() || b.get_empty_list().is_some() => {
                Some(ListIter::new(self).cloned().collect())
            },
            &ValueData::EmptyList => Some(vec![]),
            _ => None
        }
    }

    pub fn get_symbol(&self) -> Option<u64> {
        match self.data() {
            &ValueData::Symbol(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_bool(&self) -> Option<bool> {
        match self.data() {
            &ValueData::Bool(b) => Some(b),
            _ => None,
        }
    }

    pub fn get_integer(&self) -> Option<i64> {
        match self.data() {
            &ValueData::Integer(i) => Some(i),
            _ => None,
        }
    }

    pub fn get_char(&self) -> Option<char> {
        match self.data() {
            &ValueData::Char(c) => Some(c),
            _ => None,
        }
    }

    pub fn get_string(&self) -> Option<&str> {
        match self.data() {
            &ValueData::String(ref s) => Some(s.as_str()),
            _ => None,
        }
    }

    pub fn get_pair(&self) -> Option<(&Value, &Value)> {
        match self.data() {
            &ValueData::Pair(ref a, ref b) => Some((a, b)),
            _ => None,
        }
    }

    pub fn get_condition(&self) -> Option<&Value> {
        match self.data() {
            &ValueData::Condition(ref x) => Some(x),
            _ => None,
        }
    }

    pub fn get_native_fn_ptr(&self) -> Option<fn(&mut Interpreter, &mut [Value]) -> Value> {
        match self.data() {
            &ValueData::NativeProc(f) => Some(unsafe { mem::transmute(f) }),
            _ => None,
        }
    }

    pub fn get_proc(&self) -> Option<&Proc> {
        match self.data() {
            &ValueData::Proc(ref p) => Some(p),
            _ => None,
        }
    }

    pub fn from_char_to_integer(a: &Value) -> Value {
        let c = check_type!(Value::get_char, a, "char");
        Value::new_integer(c as i64)
    }

    pub fn from_integer_to_char(a: &Value) -> Value {
        let i = check_type!(Value::get_integer, a, "integer");
        let c = char::from_u32(i as u32);
        if i > char::MAX as i64 || c.is_none() {
            return Value::new_condition(Value::new_string(format!("{} is no valid char", i)))
        } else {
            Value::new_char(c.unwrap())
        }
    }

    pub fn from_number_to_string(a: &Value) -> Value {
        let i = check_type!(Value::get_integer, a, "integer");
        Value::new_string(format!("{}", i))
    }

    pub fn from_string_to_number(a: &Value) -> Value {
        let s = check_type!(Value::get_string, a, "string");
        match grammar::parse_integer(s) {
            Ok(ref n) if n.get_integer().is_some() => n.clone(),
            _ => return Value::new_condition(Value::new_string(format!("{} is no valid integer", s)))
        }
    }

    pub fn new_list(elements: &[Value]) -> Value {
        if elements.len() == 0 { return Value::empty_list(); }
        let mut iter = elements.into_iter().rev();
        let last = iter.next().unwrap(); // safe because list len must be >= 1
        iter.fold(Value::new_pair(last.clone(), Value::empty_list()), |prev_pair, value| Value::new_pair(value.clone(), prev_pair))
    }

    pub fn to_string(&self, interner: &StringInterner) -> String {
        self.data().to_string(interner)
    }
}

pub struct ListIter<'a> {
    current: &'a Value,
}

impl<'a> ListIter<'a> {
    pub fn new(val: &'a Value) -> Self {
        ListIter { current: val }
    }
}

impl<'a> Iterator for ListIter<'a> {
    type Item = &'a Value;
    fn next(&mut self) -> Option<Self::Item> {
        match self.current.data() {
            &ValueData::Pair(ref a, ref b) if b.get_pair().is_some() || b.get_empty_list().is_some() => {
                self.current = b;
                Some(a)
            },
            &ValueData::Pair(ref a, _) => {
                let ret = self.current;
                self.current = a; // dummy
                Some(ret)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
enum ValueData {
    Bool(bool),
    Char(char),
    Integer(i64),
    Symbol(u64),
    String(String),
    Pair(Value, Value),
    EmptyList,
    Condition(Value),
    NativeProc(*const ()),
    Proc(Proc),
}

impl ValueData {
    fn to_string(&self, interner: &StringInterner) -> String {
        match self {
            &ValueData::Bool(x) => format!("{}", x),
            &ValueData::Char(x) => format!("{}", x),
            &ValueData::Integer(x) => format!("{}", x),
            &ValueData::Symbol(id) => format!("{}", interner.lookup(id).unwrap_or(&format!("[SYMBOL: {}]", id.to_string()))),
            &ValueData::String(ref x) => format!("\"{}\"", x),
            &ValueData::Pair(ref a, ref b) if b.get_pair().is_some() || b.get_empty_list().is_some() => {
                let iter = ListIter::new(b);
                let mut res = format!("({}", a.to_string(interner));
                for x in iter {
                    res.push_str(&format!(" {}", x.to_string(interner)));
                }
                res.push(')');
                res
            },
            &ValueData::Condition(ref x) => format!("[CONDITION: {:?}]", x),
            &ValueData::Pair(ref a, ref b) => format!("({} . {})", a.to_string(interner), b.to_string(interner)),
            &ValueData::EmptyList => format!("()"),
            &ValueData::NativeProc(x) => format!("[NATIVE_PROC: {:?}]", x),
            &ValueData::Proc(ref p) => format!("[PROC: {}]", p),
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Proc {
    name: Option<String>,
    parent_scope: Scope,
    bindings: Vec<u64>,
    code: Value,
}

impl Proc {
    pub fn evaluate(&self, interpreter: &mut Interpreter, args: &[Value]) -> Value {
        if self.bindings.len() != args.len() {
            let name = self.name.clone().unwrap_or("lambda".into());
            return Value::new_condition(Value::new_string(
                format!("arity mismatch for {}: expected: {}, got: {}", name, self.bindings.len(), args.len())));
        }

        let mut fn_scope = self.parent_scope.new_child();
        for (&binding, value) in self.bindings.iter().zip(args.iter()) {
            fn_scope.add_symbol(binding, value.clone());
        }

        let current_scope = interpreter.current_scope.clone(); // this is just one Rc::clone
        interpreter.current_scope = fn_scope;

        let res = interpreter.evaluate(&self.code);
        interpreter.current_scope = current_scope;
        res
    }
}

impl fmt::Display for Proc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        write!(f, "[PROC]")
        /* TODO
        let mut bindings: String = "(".into();
        for b in self.bindings.iter().take(self.bindings.len()-1) {
            bindings.push_str(b);
            bindings.push(' ');
        }
        bindings.push_str(self.bindings.last().unwrap_or(&String::new()));
        bindings.push(')');

        let name = self.name.as_ref().and_then(Value::get_symbol).unwrap_or("lambda");
        write!(f, "({} {} {})", name, bindings, self.code)
        */
    }
}

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

    #[test]
    fn pair_format() {
        fn v(x: i64) -> Value { Value::new_integer(x) }
        let empty = Value::empty_list();

        let a = Value::new_pair(v(4), empty.clone());
        let b = Value::new_pair(v(3), a.clone());
        let c = Value::new_pair(v(2), b.clone());
        let d = Value::new_pair(v(1), c.clone());

        assert_eq!(format!("{}", empty), "()");
        assert_eq!(format!("{}", a), "(4)");
        assert_eq!(format!("{}", b), "(3 4)");
        assert_eq!(format!("{}", c), "(2 3 4)");
        assert_eq!(format!("{}", d), "(1 2 3 4)");

        let x = Value::new_pair(v(3), v(4));
        let y = Value::new_pair(v(2), x.clone());
        let z = Value::new_pair(v(1), y.clone());

        assert_eq!(format!("{}", x), "(3 . 4)");
        assert_eq!(format!("{}", y), "(2 (3 . 4))");
        assert_eq!(format!("{}", z), "(1 2 (3 . 4))");

        let r = Value::new_pair(v(4), empty.clone());
        let s = Value::new_pair(v(2), v(3));
        let t = Value::new_pair(s.clone(), r.clone());
        let u = Value::new_pair(v(1), t.clone());
        let v = Value::new_pair(v(0), u.clone());

        assert_eq!(format!("{}", r), "(4)");
        assert_eq!(format!("{}", s), "(2 . 3)");
        assert_eq!(format!("{}", t), "((2 . 3) 4)");
        assert_eq!(format!("{}", u), "(1 (2 . 3) 4)");
        assert_eq!(format!("{}", v), "(0 1 (2 . 3) 4)");
    }
}
<commit_msg>fix lambda<commit_after>use std::fmt;
use std::rc::Rc;
use std::borrow::Cow;
use std::mem;
use std::char;
use ::interpreter::Interpreter;
use ::grammar;
use ::scope::Scope;
use ::string_interner::StringInterner;

#[derive(Debug, Clone, PartialEq)]
pub struct Value {
    val_ptr: Rc<ValueData>
}

macro_rules! check_type {
    ($unwrap_fn:path, $e:expr, $type_name:expr) =>
    ({
        match $unwrap_fn($e) {
            Some(x) => x,
            None => return Value::new_condition(Value::new_string(format!("expected {}, got {:?}", $type_name, $e))),
        }
    });
}

impl Value {
    fn new_with(data: ValueData) -> Self {
        Value { val_ptr: Rc::new(data) }
    }

    pub fn new_bool(x: bool) -> Self { Self::new_with(ValueData::Bool(x)) }
    pub fn new_char(x: char) -> Self { Self::new_with(ValueData::Char(x)) }
    pub fn new_integer(x: i64) -> Self { Self::new_with(ValueData::Integer(x)) }
    pub fn new_symbol(id: u64) -> Self { Self::new_with(ValueData::Symbol(id)) }
    pub fn new_string<'a, T: 'a + Into<Cow<'a, str>>>(x: T) -> Self { Self::new_with(ValueData::String(x.into().into_owned())) }
    pub fn new_pair(a: Value, b: Value) -> Self { Self::new_with(ValueData::Pair(a,b)) }
    pub fn new_condition(x: Value) -> Self { Self::new_with(ValueData::Condition(x)) }
    pub fn empty_list() -> Self { Self::new_with(ValueData::EmptyList) }
    pub fn new_native_proc(f: fn(&mut Interpreter, &mut [Value]) -> Value) -> Self {
        let raw: *const () = f as *const ();
        Self::new_with(ValueData::NativeProc(raw))
    }
    pub fn new_proc(name: Option<String>, parent_scope: Scope, bindings: Vec<u64>, code: Value) -> Self {
        let procedure = Proc {
            name: name,
            parent_scope: parent_scope,
            bindings: bindings,
            code: code,
        };
        Self::new_with(ValueData::Proc(procedure))
    }

    fn data(&self) -> &ValueData {
        &*self.val_ptr
    }

    pub fn get_empty_list(&self) -> Option<()> {
        if let &ValueData::EmptyList = self.data() { Some(()) } else { None }
    }

    pub fn get_list(&self) -> Option<Vec<Value>> {
        match self.data() {
            &ValueData::Pair(_, ref b) if b.get_pair().is_some() || b.get_empty_list().is_some() => {
                Some(ListIter::new(self).cloned().collect())
            },
            &ValueData::EmptyList => Some(vec![]),
            _ => None
        }
    }

    pub fn get_symbol(&self) -> Option<u64> {
        match self.data() {
            &ValueData::Symbol(id) => Some(id),
            _ => None,
        }
    }

    pub fn get_bool(&self) -> Option<bool> {
        match self.data() {
            &ValueData::Bool(b) => Some(b),
            _ => None,
        }
    }

    pub fn get_integer(&self) -> Option<i64> {
        match self.data() {
            &ValueData::Integer(i) => Some(i),
            _ => None,
        }
    }

    pub fn get_char(&self) -> Option<char> {
        match self.data() {
            &ValueData::Char(c) => Some(c),
            _ => None,
        }
    }

    pub fn get_string(&self) -> Option<&str> {
        match self.data() {
            &ValueData::String(ref s) => Some(s.as_str()),
            _ => None,
        }
    }

    pub fn get_pair(&self) -> Option<(&Value, &Value)> {
        match self.data() {
            &ValueData::Pair(ref a, ref b) => Some((a, b)),
            _ => None,
        }
    }

    pub fn get_condition(&self) -> Option<&Value> {
        match self.data() {
            &ValueData::Condition(ref x) => Some(x),
            _ => None,
        }
    }

    pub fn get_native_fn_ptr(&self) -> Option<fn(&mut Interpreter, &mut [Value]) -> Value> {
        match self.data() {
            &ValueData::NativeProc(f) => Some(unsafe { mem::transmute(f) }),
            _ => None,
        }
    }

    pub fn get_proc(&self) -> Option<&Proc> {
        match self.data() {
            &ValueData::Proc(ref p) => Some(p),
            _ => None,
        }
    }

    pub fn from_char_to_integer(a: &Value) -> Value {
        let c = check_type!(Value::get_char, a, "char");
        Value::new_integer(c as i64)
    }

    pub fn from_integer_to_char(a: &Value) -> Value {
        let i = check_type!(Value::get_integer, a, "integer");
        let c = char::from_u32(i as u32);
        if i > char::MAX as i64 || c.is_none() {
            return Value::new_condition(Value::new_string(format!("{} is no valid char", i)))
        } else {
            Value::new_char(c.unwrap())
        }
    }

    pub fn from_number_to_string(a: &Value) -> Value {
        let i = check_type!(Value::get_integer, a, "integer");
        Value::new_string(format!("{}", i))
    }

    pub fn from_string_to_number(a: &Value) -> Value {
        let s = check_type!(Value::get_string, a, "string");
        match grammar::parse_integer(s) {
            Ok(ref n) if n.get_integer().is_some() => n.clone(),
            _ => return Value::new_condition(Value::new_string(format!("{} is no valid integer", s)))
        }
    }

    pub fn new_list(elements: &[Value]) -> Value {
        if elements.len() == 0 { return Value::empty_list(); }
        let mut iter = elements.into_iter().rev();
        let last = iter.next().unwrap(); // safe because list len must be >= 1
        iter.fold(Value::new_pair(last.clone(), Value::empty_list()), |prev_pair, value| Value::new_pair(value.clone(), prev_pair))
    }

    pub fn to_string(&self, interner: &StringInterner) -> String {
        self.data().to_string(interner)
    }
}

pub struct ListIter<'a> {
    current: &'a Value,
}

impl<'a> ListIter<'a> {
    pub fn new(val: &'a Value) -> Self {
        ListIter { current: val }
    }
}

impl<'a> Iterator for ListIter<'a> {
    type Item = &'a Value;
    fn next(&mut self) -> Option<Self::Item> {
        match self.current.data() {
            &ValueData::Pair(ref a, ref b) if b.get_pair().is_some() || b.get_empty_list().is_some() => {
                self.current = b;
                Some(a)
            },
            &ValueData::Pair(ref a, _) => {
                let ret = self.current;
                self.current = a; // dummy
                Some(ret)
            }
            _ => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
enum ValueData {
    Bool(bool),
    Char(char),
    Integer(i64),
    Symbol(u64),
    String(String),
    Pair(Value, Value),
    EmptyList,
    Condition(Value),
    NativeProc(*const ()),
    Proc(Proc),
}

impl ValueData {
    fn to_string(&self, interner: &StringInterner) -> String {
        match self {
            &ValueData::Bool(x) => format!("{}", x),
            &ValueData::Char(x) => format!("{}", x),
            &ValueData::Integer(x) => format!("{}", x),
            &ValueData::Symbol(id) => format!("{}", interner.lookup(id).unwrap_or(&format!("[SYMBOL: {}]", id.to_string()))),
            &ValueData::String(ref x) => format!("\"{}\"", x),
            &ValueData::Pair(ref a, ref b) if b.get_pair().is_some() || b.get_empty_list().is_some() => {
                let iter = ListIter::new(b);
                let mut res = format!("({}", a.to_string(interner));
                for x in iter {
                    res.push_str(&format!(" {}", x.to_string(interner)));
                }
                res.push(')');
                res
            },
            &ValueData::Condition(ref x) => format!("[CONDITION: {:?}]", x),
            &ValueData::Pair(ref a, ref b) => format!("({} . {})", a.to_string(interner), b.to_string(interner)),
            &ValueData::EmptyList => format!("()"),
            &ValueData::NativeProc(x) => format!("[NATIVE_PROC: {:?}]", x),
            &ValueData::Proc(ref p) => format!("[PROC: {}]", p),
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct Proc {
    name: Option<String>,
    parent_scope: Scope,
    bindings: Vec<u64>,
    code: Value,
}

impl Proc {
    pub fn evaluate(&self, interpreter: &mut Interpreter, args: &[Value]) -> Value {
        if self.bindings.len() != args.len() {
            let name = self.name.clone().unwrap_or("lambda".into());
            return Value::new_condition(Value::new_string(
                format!("arity mismatch for {}: expected: {}, got: {}", name, self.bindings.len(), args.len())));
        }

        // evaluate args in current scope
        let evaluated_args: Vec<Value> = args.iter().map(|x| interpreter.evaluate(x)).collect();

        // create new scope for fn from fns parent scope
        let mut fn_scope = self.parent_scope.new_child();

        // add args to fn scope
        for (&binding, value) in self.bindings.iter().zip(evaluated_args.into_iter()) {
            fn_scope.add_symbol(binding, value);
        }

        // backup current scope
        let old_scope = interpreter.current_scope.clone(); // this is just one Rc::clone

        // evaluate code in fn scope
        interpreter.current_scope = fn_scope;
        let res = interpreter.evaluate(&self.code);
        interpreter.current_scope = old_scope;
        res
    }
}

impl fmt::Display for Proc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        write!(f, "[PROC]")
        /* TODO
        let mut bindings: String = "(".into();
        for b in self.bindings.iter().take(self.bindings.len()-1) {
            bindings.push_str(b);
            bindings.push(' ');
        }
        bindings.push_str(self.bindings.last().unwrap_or(&String::new()));
        bindings.push(')');

        let name = self.name.as_ref().and_then(Value::get_symbol).unwrap_or("lambda");
        write!(f, "({} {} {})", name, bindings, self.code)
        */
    }
}

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

    #[test]
    fn pair_format() {
        fn v(x: i64) -> Value { Value::new_integer(x) }
        let empty = Value::empty_list();

        let a = Value::new_pair(v(4), empty.clone());
        let b = Value::new_pair(v(3), a.clone());
        let c = Value::new_pair(v(2), b.clone());
        let d = Value::new_pair(v(1), c.clone());

        assert_eq!(format!("{}", empty), "()");
        assert_eq!(format!("{}", a), "(4)");
        assert_eq!(format!("{}", b), "(3 4)");
        assert_eq!(format!("{}", c), "(2 3 4)");
        assert_eq!(format!("{}", d), "(1 2 3 4)");

        let x = Value::new_pair(v(3), v(4));
        let y = Value::new_pair(v(2), x.clone());
        let z = Value::new_pair(v(1), y.clone());

        assert_eq!(format!("{}", x), "(3 . 4)");
        assert_eq!(format!("{}", y), "(2 (3 . 4))");
        assert_eq!(format!("{}", z), "(1 2 (3 . 4))");

        let r = Value::new_pair(v(4), empty.clone());
        let s = Value::new_pair(v(2), v(3));
        let t = Value::new_pair(s.clone(), r.clone());
        let u = Value::new_pair(v(1), t.clone());
        let v = Value::new_pair(v(0), u.clone());

        assert_eq!(format!("{}", r), "(4)");
        assert_eq!(format!("{}", s), "(2 . 3)");
        assert_eq!(format!("{}", t), "((2 . 3) 4)");
        assert_eq!(format!("{}", u), "(1 (2 . 3) 4)");
        assert_eq!(format!("{}", v), "(0 1 (2 . 3) 4)");
    }
}
<|endoftext|>


<commit_before>use std;

#[derive(Debug,Clone,PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  StrLit(String),
  Name(String),

  // Keywords
  Break,
  Continue,
  Else,
  For,
  Func,
  If,
  Return,
  While,

  // Symbols
  Arr, // ->
  Col, // :
  Com, // ,
  Dot, // .
  Ass, // =

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  Div, // /
  Mul, // *
  Sub, // -
  Dol, // $
  Pct, // %
  Car, // ^
  And, // &
  Or,  // |
  Not, // !
  Neg, // ~

  // Comparisons
  Gt,  // >
  Ge,  // >=
  Lt,  // <
  Le,  // <=
  Ne,  // !=
  Eql, // ==
}

use self::Token::*;

fn lex_number(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut digits = String::new();
  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

pub fn lex(input: &str) {
  let mut tokens: Vec<Token> = Vec::new();
  let mut it = input.chars().peekable();

  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' => {
        tokens.push(lex_number(&mut it));
      }
      '-' => {
        it.next();
        match it.peek() {
          Some(&'>') => {
            tokens.push(Arr);
            it.next();
          }
          _ => {
            tokens.push(Sub);
          }
        }
      }
      '+' => {tokens.push(Add); it.next();}
      '/' => {tokens.push(Div); it.next();}
      '*' => {tokens.push(Mul); it.next();}
      '(' => {tokens.push(Pal); it.next();}
      ')' => {tokens.push(Par); it.next();}
      '[' => {tokens.push(Sql); it.next();}
      ']' => {tokens.push(Sqr); it.next();}
      '{' => {tokens.push(Cul); it.next();}
      '}' => {tokens.push(Cur); it.next();}
      '<' => {tokens.push(Lt); it.next();}
      '>' => {tokens.push(Gt); it.next();}
      _ => {it.next();}
    }
  }

  println!("{:?}", tokens);
}
<commit_msg>lexer: Add a few symbol tokens and sort them<commit_after>use std;

#[derive(Debug,Clone,PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  StrLit(String),
  Name(String),

  // Keywords
  Break,
  Continue,
  Else,
  For,
  Func,
  If,
  Return,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

use self::Token::*;

fn lex_number(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut digits = String::new();
  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

pub fn lex(input: &str) {
  let mut tokens: Vec<Token> = Vec::new();
  let mut it = input.chars().peekable();

  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' => {
        tokens.push(lex_number(&mut it));
      }
      '-' => {
        it.next();
        match it.peek() {
          Some(&'>') => {
            tokens.push(Arr);
            it.next();
          }
          _ => {
            tokens.push(Sub);
          }
        }
      }
      '+' => {tokens.push(Add); it.next();}
      '/' => {tokens.push(Div); it.next();}
      '*' => {tokens.push(Mul); it.next();}
      '(' => {tokens.push(Pal); it.next();}
      ')' => {tokens.push(Par); it.next();}
      '[' => {tokens.push(Sql); it.next();}
      ']' => {tokens.push(Sqr); it.next();}
      '{' => {tokens.push(Cul); it.next();}
      '}' => {tokens.push(Cur); it.next();}
      '<' => {tokens.push(Lt); it.next();}
      '>' => {tokens.push(Gt); it.next();}
      _ => {it.next();}
    }
  }

  println!("{:?}", tokens);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/* automatically generated by rust-bindgen */

#[allow(non_uppercase_statics)];

use std::libc::*;

type enum_unnamed1 = c_uint;
//static STBI_default: u32 = 0_u32;
//static STBI_grey: u32 = 1_u32;
//static STBI_grey_alpha: u32 = 2_u32;
//static STBI_rgb: u32 = 3_u32;
//static STBI_rgb_alpha: u32 = 4_u32;

pub mod bindgen {
  use std::libc::*;

  type stbi_uc = c_uchar;
  struct stbi_io_callbacks {
    read: *u8,
    skip: *u8,
    eof: *u8,
  }

#[link(name = "stb-image")]
extern {

pub fn stbi_load_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_load(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_load_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_load_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_loadf_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_loadf(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_loadf_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_loadf_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_hdr_to_ldr_gamma(gamma: c_float);

pub fn stbi_hdr_to_ldr_scale(scale: c_float);

pub fn stbi_ldr_to_hdr_gamma(gamma: c_float);

pub fn stbi_ldr_to_hdr_scale(scale: c_float);

pub fn stbi_is_hdr_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void) -> c_int;

pub fn stbi_is_hdr_from_memory(buffer: *stbi_uc, len: c_int) -> c_int;

pub fn stbi_is_hdr(filename: *c_char) -> c_int;

pub fn stbi_is_hdr_from_file(f: *FILE) -> c_int;

pub fn stbi_failure_reason() -> *c_char;

pub fn stbi_image_free(retval_from_stbi_load: *c_void);

pub fn stbi_info_from_memory(buffer: *stbi_uc, len: c_int, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_info_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_info(filename: *c_char, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_info_from_file(f: *FILE, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_set_unpremultiply_on_load(flag_true_if_should_unpremultiply: c_int);

pub fn stbi_convert_iphone_png_to_rgb(flag_true_if_should_convert: c_int);

pub fn stbi_zlib_decode_malloc_guesssize(buffer: *c_char, len: c_int, initial_size: c_int, outlen: *c_int) -> *c_char;

pub fn stbi_zlib_decode_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

pub fn stbi_zlib_decode_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

pub fn stbi_zlib_decode_noheader_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

pub fn stbi_zlib_decode_noheader_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

  }
}
<commit_msg>Warning police.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/* automatically generated by rust-bindgen */

#[allow(non_uppercase_statics, non_camel_case_types)];

use std::libc::*;

type enum_unnamed1 = c_uint;
//static STBI_default: u32 = 0_u32;
//static STBI_grey: u32 = 1_u32;
//static STBI_grey_alpha: u32 = 2_u32;
//static STBI_rgb: u32 = 3_u32;
//static STBI_rgb_alpha: u32 = 4_u32;

pub mod bindgen {
  use std::libc::*;

  type stbi_uc = c_uchar;
  struct stbi_io_callbacks {
    read: *u8,
    skip: *u8,
    eof: *u8,
  }

#[link(name = "stb-image")]
extern {

pub fn stbi_load_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_load(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_load_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_load_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *stbi_uc;

pub fn stbi_loadf_from_memory(buffer: *stbi_uc, len: c_int, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_loadf(filename: *c_char, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_loadf_from_file(f: *FILE, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_loadf_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *mut c_int, y: *mut c_int, comp: *mut c_int, req_comp: c_int) -> *c_float;

pub fn stbi_hdr_to_ldr_gamma(gamma: c_float);

pub fn stbi_hdr_to_ldr_scale(scale: c_float);

pub fn stbi_ldr_to_hdr_gamma(gamma: c_float);

pub fn stbi_ldr_to_hdr_scale(scale: c_float);

pub fn stbi_is_hdr_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void) -> c_int;

pub fn stbi_is_hdr_from_memory(buffer: *stbi_uc, len: c_int) -> c_int;

pub fn stbi_is_hdr(filename: *c_char) -> c_int;

pub fn stbi_is_hdr_from_file(f: *FILE) -> c_int;

pub fn stbi_failure_reason() -> *c_char;

pub fn stbi_image_free(retval_from_stbi_load: *c_void);

pub fn stbi_info_from_memory(buffer: *stbi_uc, len: c_int, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_info_from_callbacks(clbk: *stbi_io_callbacks, user: *c_void, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_info(filename: *c_char, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_info_from_file(f: *FILE, x: *c_int, y: *c_int, comp: *c_int) -> c_int;

pub fn stbi_set_unpremultiply_on_load(flag_true_if_should_unpremultiply: c_int);

pub fn stbi_convert_iphone_png_to_rgb(flag_true_if_should_convert: c_int);

pub fn stbi_zlib_decode_malloc_guesssize(buffer: *c_char, len: c_int, initial_size: c_int, outlen: *c_int) -> *c_char;

pub fn stbi_zlib_decode_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

pub fn stbi_zlib_decode_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

pub fn stbi_zlib_decode_noheader_malloc(buffer: *c_char, len: c_int, outlen: *c_int) -> *c_char;

pub fn stbi_zlib_decode_noheader_buffer(obuffer: *c_char, olen: c_int, ibuffer: *c_char, ilen: c_int) -> c_int;

  }
}
<|endoftext|>


<commit_before>pub use std::collections::HashMap;
pub use api::*;
use errors::*;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, to_value, Value, Map};

/// A trait for any struct that can be converted from/into a Resource.
/// The only requirement is that your struct has an 'id: String' field.
/// You shouldn't be implementing JsonApiModel manually, look at the
/// `jsonapi_model!` macro instead.
pub trait JsonApiModel: Serialize
    where for<'de> Self: Deserialize<'de>
{
    #[doc(hidden)]
    fn jsonapi_type(&self) -> String;
    #[doc(hidden)]
    fn jsonapi_id(&self) -> String;
    #[doc(hidden)]
    fn relationship_fields() -> Option<&'static [&'static str]>;
    #[doc(hidden)]
    fn build_relationships(&self) -> Option<Relationships>;
    #[doc(hidden)]
    fn build_included(&self) -> Option<Resources>;

    fn from_jsonapi_resource(resource: &Resource, included: &Option<Resources>)
        -> Result<Self>
    {
        Self::from_serializable(Self::resource_to_attrs(resource, included))
    }

    fn from_jsonapi_document(doc: &JsonApiDocument) -> Result<Self> {
        match doc.data.as_ref() {
            Some(primary_data) => {
                match *primary_data {
                    PrimaryData::None => bail!("Document had no data"),
                    PrimaryData::Single(ref resource) =>
                        Self::from_jsonapi_resource(resource, &doc.included),
                    PrimaryData::Multiple(ref resources) => {
                        let all: Vec<ResourceAttributes> = resources
                            .iter()
                            .map(|r| Self::resource_to_attrs(r, &doc.included))
                            .collect();
                        Self::from_serializable(all)
                    }
                }
            },
            None => bail!("Document had no data")
        }
    }

    fn to_jsonapi_resource(&self) -> (Resource, Option<Resources>) {
        if let Value::Object(mut attrs) = to_value(self).unwrap(){
            let id_value = attrs
                .remove("id")
                .unwrap_or_else(|| Value::String("".into()));

            let resource = Resource{
                _type: self.jsonapi_type(),
                id: from_value(id_value).unwrap_or_else(|_| "".into()),
                relationships: self.build_relationships(),
                attributes: Self::extract_attributes(&attrs),
                ..Default::default()
            };

            (resource, self.build_included())
        }else{
            panic!(format!("{} is not a Value::Object", self.jsonapi_type()))
        }
    }

    fn to_jsonapi_document(&self) -> JsonApiDocument {
        let (resource, included) = self.to_jsonapi_resource();
        JsonApiDocument {
            data: Some(PrimaryData::Single(Box::new(resource))),
            included: included,
            ..Default::default()
        }
    }

    #[doc(hidden)]
    fn build_has_one<M: JsonApiModel>(model: &M) -> Relationship {
        Relationship{
            data: IdentifierData::Single(model.as_resource_identifier()),
            links: None
        }
    }

    #[doc(hidden)]
    fn build_has_many<M: JsonApiModel>(models: &[M]) -> Relationship {
        Relationship{
            data: IdentifierData::Multiple(
                models.iter().map(|m| m.as_resource_identifier()).collect()
            ),
            links: None
        }
    }

    #[doc(hidden)]
    fn as_resource_identifier(&self) -> ResourceIdentifier {
        ResourceIdentifier {
            _type: self.jsonapi_type(),
            id: self.jsonapi_id(),
        }
    }

    /* Attribute corresponding to the model is removed from the Map
     * before calling this, so there's no need to ignore it like we do
     * with the attributes that correspond with relationships.
     * */
    #[doc(hidden)]
    fn extract_attributes(attrs: &Map<String, Value>) -> ResourceAttributes {
        attrs.iter().filter(|&(key, _)|{
            if let Some(fields) = Self::relationship_fields(){
                if fields.contains(&key.as_str()) {
                    return false;
                }
            }
            true
        }).map(|(k,v)|{ (k.clone(), v.clone()) }).collect()
    }

    #[doc(hidden)]
    fn to_resources(&self) -> Resources {
        let (me, maybe_others) = self.to_jsonapi_resource();
        let mut flattened = vec![me];
        if let Some(mut others) = maybe_others {
            flattened.append(&mut others);
        }
        flattened
    }

    #[doc(hidden)]
    fn lookup<'a>(needle: &ResourceIdentifier, haystack: &'a [Resource])
        -> Option<&'a Resource>
    {
        for resource in haystack {
            if resource._type == needle._type && resource.id == needle.id {
                return Some(resource)
            }
        }
        None
    }

    #[doc(hidden)]
    fn resource_to_attrs(resource: &Resource, included: &Option<Resources>)
        -> ResourceAttributes
    {
        let mut new_attrs = HashMap::new();
        new_attrs.clone_from(&resource.attributes);
        new_attrs.insert("id".into(), resource.id.clone().into());

        if let Some(relations) = resource.relationships.as_ref() {
            if let Some(inc) = included.as_ref() {
                for (name, relation) in relations {
                    let value = match relation.data {
                        IdentifierData::None => Value::Null,
                        IdentifierData::Single(ref identifier) => {
                            let found = Self::lookup(identifier, inc)
                                .map(|r| Self::resource_to_attrs(r, included) );
                            to_value(found)
                                .expect("Casting Single relation to value")
                        },
                        IdentifierData::Multiple(ref identifiers) => {
                            let found: Vec<Option<ResourceAttributes>> =
                                identifiers.iter().map(|id|{
                                    Self::lookup(id, inc).map(|r|{
                                        Self::resource_to_attrs(r, included)
                                    })
                                }).collect();
                            to_value(found)
                                .expect("Casting Multiple relation to value")
                        },
                    };
                    new_attrs.insert(name.to_string(), value);
                }
            }
        }

        new_attrs
    }

    #[doc(hidden)]
    fn from_serializable<S: Serialize>(s: S) -> Result<Self> {
        from_value(to_value(s).unwrap())
            .chain_err(|| "Error casting via serde_json")
    }
}

#[macro_export]
macro_rules! jsonapi_model {
    ($model:ty; $type:expr) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }
            fn relationship_fields() -> Option<&'static [&'static str]> { None }
            fn build_relationships(&self) -> Option<Relationships> { None }
            fn build_included(&self) -> Option<Resources> { None }
        }
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one $( $has_one ),*; has many);
    );
    ($model:ty; $type:expr;
        has many $( $has_many:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one; has many $( $has_many ),*);
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*;
        has many $( $has_many:ident ),*
    ) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }

            fn relationship_fields() -> Option<&'static [&'static str]> {
                Some(&[
                     $( stringify!($has_one),)*
                     $( stringify!($has_many),)*
                ])
            }

            fn build_relationships(&self) -> Option<Relationships> {
                let mut relationships = HashMap::new();
                $(
                    relationships.insert(stringify!($has_one).into(),
                        Self::build_has_one(&self.$has_one)
                    );
                )*
                $(
                    relationships.insert(stringify!($has_many).into(),
                        Self::build_has_many(&self.$has_many)
                    );
                )*
                Some(relationships)
            }

            fn build_included(&self) -> Option<Resources> {
                let mut included:Resources = vec![];
                $( included.append(&mut self.$has_one.to_resources()); )*
                $(
                    for model in &self.$has_many {
                        included.append(&mut model.to_resources());
                    }
                )*
                Some(included)
            }
        }
    );
}
<commit_msg>fix issue with static slice reference on stable<commit_after>pub use std::collections::HashMap;
pub use api::*;
use errors::*;
use serde::{Deserialize, Serialize};
use serde_json::{from_value, to_value, Value, Map};

/// A trait for any struct that can be converted from/into a Resource.
/// The only requirement is that your struct has an 'id: String' field.
/// You shouldn't be implementing JsonApiModel manually, look at the
/// `jsonapi_model!` macro instead.
pub trait JsonApiModel: Serialize
    where for<'de> Self: Deserialize<'de>
{
    #[doc(hidden)]
    fn jsonapi_type(&self) -> String;
    #[doc(hidden)]
    fn jsonapi_id(&self) -> String;
    #[doc(hidden)]
    fn relationship_fields() -> Option<&'static [&'static str]>;
    #[doc(hidden)]
    fn build_relationships(&self) -> Option<Relationships>;
    #[doc(hidden)]
    fn build_included(&self) -> Option<Resources>;

    fn from_jsonapi_resource(resource: &Resource, included: &Option<Resources>)
        -> Result<Self>
    {
        Self::from_serializable(Self::resource_to_attrs(resource, included))
    }

    fn from_jsonapi_document(doc: &JsonApiDocument) -> Result<Self> {
        match doc.data.as_ref() {
            Some(primary_data) => {
                match *primary_data {
                    PrimaryData::None => bail!("Document had no data"),
                    PrimaryData::Single(ref resource) =>
                        Self::from_jsonapi_resource(resource, &doc.included),
                    PrimaryData::Multiple(ref resources) => {
                        let all: Vec<ResourceAttributes> = resources
                            .iter()
                            .map(|r| Self::resource_to_attrs(r, &doc.included))
                            .collect();
                        Self::from_serializable(all)
                    }
                }
            },
            None => bail!("Document had no data")
        }
    }

    fn to_jsonapi_resource(&self) -> (Resource, Option<Resources>) {
        if let Value::Object(mut attrs) = to_value(self).unwrap(){
            let id_value = attrs
                .remove("id")
                .unwrap_or_else(|| Value::String("".into()));

            let resource = Resource{
                _type: self.jsonapi_type(),
                id: from_value(id_value).unwrap_or_else(|_| "".into()),
                relationships: self.build_relationships(),
                attributes: Self::extract_attributes(&attrs),
                ..Default::default()
            };

            (resource, self.build_included())
        }else{
            panic!(format!("{} is not a Value::Object", self.jsonapi_type()))
        }
    }

    fn to_jsonapi_document(&self) -> JsonApiDocument {
        let (resource, included) = self.to_jsonapi_resource();
        JsonApiDocument {
            data: Some(PrimaryData::Single(Box::new(resource))),
            included: included,
            ..Default::default()
        }
    }

    #[doc(hidden)]
    fn build_has_one<M: JsonApiModel>(model: &M) -> Relationship {
        Relationship{
            data: IdentifierData::Single(model.as_resource_identifier()),
            links: None
        }
    }

    #[doc(hidden)]
    fn build_has_many<M: JsonApiModel>(models: &[M]) -> Relationship {
        Relationship{
            data: IdentifierData::Multiple(
                models.iter().map(|m| m.as_resource_identifier()).collect()
            ),
            links: None
        }
    }

    #[doc(hidden)]
    fn as_resource_identifier(&self) -> ResourceIdentifier {
        ResourceIdentifier {
            _type: self.jsonapi_type(),
            id: self.jsonapi_id(),
        }
    }

    /* Attribute corresponding to the model is removed from the Map
     * before calling this, so there's no need to ignore it like we do
     * with the attributes that correspond with relationships.
     * */
    #[doc(hidden)]
    fn extract_attributes(attrs: &Map<String, Value>) -> ResourceAttributes {
        attrs.iter().filter(|&(key, _)|{
            if let Some(fields) = Self::relationship_fields(){
                if fields.contains(&key.as_str()) {
                    return false;
                }
            }
            true
        }).map(|(k,v)|{ (k.clone(), v.clone()) }).collect()
    }

    #[doc(hidden)]
    fn to_resources(&self) -> Resources {
        let (me, maybe_others) = self.to_jsonapi_resource();
        let mut flattened = vec![me];
        if let Some(mut others) = maybe_others {
            flattened.append(&mut others);
        }
        flattened
    }

    #[doc(hidden)]
    fn lookup<'a>(needle: &ResourceIdentifier, haystack: &'a [Resource])
        -> Option<&'a Resource>
    {
        for resource in haystack {
            if resource._type == needle._type && resource.id == needle.id {
                return Some(resource)
            }
        }
        None
    }

    #[doc(hidden)]
    fn resource_to_attrs(resource: &Resource, included: &Option<Resources>)
        -> ResourceAttributes
    {
        let mut new_attrs = HashMap::new();
        new_attrs.clone_from(&resource.attributes);
        new_attrs.insert("id".into(), resource.id.clone().into());

        if let Some(relations) = resource.relationships.as_ref() {
            if let Some(inc) = included.as_ref() {
                for (name, relation) in relations {
                    let value = match relation.data {
                        IdentifierData::None => Value::Null,
                        IdentifierData::Single(ref identifier) => {
                            let found = Self::lookup(identifier, inc)
                                .map(|r| Self::resource_to_attrs(r, included) );
                            to_value(found)
                                .expect("Casting Single relation to value")
                        },
                        IdentifierData::Multiple(ref identifiers) => {
                            let found: Vec<Option<ResourceAttributes>> =
                                identifiers.iter().map(|id|{
                                    Self::lookup(id, inc).map(|r|{
                                        Self::resource_to_attrs(r, included)
                                    })
                                }).collect();
                            to_value(found)
                                .expect("Casting Multiple relation to value")
                        },
                    };
                    new_attrs.insert(name.to_string(), value);
                }
            }
        }

        new_attrs
    }

    #[doc(hidden)]
    fn from_serializable<S: Serialize>(s: S) -> Result<Self> {
        from_value(to_value(s).unwrap())
            .chain_err(|| "Error casting via serde_json")
    }
}

#[macro_export]
macro_rules! jsonapi_model {
    ($model:ty; $type:expr) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }
            fn relationship_fields() -> Option<&'static [&'static str]> { None }
            fn build_relationships(&self) -> Option<Relationships> { None }
            fn build_included(&self) -> Option<Resources> { None }
        }
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one $( $has_one ),*; has many);
    );
    ($model:ty; $type:expr;
        has many $( $has_many:ident ),*
    ) => (
        jsonapi_model!($model; $type; has one; has many $( $has_many ),*);
    );
    ($model:ty; $type:expr;
        has one $( $has_one:ident ),*;
        has many $( $has_many:ident ),*
    ) => (
        impl JsonApiModel for $model {
            fn jsonapi_type(&self) -> String { $type.to_string() }
            fn jsonapi_id(&self) -> String { self.id.to_string() }

            fn relationship_fields() -> Option<&'static [&'static str]> {
                static FIELDS: &'static [&'static str] = &[
                     $( stringify!($has_one),)*
                     $( stringify!($has_many),)*
                ];

                Some(FIELDS)
            }

            fn build_relationships(&self) -> Option<Relationships> {
                let mut relationships = HashMap::new();
                $(
                    relationships.insert(stringify!($has_one).into(),
                        Self::build_has_one(&self.$has_one)
                    );
                )*
                $(
                    relationships.insert(stringify!($has_many).into(),
                        Self::build_has_many(&self.$has_many)
                    );
                )*
                Some(relationships)
            }

            fn build_included(&self) -> Option<Resources> {
                let mut included:Resources = vec![];
                $( included.append(&mut self.$has_one.to_resources()); )*
                $(
                    for model in &self.$has_many {
                        included.append(&mut model.to_resources());
                    }
                )*
                Some(included)
            }
        }
    );
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Dog {
    id: String,
    name: String,
    age: i32,
    main_flea: Flea,
    fleas: Vec<Flea>,
}
jsonapi_model!(Dog; "dog"; has one main_flea; has many fleas);
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Flea {
    id: String,
    name: String,
}
jsonapi_model!(Flea; "flea");
<|endoftext|>


<commit_before>use regex::Regex;

use iron::{Middleware, Request, Response, Alloy, Chain};
use iron::middleware::{Status, Continue};
use iron::mixin::GetUrl;

/// Exposes the original, unmodified path to be stored in an Alloy.
pub struct OriginalUrl(String);

/// `Mount` is a simple mounting middleware.
///
/// `Mount` allows you to mount other middleware within a larger chain.
///
/// Mounted middleware will receive a modified version of the request
/// url with the mount pattern removed from the start of the url.
pub struct Mount {
    route: String,
    matches: Regex,
    middleware: Box<Middleware + Send>
}

impl Clone for Mount {
    fn clone(&self) -> Mount {
        Mount {
            route: self.route.clone(),
            matches: self.matches.clone(),
            middleware: self.middleware.clone_box()
        }
    }
}

impl Mount {
    /// Creates a new instance of `Mount` mounting the given instance of Iron
    /// on the given path.
    pub fn new<M: Middleware + Send>(route: &str, middleware: M) -> Mount {
        Mount {
            route: route.to_string(),
            middleware: box middleware,
            matches: to_regex(route)
        }
    }
}

fn to_regex(route: &str) -> Regex {
    Regex::new("^".to_string().append(route).as_slice()).unwrap()
}

impl Middleware for Mount {
    fn enter(&mut self,
             req: &mut Request,
             res: &mut Response,
             alloy: &mut Alloy) -> Status {
        // This method is ugly, but it is hard to make it pretty
        // because we can't both borrow path from inside of request
        // while allowing chain.dispatch to borrow it as mutable.

        match req.url() {
           Some(path) => {
               // Short circuit if we don't match.
                if !self.matches.is_match(path.as_slice()) {
                    return Continue;
                }
           },
           // Short circuit if this is not an AbsolutePath.
           None => { return Continue; }
        }

        // We are a match, so fire off to our child instance.
        match req.url_mut() {
            Some(path) => {
                // Insert the unmodified path into the alloy.
                match alloy.find::<OriginalUrl>() {
                    Some(_) => (),
                    None => alloy.insert(OriginalUrl(path.clone()))
                }
                *path = path.as_slice().slice_from(self.route.len()).to_string();
            },
            // Absolutely cannot happen because of our previous check,
            // but this is here just to be careful.
            None => { return Continue; }
        } // Previous borrow of req ends here.

        // So we can borrow it again here.
        let terminator = self.middleware.enter(req, res, alloy);
        let _ = self.middleware.exit(req, res, alloy);

        // And repair the damage here, for future middleware
        match req.url_mut() {
            Some(path) => {
                *path = self.route.clone().append(path.as_slice());
            },
            // This really, really should never happen.
            None => { fail!("The impossible happened."); }
        }

        // We dispatched the request, so return the terminator.
        terminator
    }
}

<commit_msg>(fix) Publicized OriginalUrl tuple.<commit_after>use regex::Regex;

use iron::{Middleware, Request, Response, Alloy, Chain};
use iron::middleware::{Status, Continue};
use iron::mixin::GetUrl;

/// Exposes the original, unmodified path to be stored in an Alloy.
pub struct OriginalUrl(pub String);

/// `Mount` is a simple mounting middleware.
///
/// `Mount` allows you to mount other middleware within a larger chain.
///
/// Mounted middleware will receive a modified version of the request
/// url with the mount pattern removed from the start of the url.
pub struct Mount {
    route: String,
    matches: Regex,
    middleware: Box<Middleware + Send>
}

impl Clone for Mount {
    fn clone(&self) -> Mount {
        Mount {
            route: self.route.clone(),
            matches: self.matches.clone(),
            middleware: self.middleware.clone_box()
        }
    }
}

impl Mount {
    /// Creates a new instance of `Mount` mounting the given instance of Iron
    /// on the given path.
    pub fn new<M: Middleware + Send>(route: &str, middleware: M) -> Mount {
        Mount {
            route: route.to_string(),
            middleware: box middleware,
            matches: to_regex(route)
        }
    }
}

fn to_regex(route: &str) -> Regex {
    Regex::new("^".to_string().append(route).as_slice()).unwrap()
}

impl Middleware for Mount {
    fn enter(&mut self,
             req: &mut Request,
             res: &mut Response,
             alloy: &mut Alloy) -> Status {
        // This method is ugly, but it is hard to make it pretty
        // because we can't both borrow path from inside of request
        // while allowing chain.dispatch to borrow it as mutable.

        match req.url() {
           Some(path) => {
               // Short circuit if we don't match.
                if !self.matches.is_match(path.as_slice()) {
                    return Continue;
                }
           },
           // Short circuit if this is not an AbsolutePath.
           None => { return Continue; }
        }

        // We are a match, so fire off to our child instance.
        match req.url_mut() {
            Some(path) => {
                // Insert the unmodified path into the alloy.
                match alloy.find::<OriginalUrl>() {
                    Some(_) => (),
                    None => alloy.insert(OriginalUrl(path.clone()))
                }
                *path = path.as_slice().slice_from(self.route.len()).to_string();
            },
            // Absolutely cannot happen because of our previous check,
            // but this is here just to be careful.
            None => { return Continue; }
        } // Previous borrow of req ends here.

        // So we can borrow it again here.
        let terminator = self.middleware.enter(req, res, alloy);
        let _ = self.middleware.exit(req, res, alloy);

        // And repair the damage here, for future middleware
        match req.url_mut() {
            Some(path) => {
                *path = self.route.clone().append(path.as_slice());
            },
            // This really, really should never happen.
            None => { fail!("The impossible happened."); }
        }

        // We dispatched the request, so return the terminator.
        terminator
    }
}

<|endoftext|>