<commit_before>//! Handlers
//!  - Endpoint handlers
//!
use std::io::{self, Read, Write};
use std::path::PathBuf;
use std::ffi::OsStr;
use std::fs;
use std::env;
use std::time as std_time;
use std::fmt;
use std::thread;

use reqwest;
use url::Url;
use iron::prelude::*;
use iron::{self, status, modifiers, Handler};
use persistent;
use router::Router;
use params::Params;
use mime;
use chrono::{self, UTC};
use tera::Context;

use service::{Cache, Record, Templates};
use errors::*;

lazy_static! {
    static ref STATIC_ROOT: PathBuf = {
        let mut root = env::current_dir().expect("Failed to get the current directory");
        root.push("static/badges");
        root
    };
    static ref CACHE_LIFESPAN: chrono::Duration = chrono::Duration::seconds(43200);  // 43200s == 12hrs
    static ref CLEAN_INTERVAL: std_time::Duration = std_time::Duration::new(3600, 0);
    static ref SVG: mime::Mime = "image/svg+xml".parse().expect("failed parsing svg mimetype");
    static ref PNG: mime::Mime = "image/png".parse().expect("failed parsing png mimetype");
    static ref JPG: mime::Mime = "image/jpg".parse().expect("failed parsing jpg mimetype");
    static ref JSON: mime::Mime = "application/json".parse().expect("failed parsing json mimetype");
}

/// Helper for pulling out persistent template engine
macro_rules! get_templates {
    ($request:expr) => {
        {
            let arc = $request.get::<persistent::Read<Templates>>()
                .expect("failed to extract persistent template engine");
            arc.clone()
        }
    }
}

/// Badge type represents a `crate` badge or a generic customizable `label` badge
enum Badge {
    Crate,
    Label,
}
impl fmt::Display for Badge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Badge::*;
        match *self {
            Crate => write!(f, "crate"),
            Label => write!(f, "label"),
        }
    }
}

/// `Url::parse_with_params` expects `&[(k, v), ...]`
type UrlParams = Vec<(String, String)>;

/// Cleans up the cache, deleting any expired files.
///
/// Errors:
///     * Unable to acquire mutex lock
fn wait_and_clear(wait_dur: &std_time::Duration, cache: &Cache) -> Result<usize> {
    thread::sleep(*wait_dur);
    let n_removed = {
        let mut cache = cache.lock().map_err(|e| Error::Msg(format!("[Cleaner] Error obtaining cache lock: {}", e)))?;
        let stale: Vec<String> = cache.iter().fold(vec![], |mut stale, (key, record)| {
            if let Some(ref record) = *record {
                // collect stale keys & delete files
                if UTC::now().signed_duration_since(record.last_refresh) > *CACHE_LIFESPAN {
                    stale.push(key.clone());
                    // ignore failed deletions, file may be missing, any skipped files will
                    // be cleaned up by the occasional cron
                    let _ = fs::remove_file(record.path_buf.clone());
                }
            }
            stale
        });
        for key in &stale {
            cache.remove(key);
        }
        stale.len()
    };
    Ok(n_removed)
}

/// Initialize a cleaning thread with cache access
pub fn init_cleaner(cache: Cache) {
    thread::spawn(move ||{
        let mut wait_dur = *CLEAN_INTERVAL;
        loop {
            match wait_and_clear(&wait_dur, &cache) {
                Ok(n) => {
                    wait_dur = *CLEAN_INTERVAL;
                    println!("[Cleaner]: Cleaned and deleted {} stale records", n);
                }
                Err(e) =>  {
                    // cleaner couldn't get a mutex lock, try again in a couple seconds
                    println!("[Cleaner]: {}", e);
                    wait_dur = std_time::Duration::new(30, 0);
                }
            }
        }
    });
}

/// Returns an appropriate mime type per file extension
fn mime_from_filetype(filetype: &str) -> Result<mime::Mime> {
    Ok(match filetype {
        "svg" => SVG.clone(),
        "png" => PNG.clone(),
        "jpg" => JPG.clone(),
        "json" => JSON.clone(),
        _ => return Err(Error::Nil),
    })
}

/// Downloads a fresh badge from shields.io and saves it to `badge_path`
/// Returns the contents of the downloaded file.
///
/// Errors:
///     * Url parse errors from generating a new shields.io url with querystring
///     * Network errors from reqwest
///     * Io errors from copying badge content or writing it to file
fn fetch_badge(badge_type: &Badge, badge_path: &PathBuf, name: &str, filetype: &str, params: &UrlParams) -> Result<Vec<u8>> {
    println!("[LOG]: fetching fresh badge ({}) -> {:?}", badge_type, badge_path);
    let url = match *badge_type {
        Badge::Crate => format!("https://img.shields.io/crates/v/{}.{}", name, filetype),
        Badge::Label => format!("https://img.shields.io/badge/{}.{}", name, filetype),
    };
    let url = Url::parse_with_params(&url, params)?;

    let mut client = reqwest::Client::new()?;
    client.timeout(std_time::Duration::new(3, 0));
    let mut resp = client.get(url.as_str())
        .form(params)
        .send()?;

    if !resp.status().is_success() { return Err(Error::Msg(format!("HTTP request not successful, status: {}", resp.status()))) }

    let mut bytes = Vec::new();
    io::copy(&mut resp, &mut bytes)?;

    let mut file = fs::File::create(badge_path)?;
    file.write_all(&bytes)?;

    Ok(bytes)
}

/// Create a new `PathBuf` for the given badge parameters in the `STATIC_ROOT`
fn create_badge_path(badge_type: &Badge, badge_key: &str, filetype: &str) -> PathBuf {
    let filename = format!("{}__{}.{}", badge_type, badge_key, filetype);
    let mut badge_path = PathBuf::from(&*STATIC_ROOT);
    badge_path.push(filename);
    badge_path
}

/// Create a new key identifier from badge and url info
fn create_badge_key(name: &str, filetype: &str, params: &UrlParams) -> String {
    let mut s = String::from(name);
    s.push('_');
    s.push_str(filetype);
    params.iter().fold(s, |mut s, &(ref k, ref v)| {
        s.push('_');
        s.push_str(k);
        s.push('_');
        s.push_str(v);
        s
    })
}

/// Returns bytes of the requested badge
/// Tries to find a cached file, falls back to fetching a fresh badge from shields.io
///
/// Errors:
///     * Io/Url/Reqwest errors from `fetch_badge`
fn get_badge(cache: Cache, badge_type: &Badge, name: &str, filetype: &str, params: &UrlParams) -> Result<Vec<u8>> {
    // build key for the cache and filename
    let badge_key = create_badge_key(name, filetype, params);

    let mut cache = cache.lock().map_err(|e| Error::Msg(format!("Error acquiring mutex lock: {}", e)))?;

    let record = cache.entry(badge_key.clone()).or_insert(None);
    let mut new_record = None;
    let bytes = match *record {
        None => {
            // No cached `Record` found
            let new_badge_path = create_badge_path(badge_type, &badge_key, filetype);
            new_record = Some(Record::from_path_buf(&new_badge_path));
            fetch_badge(badge_type, &new_badge_path, name, filetype, params)
        }
        Some(ref r) => {
            // cached `Record` found
            if UTC::now().signed_duration_since(r.last_refresh) > *CACHE_LIFESPAN {
                // content is expired
                new_record = Some(Record::from_path_buf(&r.path_buf));
                fetch_badge(badge_type, &r.path_buf, name, filetype, params)
            } else {
                // content is still valid
                fs::File::open(&r.path_buf).and_then(|mut file| {
                    let mut bytes = Vec::new();
                    file.read_to_end(&mut bytes)?;
                    Ok(bytes)
                }).or_else(|_| {
                    // cached file is missing
                    new_record = Some(Record::from_path_buf(&r.path_buf));
                    fetch_badge(badge_type, &r.path_buf, name, filetype, params)
                })
            }
        }
    };
    if let Some(new_record) = new_record {
        *record = Some(new_record);
    }
    bytes
}

/// Returns the contents of a request badge defined by its `badge_type`, `name`,
/// and modifying `params`
/// If something goes wrong when loading/fetching bytes, redirects to shields.io
fn badge_or_redirect(badge_type: &Badge, name: &str, params: &UrlParams, cache: Cache) -> IronResult<Response> {
    let name = PathBuf::from(name);
    let filetype = name.extension().and_then(OsStr::to_str).unwrap_or("svg");
    let name = name.file_stem().and_then(OsStr::to_str).expect("Failed to extract filename");

    let mimetype = match mime_from_filetype(filetype) {
        Ok(m) => m,
        Err(_) => return Ok(Response::with((status::BadRequest, format!("Invalid filetype: {}. Accepted: [svg, png, jpg, json]", filetype)))),
    };
    match get_badge(cache, badge_type, name, filetype, params) {
        Err(_) => {
            // Failed to fetch a cached or fresh version, redirect to shields.io
            let url = match *badge_type {
                Badge::Crate => format!("https://img.shields.io/crates/v/{}.{}", name, filetype),
                Badge::Label => format!("https://img.shields.io/badge/{}.{}", name, filetype),
            };
            let url = Url::parse_with_params(&url, params).expect("invalid params");
            let url = iron::Url::from_generic_url(url).unwrap();
            Ok(Response::with((status::Found, modifiers::Redirect(url))))
        }
        Ok(bytes) => {
            Ok(Response::with((mimetype, status::Ok, bytes)))
        }
    }

}

#[derive(Clone)]
/// handle requests for
/// - /crate/:cratename
/// - /crates/v/:cratename
/// - /badge/:badgeinfo
pub struct BadgeHandler {
    cache: Cache,
}
impl Handler for BadgeHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let (badge_type, name) = {
            let router_params = req.extensions.get::<Router>().expect("failed to extract router params");
            if let Some(crate_name) = router_params.find("cratename") {
                (Badge::Crate, crate_name.to_string())
            } else if let Some(badge_name) = router_params.find("badgeinfo") {
                (Badge::Label, badge_name.to_string())
            } else {
                unreachable!()
            }
        };
        let params = req.get_ref::<Params>().unwrap()
            .to_strict_map::<String>().unwrap();
        let params: UrlParams = params.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();

        badge_or_redirect(&badge_type, &name, &params, self.cache.clone())
    }
}

#[derive(Clone)]
/// handle requests for
/// - /reset/crate/:cratename
/// - /reset/crates/v/:cratename
/// - /reset/badge/:badgeinfo
pub struct ResetBadgeHandler {
    cache: Cache,
}
impl Handler for ResetBadgeHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let name = {
            let router_params = req.extensions.get::<Router>().expect("failed to extract router params");
            if let Some(crate_name) = router_params.find("cratename") {
                crate_name.to_string()
            } else if let Some(badge_name) = router_params.find("badgeinfo") {
                badge_name.to_string()
            } else {
                unreachable!()
            }
        };
        let params = req.get_ref::<Params>().unwrap()
            .to_strict_map::<String>().unwrap();
        let params: UrlParams = params.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();

        let name = PathBuf::from(name);
        let filetype = name.extension().and_then(OsStr::to_str).unwrap_or("svg");
        let name = name.file_stem().and_then(OsStr::to_str).expect("Failed to extract filename");

        let badge_key = create_badge_key(&name, &filetype, &params);
        let mut cache = self.cache.lock().expect("Failed to aquire mutex lock. Just die.");
        if let Some(record) = cache.remove(&badge_key) {
            // ignore file deletion errors
            record.map(Record::delete_file);
        }
        Ok(Response::with((JSON.clone(), status::Ok, r##"{"ok": "ok", "msg": "it's reset!"}"##)))
    }
}

/// Collection of `struct`s that `impl` `iron::Handler`
pub struct Handlers {
    pub badge_handler: BadgeHandler,
    pub reset_badge_handler: ResetBadgeHandler,
}

/// Return `Handlers` initialized with `Cache` access
pub fn initialize(cache: Cache) -> Handlers {
    Handlers {
        badge_handler: BadgeHandler { cache: cache.clone() },
        reset_badge_handler: ResetBadgeHandler { cache: cache.clone() },
    }
}

/// Return rendered template response
fn render_to_req(req: &mut Request, template_name: &str, context: Context) -> IronResult<Response> {
    let tera = get_templates!(req);
    let content = tera.render(template_name, &context).expect("Template render failed. Oh well.");
    Ok(Response::with((mime!(Text/Html), status::Ok, content)))
}

/// Handle requests for "/reset" cache reset page
pub fn reset_page(req: &mut Request) -> IronResult<Response> {
    let c = Context::new();
    render_to_req(req, "reset.html", c)
}

/// Handle requests for "/" landing page
pub fn landing(req: &mut Request) -> IronResult<Response> {
    let c = Context::new();
    render_to_req(req, "landing.html", c)
}
<commit_msg>check for content-length<commit_after>//! Handlers
//!  - Endpoint handlers
//!
use std::io::{self, Read, Write};
use std::path::PathBuf;
use std::ffi::OsStr;
use std::fs;
use std::env;
use std::time as std_time;
use std::fmt;
use std::thread;

use reqwest;
use url::Url;
use iron::prelude::*;
use iron::{self, status, modifiers, Handler};
use persistent;
use router::Router;
use params::Params;
use mime;
use chrono::{self, UTC};
use tera::Context;

use service::{Cache, Record, Templates};
use errors::*;

lazy_static! {
    static ref STATIC_ROOT: PathBuf = {
        let mut root = env::current_dir().expect("Failed to get the current directory");
        root.push("static/badges");
        root
    };
    static ref CACHE_LIFESPAN: chrono::Duration = chrono::Duration::seconds(43200);  // 43200s == 12hrs
    static ref CLEAN_INTERVAL: std_time::Duration = std_time::Duration::new(3600, 0);
    static ref SVG: mime::Mime = "image/svg+xml".parse().expect("failed parsing svg mimetype");
    static ref PNG: mime::Mime = "image/png".parse().expect("failed parsing png mimetype");
    static ref JPG: mime::Mime = "image/jpg".parse().expect("failed parsing jpg mimetype");
    static ref JSON: mime::Mime = "application/json".parse().expect("failed parsing json mimetype");
}

/// Helper for pulling out persistent template engine
macro_rules! get_templates {
    ($request:expr) => {
        {
            let arc = $request.get::<persistent::Read<Templates>>()
                .expect("failed to extract persistent template engine");
            arc.clone()
        }
    }
}

/// Badge type represents a `crate` badge or a generic customizable `label` badge
enum Badge {
    Crate,
    Label,
}
impl fmt::Display for Badge {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Badge::*;
        match *self {
            Crate => write!(f, "crate"),
            Label => write!(f, "label"),
        }
    }
}

/// `Url::parse_with_params` expects `&[(k, v), ...]`
type UrlParams = Vec<(String, String)>;

/// Cleans up the cache, deleting any expired files.
///
/// Errors:
///     * Unable to acquire mutex lock
fn wait_and_clear(wait_dur: &std_time::Duration, cache: &Cache) -> Result<usize> {
    thread::sleep(*wait_dur);
    let n_removed = {
        let mut cache = cache.lock().map_err(|e| Error::Msg(format!("[Cleaner] Error obtaining cache lock: {}", e)))?;
        let stale: Vec<String> = cache.iter().fold(vec![], |mut stale, (key, record)| {
            if let Some(ref record) = *record {
                // collect stale keys & delete files
                if UTC::now().signed_duration_since(record.last_refresh) > *CACHE_LIFESPAN {
                    stale.push(key.clone());
                    // ignore failed deletions, file may be missing, any skipped files will
                    // be cleaned up by the occasional cron
                    let _ = fs::remove_file(record.path_buf.clone());
                }
            }
            stale
        });
        for key in &stale {
            cache.remove(key);
        }
        stale.len()
    };
    Ok(n_removed)
}

/// Initialize a cleaning thread with cache access
pub fn init_cleaner(cache: Cache) {
    thread::spawn(move ||{
        let mut wait_dur = *CLEAN_INTERVAL;
        loop {
            match wait_and_clear(&wait_dur, &cache) {
                Ok(n) => {
                    wait_dur = *CLEAN_INTERVAL;
                    println!("[Cleaner]: Cleaned and deleted {} stale records", n);
                }
                Err(e) =>  {
                    // cleaner couldn't get a mutex lock, try again in a couple seconds
                    println!("[Cleaner]: {}", e);
                    wait_dur = std_time::Duration::new(30, 0);
                }
            }
        }
    });
}

/// Returns an appropriate mime type per file extension
fn mime_from_filetype(filetype: &str) -> Result<mime::Mime> {
    Ok(match filetype {
        "svg" => SVG.clone(),
        "png" => PNG.clone(),
        "jpg" => JPG.clone(),
        "json" => JSON.clone(),
        _ => return Err(Error::Nil),
    })
}

/// Downloads a fresh badge from shields.io and saves it to `badge_path`
/// Returns the contents of the downloaded file.
///
/// Errors:
///     * Url parse errors from generating a new shields.io url with querystring
///     * Network errors from reqwest
///     * Io errors from copying badge content or writing it to file
fn fetch_badge(badge_type: &Badge, badge_path: &PathBuf, name: &str, filetype: &str, params: &UrlParams) -> Result<Vec<u8>> {
    use reqwest::header::ContentLength;

    let url = match *badge_type {
        Badge::Crate => format!("https://img.shields.io/crates/v/{}.{}", name, filetype),
        Badge::Label => format!("https://img.shields.io/badge/{}.{}", name, filetype),
    };
    let url = Url::parse_with_params(&url, params)?;

    let mut client = reqwest::Client::new()?;
    client.timeout(std_time::Duration::new(3, 0));
    let mut resp = client.get(url.as_str())
        .form(params)
        .send()?;

    if !resp.status().is_success() { return Err(Error::Msg(format!("HTTP request not successful, status: {}", resp.status()))) }
    println!("[LOG]: saving fresh badge ({}) -> {:?}", badge_type, badge_path);

    let ct_len = resp.headers().get::<ContentLength>()
        .map(|ct_len| **ct_len)
        .unwrap_or(0);

    let mut bytes = Vec::with_capacity(ct_len as usize);
    io::copy(&mut resp, &mut bytes)?;

    let mut file = fs::File::create(badge_path)?;
    file.write_all(&bytes)?;

    Ok(bytes)
}

/// Create a new `PathBuf` for the given badge parameters in the `STATIC_ROOT`
fn create_badge_path(badge_type: &Badge, badge_key: &str, filetype: &str) -> PathBuf {
    let filename = format!("{}__{}.{}", badge_type, badge_key, filetype);
    let mut badge_path = PathBuf::from(&*STATIC_ROOT);
    badge_path.push(filename);
    badge_path
}

/// Create a new key identifier from badge and url info
fn create_badge_key(name: &str, filetype: &str, params: &UrlParams) -> String {
    let mut s = String::from(name);
    s.push('_');
    s.push_str(filetype);
    params.iter().fold(s, |mut s, &(ref k, ref v)| {
        s.push('_');
        s.push_str(k);
        s.push('_');
        s.push_str(v);
        s
    })
}

/// Returns bytes of the requested badge
/// Tries to find a cached file, falls back to fetching a fresh badge from shields.io
///
/// Errors:
///     * Io/Url/Reqwest errors from `fetch_badge`
fn get_badge(cache: Cache, badge_type: &Badge, name: &str, filetype: &str, params: &UrlParams) -> Result<Vec<u8>> {
    // build key for the cache and filename
    let badge_key = create_badge_key(name, filetype, params);

    let mut cache = cache.lock().map_err(|e| Error::Msg(format!("Error acquiring mutex lock: {}", e)))?;

    let record = cache.entry(badge_key.clone()).or_insert(None);
    let mut new_record = None;
    let bytes = match *record {
        None => {
            // No cached `Record` found
            let new_badge_path = create_badge_path(badge_type, &badge_key, filetype);
            new_record = Some(Record::from_path_buf(&new_badge_path));
            fetch_badge(badge_type, &new_badge_path, name, filetype, params)
        }
        Some(ref r) => {
            // cached `Record` found
            if UTC::now().signed_duration_since(r.last_refresh) > *CACHE_LIFESPAN {
                // content is expired
                new_record = Some(Record::from_path_buf(&r.path_buf));
                fetch_badge(badge_type, &r.path_buf, name, filetype, params)
            } else {
                // content is still valid
                fs::File::open(&r.path_buf).and_then(|mut file| {
                    let mut bytes = Vec::new();
                    file.read_to_end(&mut bytes)?;
                    Ok(bytes)
                }).or_else(|_| {
                    // cached file is missing
                    new_record = Some(Record::from_path_buf(&r.path_buf));
                    fetch_badge(badge_type, &r.path_buf, name, filetype, params)
                })
            }
        }
    };
    if let Some(new_record) = new_record {
        *record = Some(new_record);
    }
    bytes
}

/// Returns the contents of a request badge defined by its `badge_type`, `name`,
/// and modifying `params`
/// If something goes wrong when loading/fetching bytes, redirects to shields.io
fn badge_or_redirect(badge_type: &Badge, name: &str, params: &UrlParams, cache: Cache) -> IronResult<Response> {
    let name = PathBuf::from(name);
    let filetype = name.extension().and_then(OsStr::to_str).unwrap_or("svg");
    let name = name.file_stem().and_then(OsStr::to_str).expect("Failed to extract filename");

    let mimetype = match mime_from_filetype(filetype) {
        Ok(m) => m,
        Err(_) => return Ok(Response::with((status::BadRequest, format!("Invalid filetype: {}. Accepted: [svg, png, jpg, json]", filetype)))),
    };
    match get_badge(cache, badge_type, name, filetype, params) {
        Err(_) => {
            // Failed to fetch a cached or fresh version, redirect to shields.io
            let url = match *badge_type {
                Badge::Crate => format!("https://img.shields.io/crates/v/{}.{}", name, filetype),
                Badge::Label => format!("https://img.shields.io/badge/{}.{}", name, filetype),
            };
            let url = Url::parse_with_params(&url, params).expect("invalid params");
            let url = iron::Url::from_generic_url(url).unwrap();
            Ok(Response::with((status::Found, modifiers::Redirect(url))))
        }
        Ok(bytes) => {
            Ok(Response::with((mimetype, status::Ok, bytes)))
        }
    }

}

#[derive(Clone)]
/// handle requests for
/// - /crate/:cratename
/// - /crates/v/:cratename
/// - /badge/:badgeinfo
pub struct BadgeHandler {
    cache: Cache,
}
impl Handler for BadgeHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let (badge_type, name) = {
            let router_params = req.extensions.get::<Router>().expect("failed to extract router params");
            if let Some(crate_name) = router_params.find("cratename") {
                (Badge::Crate, crate_name.to_string())
            } else if let Some(badge_name) = router_params.find("badgeinfo") {
                (Badge::Label, badge_name.to_string())
            } else {
                unreachable!()
            }
        };
        let params = req.get_ref::<Params>().unwrap()
            .to_strict_map::<String>().unwrap();
        let params: UrlParams = params.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();

        badge_or_redirect(&badge_type, &name, &params, self.cache.clone())
    }
}

#[derive(Clone)]
/// handle requests for
/// - /reset/crate/:cratename
/// - /reset/crates/v/:cratename
/// - /reset/badge/:badgeinfo
pub struct ResetBadgeHandler {
    cache: Cache,
}
impl Handler for ResetBadgeHandler {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let name = {
            let router_params = req.extensions.get::<Router>().expect("failed to extract router params");
            if let Some(crate_name) = router_params.find("cratename") {
                crate_name.to_string()
            } else if let Some(badge_name) = router_params.find("badgeinfo") {
                badge_name.to_string()
            } else {
                unreachable!()
            }
        };
        let params = req.get_ref::<Params>().unwrap()
            .to_strict_map::<String>().unwrap();
        let params: UrlParams = params.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();

        let name = PathBuf::from(name);
        let filetype = name.extension().and_then(OsStr::to_str).unwrap_or("svg");
        let name = name.file_stem().and_then(OsStr::to_str).expect("Failed to extract filename");

        let badge_key = create_badge_key(&name, &filetype, &params);
        let mut cache = self.cache.lock().expect("Failed to aquire mutex lock. Just die.");
        if let Some(record) = cache.remove(&badge_key) {
            // ignore file deletion errors
            record.map(Record::delete_file);
        }
        Ok(Response::with((JSON.clone(), status::Ok, r##"{"ok": "ok", "msg": "it's reset!"}"##)))
    }
}

/// Collection of `struct`s that `impl` `iron::Handler`
pub struct Handlers {
    pub badge_handler: BadgeHandler,
    pub reset_badge_handler: ResetBadgeHandler,
}

/// Return `Handlers` initialized with `Cache` access
pub fn initialize(cache: Cache) -> Handlers {
    Handlers {
        badge_handler: BadgeHandler { cache: cache.clone() },
        reset_badge_handler: ResetBadgeHandler { cache: cache.clone() },
    }
}

/// Return rendered template response
fn render_to_req(req: &mut Request, template_name: &str, context: Context) -> IronResult<Response> {
    let tera = get_templates!(req);
    let content = tera.render(template_name, &context).expect("Template render failed. Oh well.");
    Ok(Response::with((mime!(Text/Html), status::Ok, content)))
}

/// Handle requests for "/reset" cache reset page
pub fn reset_page(req: &mut Request) -> IronResult<Response> {
    let c = Context::new();
    render_to_req(req, "reset.html", c)
}

/// Handle requests for "/" landing page
pub fn landing(req: &mut Request) -> IronResult<Response> {
    let c = Context::new();
    render_to_req(req, "landing.html", c)
}
<|endoftext|>


<commit_before>//! Nursery for slog-rs
//!
//! This crate is forever unstable, and contains things that
//! at a given moment are useful but not final.
#![warn(missing_docs)]

use slog::*;
use std::result;

/// `Drain` that switches destination of error
///
/// Logs everything to drain `D1`, but in case of it reporting an error,
/// switching to `D2`. If `D2` returns an error too, `Failover` will return
/// an error.
pub struct Failover<D1: Drain, D2: Drain>
{
    drain1: D1,
    drain2: D2,
}

impl<D1: Drain, D2: Drain, O> Failover<D1, D2>
    where
    D1 : Drain<Ok = O>,
    D2 : Drain<Ok = O>,
{
    /// Create `Failover`
    pub fn new(drain1: D1, drain2: D2) -> Self {
        Failover {
            drain1: drain1,
            drain2: drain2,
        }
    }
}

impl<D1, D2, E2, O> Drain for Failover<D1, D2>
    where
    D1 : Drain<Ok = O>,
    D2 : Drain<Ok = O>,
{
    type Ok = O;
    type Err = D2::Err;
    fn log(&self,
           info: &Record,
           logger_values: &OwnedKVList)
           -> result::Result<Self::Ok, Self::Err> {
        match self.drain1.log(info, logger_values) {
            Ok(ok) => Ok(ok),
            Err(_) => self.drain2.log(info, logger_values),
        }
    }
}

/// Failover logging to secondary drain on primary's failure
///
/// Create `Failover` drain
pub fn failover<D1: Drain, D2: Drain, O>(d1: D1, d2: D2) -> Failover<D1, D2>
    where
    D1 : Drain<Ok = O>,
    D2 : Drain<Ok = O>,
{
    Failover::new(d1, d2)
}
<commit_msg>Rust 2018 update for nursery<commit_after>//! Nursery for slog-rs
//!
//! This crate is forever unstable, and contains things that
//! at a given moment are useful but not final.
#![warn(missing_docs, rust_2018_idioms)]

use slog::*;
use std::result;

/// `Drain` that switches destination of error
///
/// Logs everything to drain `D1`, but in case of it reporting an error,
/// switching to `D2`. If `D2` returns an error too, `Failover` will return
/// an error.
pub struct Failover<D1: Drain, D2: Drain> {
    drain1: D1,
    drain2: D2,
}

impl<D1: Drain, D2: Drain, O> Failover<D1, D2>
where
    D1: Drain<Ok = O>,
    D2: Drain<Ok = O>,
{
    /// Create `Failover`
    pub fn new(drain1: D1, drain2: D2) -> Self {
        Failover {
            drain1: drain1,
            drain2: drain2,
        }
    }
}

impl<D1, D2, E2, O> Drain for Failover<D1, D2>
where
    D1: Drain<Ok = O>,
    D2: Drain<Ok = O>,
{
    type Ok = O;
    type Err = D2::Err;
    fn log(
        &self,
        info: &Record,
        logger_values: &OwnedKVList,
    ) -> result::Result<Self::Ok, Self::Err> {
        match self.drain1.log(info, logger_values) {
            Ok(ok) => Ok(ok),
            Err(_) => self.drain2.log(info, logger_values),
        }
    }
}

/// Failover logging to secondary drain on primary's failure
///
/// Create `Failover` drain
pub fn failover<D1: Drain, D2: Drain, O>(d1: D1, d2: D2) -> Failover<D1, D2>
where
    D1: Drain<Ok = O>,
    D2: Drain<Ok = O>,
{
    Failover::new(d1, d2)
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use std::marker;
use std::fmt::Debug;
use std::marker::PhantomData;
use snapshot_vec as sv;

#[cfg(test)]
mod test;

/// This trait is implemented by any type that can serve as a type
/// variable. We call such variables *unification keys*. For example,
/// this trait is implemented by `IntVid`, which represents integral
/// variables.
///
/// Each key type has an associated value type `V`. For example, for
/// `IntVid`, this is `Option<IntVarValue>`, representing some
/// (possibly not yet known) sort of integer.
///
/// Clients are expected to provide implementations of this trait; you
/// can see some examples in the `test` module.
pub trait UnifyKey : Copy + Clone + Debug + PartialEq {
    type Value: Clone + PartialEq + Debug;

    fn index(&self) -> u32;

    fn from_index(u: u32) -> Self;

    fn tag(k: Option<Self>) -> &'static str;
}

/// Value of a unification key. We implement Tarjan's union-find
/// algorithm: when two keys are unified, one of them is converted
/// into a "redirect" pointing at the other. These redirects form a
/// DAG: the roots of the DAG (nodes that are not redirected) are each
/// associated with a value of type `V` and a rank. The rank is used
/// to keep the DAG relatively balanced, which helps keep the running
/// time of the algorithm under control. For more information, see
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
#[derive(PartialEq,Clone,Debug)]
pub struct VarValue<K:UnifyKey> {
    parent: K,       // if equal to self, this is a root
    value: K::Value, // value assigned (only relevant to root)
    rank: u32,       // max depth (only relevant to root)
}

/// Table of unification keys and their values.
pub struct UnificationTable<K:UnifyKey> {
    /// Indicates the current value of each key.
    values: sv::SnapshotVec<Delegate<K>>,
}

/// At any time, users may snapshot a unification table.  The changes
/// made during the snapshot may either be *committed* or *rolled back*.
pub struct Snapshot<K:UnifyKey> {
    // Link snapshot to the key type `K` of the table.
    marker: marker::PhantomData<K>,
    snapshot: sv::Snapshot,
}

#[derive(Copy, Clone)]
struct Delegate<K>(PhantomData<K>);

impl<K:UnifyKey> VarValue<K> {
    fn new_var(key: K, value: K::Value) -> VarValue<K> {
        VarValue::new(key, value, 0)
    }

    fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> {
        VarValue { parent: parent, // this is a root
                   value: value,
                   rank: rank }
    }

    fn redirect(self, to: K) -> VarValue<K> {
        VarValue { parent: to, ..self }
    }

    fn root(self, rank: u32, value: K::Value) -> VarValue<K> {
        VarValue { rank: rank, value: value, ..self }
    }

    /// Returns the key of this node. Only valid if this is a root
    /// node, which you yourself must ensure.
    fn key(&self) -> K {
        self.parent
    }

    fn parent(&self, self_key: K) -> Option<K> {
        self.if_not_self(self.parent, self_key)
    }

    fn if_not_self(&self, key: K, self_key: K) -> Option<K> {
        if key == self_key {
            None
        } else {
            Some(key)
        }
    }
}

// We can't use V:LatticeValue, much as I would like to,
// because frequently the pattern is that V=Option<U> for some
// other type parameter U, and we have no way to say
// Option<U>:LatticeValue.

impl<K:UnifyKey> UnificationTable<K> {
    pub fn new() -> UnificationTable<K> {
        UnificationTable {
            values: sv::SnapshotVec::new()
        }
    }

    /// Starts a new snapshot. Each snapshot must be either
    /// rolled back or committed in a "LIFO" (stack) order.
    pub fn snapshot(&mut self) -> Snapshot<K> {
        Snapshot { marker: marker::PhantomData::<K>,
                   snapshot: self.values.start_snapshot() }
    }

    /// Reverses all changes since the last snapshot. Also
    /// removes any keys that have been created since then.
    pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
        debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
        self.values.rollback_to(snapshot.snapshot);
    }

    /// Commits all changes since the last snapshot. Of course, they
    /// can still be undone if there is a snapshot further out.
    pub fn commit(&mut self, snapshot: Snapshot<K>) {
        debug!("{}: commit()", UnifyKey::tag(None::<K>));
        self.values.commit(snapshot.snapshot);
    }

    pub fn new_key(&mut self, value: K::Value) -> K {
        let len = self.values.len();
        let key: K = UnifyKey::from_index(len as u32);
        self.values.push(VarValue::new_var(key, value));
        debug!("{}: created new key: {:?}",
               UnifyKey::tag(None::<K>),
               key);
        key
    }

    /// Find the root node for `vid`. This uses the standard
    /// union-find algorithm with path compression:
    /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
    ///
    /// NB. This is a building-block operation and you would probably
    /// prefer to call `probe` below.
    fn get(&mut self, vid: K) -> VarValue<K> {
        let index = vid.index() as usize;
        let mut value: VarValue<K> = self.values.get(index).clone();
        match value.parent(vid) {
            Some(redirect) => {
                let root: VarValue<K> = self.get(redirect);
                if root.key() != redirect {
                    // Path compression
                    value.parent = root.key();
                    self.values.set(index, value);
                }
                root
            }
            None => {
                value
            }
        }
    }

    fn is_root(&self, key: K) -> bool {
        let index = key.index() as usize;
        self.values.get(index).parent(key).is_none()
    }

    /// Sets the value for `vid` to `new_value`. `vid` MUST be a root
    /// node! This is an internal operation used to impl other things.
    fn set(&mut self, key: K, new_value: VarValue<K>) {
        assert!(self.is_root(key));

        debug!("Updating variable {:?} to {:?}",
               key, new_value);

        let index = key.index() as usize;
        self.values.set(index, new_value);
    }

    /// Either redirects `node_a` to `node_b` or vice versa, depending
    /// on the relative rank. The value associated with the new root
    /// will be `new_value`.
    ///
    /// NB: This is the "union" operation of "union-find". It is
    /// really more of a building block. If the values associated with
    /// your key are non-trivial, you would probably prefer to call
    /// `unify_var_var` below.
    fn unify(&mut self, root_a: VarValue<K>, root_b: VarValue<K>, new_value: K::Value) {
        debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))",
               root_a.key(),
               root_a.rank,
               root_b.key(),
               root_b.rank);

        if root_a.rank > root_b.rank {
            // a has greater rank, so a should become b's parent,
            // i.e., b should redirect to a.
            self.redirect_root(root_a.rank, root_b, root_a, new_value);
        } else if root_a.rank < root_b.rank {
            // b has greater rank, so a should redirect to b.
            self.redirect_root(root_b.rank, root_a, root_b, new_value);
        } else {
            // If equal, redirect one to the other and increment the
            // other's rank.
            self.redirect_root(root_a.rank + 1, root_a, root_b, new_value);
        }
    }

    fn redirect_root(&mut self,
                     new_rank: u32,
                     old_root: VarValue<K>,
                     new_root: VarValue<K>,
                     new_value: K::Value) {
        let old_root_key = old_root.key();
        let new_root_key = new_root.key();
        self.set(old_root_key, old_root.redirect(new_root_key));
        self.set(new_root_key, new_root.root(new_rank, new_value));
    }
}

impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
    type Value = VarValue<K>;
    type Undo = ();

    fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {}
}

///////////////////////////////////////////////////////////////////////////
// Base union-find algorithm, where we are just making setes

impl<'tcx,K> UnificationTable<K>
    where K : UnifyKey<Value=()>,
{
    pub fn union(&mut self, a_id: K, b_id: K) {
        let node_a = self.get(a_id);
        let node_b = self.get(b_id);
        let a_id = node_a.key();
        let b_id = node_b.key();
        if a_id != b_id {
            self.unify(node_a, node_b, ());
        }
    }

    pub fn find(&mut self, id: K) -> K {
        self.get(id).key()
    }

    pub fn unioned(&mut self, a_id: K, b_id: K) -> bool {
        self.find(a_id) == self.find(b_id)
    }
}

///////////////////////////////////////////////////////////////////////////
// Code to handle keys which carry a value, like ints,
// floats---anything that doesn't have a subtyping relationship we
// need to worry about.

impl<'tcx,K,V> UnificationTable<K>
    where K: UnifyKey<Value=Option<V>>,
          V: Clone+PartialEq,
{
    pub fn unify_var_var(&mut self,
                         a_id: K,
                         b_id: K)
                         -> Result<(),(V,V)>
    {
        let node_a = self.get(a_id);
        let node_b = self.get(b_id);
        let a_id = node_a.key();
        let b_id = node_b.key();

        if a_id == b_id { return Ok(()); }

        let combined = {
            match (&node_a.value, &node_b.value) {
                (&None, &None) => {
                    None
                }
                (&Some(ref v), &None) | (&None, &Some(ref v)) => {
                    Some(v.clone())
                }
                (&Some(ref v1), &Some(ref v2)) => {
                    if *v1 != *v2 {
                        return Err((v1.clone(), v2.clone()));
                    }
                    Some(v1.clone())
                }
            }
        };

        Ok(self.unify(node_a, node_b, combined))
    }

    /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
    /// relationships, if `a_id` already has a value, it must be the same as `b`.
    pub fn unify_var_value(&mut self,
                           a_id: K,
                           b: V)
                           -> Result<(),(V,V)>
    {
        let mut node_a = self.get(a_id);

        match node_a.value {
            None => {
                node_a.value = Some(b);
                self.set(node_a.key(), node_a);
                Ok(())
            }

            Some(ref a_t) => {
                if *a_t == b {
                    Ok(())
                } else {
                    Err((a_t.clone(), b))
                }
            }
        }
    }

    pub fn has_value(&mut self, id: K) -> bool {
        self.get(id).value.is_some()
    }

    pub fn probe(&mut self, a_id: K) -> Option<V> {
        self.get(a_id).value.clone()
    }
}

<commit_msg>Address nits<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use std::marker;
use std::fmt::Debug;
use std::marker::PhantomData;
use snapshot_vec as sv;

#[cfg(test)]
mod test;

/// This trait is implemented by any type that can serve as a type
/// variable. We call such variables *unification keys*. For example,
/// this trait is implemented by `IntVid`, which represents integral
/// variables.
///
/// Each key type has an associated value type `V`. For example, for
/// `IntVid`, this is `Option<IntVarValue>`, representing some
/// (possibly not yet known) sort of integer.
///
/// Clients are expected to provide implementations of this trait; you
/// can see some examples in the `test` module.
pub trait UnifyKey : Copy + Clone + Debug + PartialEq {
    type Value: Clone + PartialEq + Debug;

    fn index(&self) -> u32;

    fn from_index(u: u32) -> Self;

    fn tag(k: Option<Self>) -> &'static str;
}

/// Value of a unification key. We implement Tarjan's union-find
/// algorithm: when two keys are unified, one of them is converted
/// into a "redirect" pointing at the other. These redirects form a
/// DAG: the roots of the DAG (nodes that are not redirected) are each
/// associated with a value of type `V` and a rank. The rank is used
/// to keep the DAG relatively balanced, which helps keep the running
/// time of the algorithm under control. For more information, see
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
#[derive(PartialEq,Clone,Debug)]
pub struct VarValue<K:UnifyKey> {
    parent: K,       // if equal to self, this is a root
    value: K::Value, // value assigned (only relevant to root)
    rank: u32,       // max depth (only relevant to root)
}

/// Table of unification keys and their values.
pub struct UnificationTable<K:UnifyKey> {
    /// Indicates the current value of each key.
    values: sv::SnapshotVec<Delegate<K>>,
}

/// At any time, users may snapshot a unification table.  The changes
/// made during the snapshot may either be *committed* or *rolled back*.
pub struct Snapshot<K:UnifyKey> {
    // Link snapshot to the key type `K` of the table.
    marker: marker::PhantomData<K>,
    snapshot: sv::Snapshot,
}

#[derive(Copy, Clone)]
struct Delegate<K>(PhantomData<K>);

impl<K:UnifyKey> VarValue<K> {
    fn new_var(key: K, value: K::Value) -> VarValue<K> {
        VarValue::new(key, value, 0)
    }

    fn new(parent: K, value: K::Value, rank: u32) -> VarValue<K> {
        VarValue { parent: parent, // this is a root
                   value: value,
                   rank: rank }
    }

    fn redirect(self, to: K) -> VarValue<K> {
        VarValue { parent: to, ..self }
    }

    fn root(self, rank: u32, value: K::Value) -> VarValue<K> {
        VarValue { rank: rank, value: value, ..self }
    }

    /// Returns the key of this node. Only valid if this is a root
    /// node, which you yourself must ensure.
    fn key(&self) -> K {
        self.parent
    }

    fn parent(&self, self_key: K) -> Option<K> {
        self.if_not_self(self.parent, self_key)
    }

    fn if_not_self(&self, key: K, self_key: K) -> Option<K> {
        if key == self_key {
            None
        } else {
            Some(key)
        }
    }
}

// We can't use V:LatticeValue, much as I would like to,
// because frequently the pattern is that V=Option<U> for some
// other type parameter U, and we have no way to say
// Option<U>:LatticeValue.

impl<K:UnifyKey> UnificationTable<K> {
    pub fn new() -> UnificationTable<K> {
        UnificationTable {
            values: sv::SnapshotVec::new()
        }
    }

    /// Starts a new snapshot. Each snapshot must be either
    /// rolled back or committed in a "LIFO" (stack) order.
    pub fn snapshot(&mut self) -> Snapshot<K> {
        Snapshot { marker: marker::PhantomData::<K>,
                   snapshot: self.values.start_snapshot() }
    }

    /// Reverses all changes since the last snapshot. Also
    /// removes any keys that have been created since then.
    pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
        debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
        self.values.rollback_to(snapshot.snapshot);
    }

    /// Commits all changes since the last snapshot. Of course, they
    /// can still be undone if there is a snapshot further out.
    pub fn commit(&mut self, snapshot: Snapshot<K>) {
        debug!("{}: commit()", UnifyKey::tag(None::<K>));
        self.values.commit(snapshot.snapshot);
    }

    pub fn new_key(&mut self, value: K::Value) -> K {
        let len = self.values.len();
        let key: K = UnifyKey::from_index(len as u32);
        self.values.push(VarValue::new_var(key, value));
        debug!("{}: created new key: {:?}",
               UnifyKey::tag(None::<K>),
               key);
        key
    }

    /// Find the root node for `vid`. This uses the standard
    /// union-find algorithm with path compression:
    /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
    ///
    /// NB. This is a building-block operation and you would probably
    /// prefer to call `probe` below.
    fn get(&mut self, vid: K) -> VarValue<K> {
        let index = vid.index() as usize;
        let mut value: VarValue<K> = self.values.get(index).clone();
        match value.parent(vid) {
            Some(redirect) => {
                let root: VarValue<K> = self.get(redirect);
                if root.key() != redirect {
                    // Path compression
                    value.parent = root.key();
                    self.values.set(index, value);
                }
                root
            }
            None => {
                value
            }
        }
    }

    fn is_root(&self, key: K) -> bool {
        let index = key.index() as usize;
        self.values.get(index).parent(key).is_none()
    }

    /// Sets the value for `vid` to `new_value`. `vid` MUST be a root
    /// node! This is an internal operation used to impl other things.
    fn set(&mut self, key: K, new_value: VarValue<K>) {
        assert!(self.is_root(key));

        debug!("Updating variable {:?} to {:?}",
               key, new_value);

        let index = key.index() as usize;
        self.values.set(index, new_value);
    }

    /// Either redirects `node_a` to `node_b` or vice versa, depending
    /// on the relative rank. The value associated with the new root
    /// will be `new_value`.
    ///
    /// NB: This is the "union" operation of "union-find". It is
    /// really more of a building block. If the values associated with
    /// your key are non-trivial, you would probably prefer to call
    /// `unify_var_var` below.
    fn unify(&mut self, root_a: VarValue<K>, root_b: VarValue<K>, new_value: K::Value) {
        debug!("unify(root_a(id={:?}, rank={:?}), root_b(id={:?}, rank={:?}))",
               root_a.key(),
               root_a.rank,
               root_b.key(),
               root_b.rank);

        if root_a.rank > root_b.rank {
            // a has greater rank, so a should become b's parent,
            // i.e., b should redirect to a.
            self.redirect_root(root_a.rank, root_b, root_a, new_value);
        } else if root_a.rank < root_b.rank {
            // b has greater rank, so a should redirect to b.
            self.redirect_root(root_b.rank, root_a, root_b, new_value);
        } else {
            // If equal, redirect one to the other and increment the
            // other's rank.
            self.redirect_root(root_a.rank + 1, root_a, root_b, new_value);
        }
    }

    fn redirect_root(&mut self,
                     new_rank: u32,
                     old_root: VarValue<K>,
                     new_root: VarValue<K>,
                     new_value: K::Value) {
        let old_root_key = old_root.key();
        let new_root_key = new_root.key();
        self.set(old_root_key, old_root.redirect(new_root_key));
        self.set(new_root_key, new_root.root(new_rank, new_value));
    }
}

impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
    type Value = VarValue<K>;
    type Undo = ();

    fn reverse(_: &mut Vec<VarValue<K>>, _: ()) {}
}

///////////////////////////////////////////////////////////////////////////
// Base union-find algorithm, where we are just making sets

impl<'tcx,K> UnificationTable<K>
    where K : UnifyKey<Value=()>,
{
    pub fn union(&mut self, a_id: K, b_id: K) {
        let node_a = self.get(a_id);
        let node_b = self.get(b_id);
        let a_id = node_a.key();
        let b_id = node_b.key();
        if a_id != b_id {
            self.unify(node_a, node_b, ());
        }
    }

    pub fn find(&mut self, id: K) -> K {
        self.get(id).key()
    }

    pub fn unioned(&mut self, a_id: K, b_id: K) -> bool {
        self.find(a_id) == self.find(b_id)
    }
}

///////////////////////////////////////////////////////////////////////////
// Code to handle keys which carry a value, like ints,
// floats---anything that doesn't have a subtyping relationship we
// need to worry about.

impl<'tcx,K,V> UnificationTable<K>
    where K: UnifyKey<Value=Option<V>>,
          V: Clone+PartialEq,
{
    pub fn unify_var_var(&mut self,
                         a_id: K,
                         b_id: K)
                         -> Result<(),(V,V)>
    {
        let node_a = self.get(a_id);
        let node_b = self.get(b_id);
        let a_id = node_a.key();
        let b_id = node_b.key();

        if a_id == b_id { return Ok(()); }

        let combined = {
            match (&node_a.value, &node_b.value) {
                (&None, &None) => {
                    None
                }
                (&Some(ref v), &None) | (&None, &Some(ref v)) => {
                    Some(v.clone())
                }
                (&Some(ref v1), &Some(ref v2)) => {
                    if *v1 != *v2 {
                        return Err((v1.clone(), v2.clone()));
                    }
                    Some(v1.clone())
                }
            }
        };

        Ok(self.unify(node_a, node_b, combined))
    }

    /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping
    /// relationships, if `a_id` already has a value, it must be the same as `b`.
    pub fn unify_var_value(&mut self,
                           a_id: K,
                           b: V)
                           -> Result<(),(V,V)>
    {
        let mut node_a = self.get(a_id);

        match node_a.value {
            None => {
                node_a.value = Some(b);
                self.set(node_a.key(), node_a);
                Ok(())
            }

            Some(ref a_t) => {
                if *a_t == b {
                    Ok(())
                } else {
                    Err((a_t.clone(), b))
                }
            }
        }
    }

    pub fn has_value(&mut self, id: K) -> bool {
        self.get(id).value.is_some()
    }

    pub fn probe(&mut self, a_id: K) -> Option<V> {
        self.get(a_id).value.clone()
    }
}

<|endoftext|>


<commit_before>mod raft_log;
pub mod storage;
mod raft;
mod progress;
mod errors;
mod log_unstable;
mod status;
pub mod raw_node;

pub use self::storage::{RaftState, Storage};
pub use self::errors::{Result, Error, StorageError};
pub use self::raft::{Raft, StateRole, Config, INVALID_ID, SoftState};
pub use self::raft_log::{RaftLog, NO_LIMIT};
pub use self::raw_node::{Ready, RawNode, Peer, is_empty_snap};
pub use self::status::Status;
pub use self::log_unstable::Unstable;
pub use self::progress::{Inflights, Progress, ProgressState};
<commit_msg>raft: public SnapshotStatus.<commit_after>mod raft_log;
pub mod storage;
mod raft;
mod progress;
mod errors;
mod log_unstable;
mod status;
pub mod raw_node;

pub use self::storage::{RaftState, Storage};
pub use self::errors::{Result, Error, StorageError};
pub use self::raft::{Raft, StateRole, Config, INVALID_ID, SoftState};
pub use self::raft_log::{RaftLog, NO_LIMIT};
pub use self::raw_node::{Ready, RawNode, Peer, is_empty_snap, SnapshotStatus};
pub use self::status::Status;
pub use self::log_unstable::Unstable;
pub use self::progress::{Inflights, Progress, ProgressState};
<|endoftext|>


<commit_before>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;
use chunks::ChunksEncoder;

/// Object representing an HTTP response.
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    http_version: HTTPVersion,
}

impl<R: Reader> Response<R> {
    #[experimental]
    pub fn new(status_code: StatusCode, mut headers: Vec<Header>,
               data: R, data_length: uint) -> Response<R>
    {
        // add Content-Length if not in the headers
        if headers.iter().find(|h| h.field.equiv(&"Content-Length")).is_none() {
            headers.unshift(
                Header{field: from_str("Content-Length").unwrap(), value: format!("{}", data_length)}
            );
        }

        Response {
            reader: data,
            status_code: status_code,
            headers: headers,
            http_version: HTTPVersion(1, 1),
        }
    }

    /// Returns the same request, but with an additional header.
    #[experimental]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.headers.push(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[experimental]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Forces an HTTP version.
    #[experimental]
    pub fn with_http_version(mut self, version: HTTPVersion) -> Response<R> {
        self.http_version = version;
        self
    }

    /// Cleans-up the headers so that they can be returned.
    #[experimental]
    fn purify_headers(&mut self) {
        // removing some unwanted headers, like Connection
        self.headers.retain(|h| !h.field.equiv(&"Connection"));

        // add Server if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                Header{field: from_str("Server").unwrap(), value: "tiny-http (Rust)".to_string()}
            );
        }

        // add Connection: close
        /*self.headers.push(
            Header{field: "Connection".to_string(), value: "close".to_string()}
        );*/
    }

    /// Prints the HTTP response to a writer.
    #[experimental]
    pub fn raw_print<W: Writer>(mut self, mut writer: W) -> IoResult<()> {
        self.purify_headers();

        // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
        let chunks_threshold = 32768;
        let use_chunks =
            self.http_version >= HTTPVersion(1, 1) &&
            self.headers.iter().find(|h| h.field.equiv(&"Content-Length"))
                .and_then(|h| from_str::<uint>(h.value.as_slice()))
                .filtered(|val| *val < chunks_threshold)
                .is_none();

        // add transfer-encoding header
        if use_chunks {
            self.headers.push(
                Header{field: from_str("Transfer-Encoding").unwrap(), value: "chunked".to_string()}
            )
        }

        // writing status line
        try!(write!(writer, "HTTP/{} {} {}\r\n",
            self.http_version,
            self.status_code.as_uint(),
            self.status_code.get_default_reason_phrase()
        ));

        // writing headers
        for header in self.headers.iter() {
            try!(write!(writer, "{}: {}\r\n", header.field, header.value));
        }

        // separator between header and data
        try!(write!(writer, "\r\n"));

        // writing data
        if use_chunks {
            let mut writer = ChunksEncoder::new(writer);
            try!(util::copy(&mut self.reader, &mut writer));
        } else {
            try!(util::copy(&mut self.reader, &mut writer));
        }

        Ok(())
    }
}

impl Response<File> {
    #[experimental]
    pub fn from_file(file: &Path) -> IoResult<Response<File>> {
        let mut file = try!(File::open(file));
        let stats = try!(file.stat());

        Ok(Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            stats.size as uint
        ))
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            data_len
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            data_len
        )
    }
}

impl Response<NullReader> {
    #[experimental]
    pub fn empty() -> Response<NullReader> {
        Response::new(
            StatusCode(204),
            Vec::new(),
            NullReader,
            0
        )
    }

    #[experimental]
    pub fn not_modified() -> Response<NullReader> {
        Response::new(
            StatusCode(304),
            Vec::new(),
            NullReader,
            0
        )
    }
}
<commit_msg>Response data length is now optional<commit_after>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;
use chunks::ChunksEncoder;

/// Object representing an HTTP response.
#[experimental]
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    http_version: HTTPVersion,
}

impl<R: Reader> Response<R> {
    #[experimental]
    pub fn new(status_code: StatusCode, mut headers: Vec<Header>,
               data: R, data_length: Option<uint>) -> Response<R>
    {
        // add Content-Length if not in the headers
        if data_length.is_some() {
            if headers.iter().find(|h| h.field.equiv(&"Content-Length")).is_none() {
                headers.unshift(
                    Header{
                        field: from_str("Content-Length").unwrap(),
                        value: format!("{}", data_length.unwrap())
                    }
                );
            }
        }

        Response {
            reader: data,
            status_code: status_code,
            headers: headers,
            http_version: HTTPVersion(1, 1),
        }
    }

    /// Returns the same request, but with an additional header.
    #[experimental]
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.headers.push(header);
        self
    }

    /// Returns the same request, but with a different status code.
    #[experimental]
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Forces an HTTP version.
    #[experimental]
    pub fn with_http_version(mut self, version: HTTPVersion) -> Response<R> {
        self.http_version = version;
        self
    }

    /// Cleans-up the headers so that they can be returned.
    #[experimental]
    fn purify_headers(&mut self) {
        // removing some unwanted headers, like Connection
        self.headers.retain(|h| !h.field.equiv(&"Connection"));

        // add Server if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                Header{field: from_str("Server").unwrap(), value: "tiny-http (Rust)".to_string()}
            );
        }

        // add Connection: close
        /*self.headers.push(
            Header{field: "Connection".to_string(), value: "close".to_string()}
        );*/
    }

    /// Prints the HTTP response to a writer.
    #[experimental]
    pub fn raw_print<W: Writer>(mut self, mut writer: W) -> IoResult<()> {
        self.purify_headers();

        // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
        let chunks_threshold = 32768;
        let use_chunks =
            self.http_version >= HTTPVersion(1, 1) &&
            self.headers.iter().find(|h| h.field.equiv(&"Content-Length"))
                .and_then(|h| from_str::<uint>(h.value.as_slice()))
                .filtered(|val| *val < chunks_threshold)
                .is_none();

        // add transfer-encoding header
        if use_chunks {
            self.headers.push(
                Header{field: from_str("Transfer-Encoding").unwrap(), value: "chunked".to_string()}
            )
        }

        // writing status line
        try!(write!(writer, "HTTP/{} {} {}\r\n",
            self.http_version,
            self.status_code.as_uint(),
            self.status_code.get_default_reason_phrase()
        ));

        // writing headers
        for header in self.headers.iter() {
            try!(write!(writer, "{}: {}\r\n", header.field, header.value));
        }

        // separator between header and data
        try!(write!(writer, "\r\n"));

        // writing data
        if use_chunks {
            let mut writer = ChunksEncoder::new(writer);
            try!(util::copy(&mut self.reader, &mut writer));
        } else {
            try!(util::copy(&mut self.reader, &mut writer));
        }

        Ok(())
    }
}

impl Response<File> {
    #[experimental]
    pub fn from_file(file: &Path) -> IoResult<Response<File>> {
        let mut file = try!(File::open(file));
        let stats = try!(file.stat());

        Ok(Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            Some(stats.size as uint)
        ))
    }
}

impl Response<MemReader> {
    #[experimental]
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            Some(data_len)
        )
    }

    #[experimental]
    pub fn from_string(data: String) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            vec!(
                from_str("Content-Type: text/plain; charset=UTF-8").unwrap()
            ),
            MemReader::new(data.into_bytes()),
            Some(data_len)
        )
    }
}

impl Response<NullReader> {
    #[experimental]
    pub fn empty() -> Response<NullReader> {
        Response::new(
            StatusCode(204),
            Vec::new(),
            NullReader,
            Some(0)
        )
    }

    #[experimental]
    pub fn not_modified() -> Response<NullReader> {
        Response::new(
            StatusCode(304),
            Vec::new(),
            NullReader,
            Some(0)
        )
    }
}
<|endoftext|>


<commit_before>use serialize::{json, Decodable, Decoder};
use serialize::json::{Json, Object, List, I64, U64, F64, Boolean, String};
use document::{SolrDocument, SolrField, SolrString, SolrI64, SolrU64, SolrF64, SolrBoolean, SolrNull};

pub type SolrUpdateResult = Result<SolrUpdateResponse, SolrError>;
pub type SolrQueryResult = Result<SolrQueryResponse, SolrError>;

/// SolrError
pub struct SolrError {
    /// HTTP status.
    /// When failed to connect, it will be 0 (zero).
    pub status: int,
    /// Time it took to execute the request in milliseconds
    pub time: int,
    /// Detailed error message
    pub message: String
}

impl<D: Decoder<E>, E> Decodable<D, E> for SolrError {
    fn decode(d: &mut D) -> Result<SolrError, E> {
        d.read_struct("root", 0, |d| {
            d.read_struct_field("error", 0, |d| {
                Ok(SolrError{
                    message: try!(d.read_struct_field("msg", 0, Decodable::decode)),
                    status: try!(d.read_struct_field("code", 1, Decodable::decode)),
                    // TODO: implement time parsing from request header
                    time: 0})
            })
        })
    }
}

/// Solr response used for update/indexing/commit operations
pub struct SolrUpdateResponse {
    /// HTTP status.
    /// When failed to connect, it will be 0 (zero).
    pub status: int,
    /// Time it took to execute the request in milliseconds
    pub time: int
}

impl<D: Decoder<E>, E> Decodable<D, E> for SolrUpdateResponse {
    fn decode(d: &mut D) -> Result<SolrUpdateResponse, E> {
        d.read_struct("root", 0, |d| {
            d.read_struct_field("responseHeader", 0, |d| {
                Ok(SolrUpdateResponse{
                    status: try!(d.read_struct_field("status", 0, Decodable::decode)),
                    time: try!(d.read_struct_field("QTime", 1, Decodable::decode))
                })
            })
        })
    }
}

/// Solr query response
#[deriving(Show)]
pub struct SolrQueryResponse {
    /// HTTP status.
    /// When failed to connect, it will be 0 (zero).
    pub status: u32,
    /// Time it took to execute the request in milliseconds
    pub time: u32,
    /// Total number of rows found.
    /// Note that this will probably be different from returned subset of rows,
    /// because Solr will always use pagination
    pub total: u64,
    /// Rows offset (zero based)
    pub start: u64,
    /// Current page of found Solr documents
    pub items: Vec<SolrDocument>
}

/*
Example JSON of query response:
```ignore
{
  "responseHeader": {
    "status": 0,
    "QTime": 1
  },
  "response": {
    "numFound": 57,
    "start": 0,
    "docs": [
      {
        "id": 1,
        "_version_": "1478235317501689856"
      },
      {
        "id": 3,
        "_version_": "1478235317504835584"
      }
    ]
  }
}
*/
impl SolrQueryResponse {
    /// Deserializes SolrQueryResponse from JSON string
    pub fn from_json_str(json_str: &str) -> SolrQueryResult {
        let mut response = SolrQueryResponse{status: 0, time: 0, total: 0, start: 0, items: Vec::new()};
        let mut error: String = "".to_string();
        match json::from_str(json_str) {
            Ok(json) => match json {
               Object(tree_map) => {
                    match tree_map.find(&"responseHeader".to_string()) {
                        Some(rh) => {
                            match rh.find(&"QTime".to_string()){
                                Some(time_json) => response.time = time_json.as_i64().unwrap() as u32,
                                None => error = "SolrQueryResponse JSON parsing error (responseHeader): QTime not found".to_string()
                            }
                            match rh.find(&"status".to_string()) {
                                Some(status_json) => response.status = status_json.as_u64().unwrap() as u32,
                                None => error = "SolrQueryResponse JSON parsing error (responseHeader): status not found".to_string()
                            }
                        },
                        None => error = "SolrQueryResponse JSON parsing error: responseHeader not found".to_string()

                    }
                    match tree_map.find(&"response".to_string()) {
                        Some(rs) => {
                            match rs.find(&"numFound".to_string()){
                                Some(total_json) => response.total = total_json.as_u64().unwrap(),
                                None => error = "SolrQueryResponse JSON parsing error (response): numFound not found".to_string()
                            }
                            match rs.find(&"start".to_string()) {
                                Some(start_json) => response.start = start_json.as_u64().unwrap(),
                                None => error = "SolrQueryResponse JSON parsing error (response): start not found".to_string()
                            }
                            match rs.find(&"docs".to_string()){
                                Some(docs_json) => {
                                    match docs_json {
                                        & List(ref docs) => {
                                            for doc_json in docs.iter() {
                                                match SolrQueryResponse::parse_doc(doc_json){
                                                    Ok(doc) => response.items.push(doc),
                                                    Err(e) => error = e
                                                }

                                            }
                                        },
                                        _ =>  error = "SolrQueryResponse JSON parsing error (response): docs is not a JSON list".to_string()
                                    }
                                },
                                None => error = "SolrQueryResponse JSON parsing error (response): docs not found".to_string()
                            }
                        },
                        None => error = "SolrQueryResponse JSON parsing error: response not found".to_string()
                    }
               },
               _ => error = "SolrQueryResponse JSON parsing error: query response is not a JSON object.".to_string()
            },
            Err(e) => error = format!("SolrQueryResponse JSON parsing error: {}", e).to_string()
        }
        if error.len() == 0 {
            Ok(response)
        } else {
            Err(SolrError{time: 0, status: 0, message: error})
        }
    }

    fn parse_doc(doc_json: &Json) -> Result<SolrDocument, String> {
        match doc_json {
            & Object(ref tm) => {
                let mut doc = SolrDocument{fields: Vec::with_capacity(tm.len())};
                for (k, json_v) in tm.iter() {
                    let v = match json_v {
                        & I64(i64) => SolrI64(i64),
                        & U64(u64) => SolrU64(u64),
                        & F64(f64) => SolrF64(f64),
                        & String(ref string) => SolrString(string.clone()),
                        & Boolean(bool) => SolrBoolean(bool),
                        _ => SolrNull
                    };
                    doc.fields.push(SolrField{name: k.clone(), value: v});
                }
                Ok(doc)
            },
            _ => Err("SolrQueryResponse JSON parsing error (response => docs): doc is not an object".to_string())
        }
    }
}
<commit_msg>Update for latest Rust<commit_after>use serialize::{json, Decodable, Decoder};
use serialize::json::{Json, Object, List, I64, U64, F64, Boolean, String};
use document::{SolrDocument, SolrField, SolrString, SolrI64, SolrU64, SolrF64, SolrBoolean, SolrNull};

pub type SolrUpdateResult = Result<SolrUpdateResponse, SolrError>;
pub type SolrQueryResult = Result<SolrQueryResponse, SolrError>;

/// SolrError
pub struct SolrError {
    /// HTTP status.
    /// When failed to connect, it will be 0 (zero).
    pub status: int,
    /// Time it took to execute the request in milliseconds
    pub time: int,
    /// Detailed error message
    pub message: String
}

impl<D: Decoder<E>, E> Decodable<D, E> for SolrError {
    fn decode(d: &mut D) -> Result<SolrError, E> {
        d.read_struct("root", 0, |d| {
            d.read_struct_field("error", 0, |d| {
                Ok(SolrError{
                    message: try!(d.read_struct_field("msg", 0, Decodable::decode)),
                    status: try!(d.read_struct_field("code", 1, Decodable::decode)),
                    // TODO: implement time parsing from request header
                    time: 0})
            })
        })
    }
}

/// Solr response used for update/indexing/commit operations
pub struct SolrUpdateResponse {
    /// HTTP status.
    /// When failed to connect, it will be 0 (zero).
    pub status: int,
    /// Time it took to execute the request in milliseconds
    pub time: int
}

impl<D: Decoder<E>, E> Decodable<D, E> for SolrUpdateResponse {
    fn decode(d: &mut D) -> Result<SolrUpdateResponse, E> {
        d.read_struct("root", 0, |d| {
            d.read_struct_field("responseHeader", 0, |d| {
                Ok(SolrUpdateResponse{
                    status: try!(d.read_struct_field("status", 0, Decodable::decode)),
                    time: try!(d.read_struct_field("QTime", 1, Decodable::decode))
                })
            })
        })
    }
}

/// Solr query response
#[deriving(Show)]
pub struct SolrQueryResponse {
    /// HTTP status.
    /// When failed to connect, it will be 0 (zero).
    pub status: u32,
    /// Time it took to execute the request in milliseconds
    pub time: u32,
    /// Total number of rows found.
    /// Note that this will probably be different from returned subset of rows,
    /// because Solr will always use pagination
    pub total: u64,
    /// Rows offset (zero based)
    pub start: u64,
    /// Current page of found Solr documents
    pub items: Vec<SolrDocument>
}

/*
Example JSON of query response:
```ignore
{
  "responseHeader": {
    "status": 0,
    "QTime": 1
  },
  "response": {
    "numFound": 57,
    "start": 0,
    "docs": [
      {
        "id": 1,
        "_version_": "1478235317501689856"
      },
      {
        "id": 3,
        "_version_": "1478235317504835584"
      }
    ]
  }
}
*/
impl SolrQueryResponse {
    /// Deserializes SolrQueryResponse from JSON string
    pub fn from_json_str(json_str: &str) -> SolrQueryResult {
        let mut response = SolrQueryResponse{status: 0, time: 0, total: 0, start: 0, items: Vec::new()};
        let mut error: String = "".to_string();
        match json::from_str(json_str) {
            Ok(json) => match json {
               Object(tree_map) => {
                    match tree_map.get(&"responseHeader".to_string()) {
                        Some(rh) => {
                            match rh.find("QTime"){
                                Some(time_json) => response.time = time_json.as_i64().unwrap() as u32,
                                None => error = "SolrQueryResponse JSON parsing error (responseHeader): QTime not found".to_string()
                            }
                            match rh.find("status") {
                                Some(status_json) => response.status = status_json.as_u64().unwrap() as u32,
                                None => error = "SolrQueryResponse JSON parsing error (responseHeader): status not found".to_string()
                            }
                        },
                        None => error = "SolrQueryResponse JSON parsing error: responseHeader not found".to_string()

                    }
                    match tree_map.get(&"response".to_string()) {
                        Some(rs) => {
                            match rs.find("numFound"){
                                Some(total_json) => response.total = total_json.as_u64().unwrap(),
                                None => error = "SolrQueryResponse JSON parsing error (response): numFound not found".to_string()
                            }
                            match rs.find("start") {
                                Some(start_json) => response.start = start_json.as_u64().unwrap(),
                                None => error = "SolrQueryResponse JSON parsing error (response): start not found".to_string()
                            }
                            match rs.find("docs"){
                                Some(docs_json) => {
                                    match docs_json {
                                        & List(ref docs) => {
                                            for doc_json in docs.iter() {
                                                match SolrQueryResponse::parse_doc(doc_json){
                                                    Ok(doc) => response.items.push(doc),
                                                    Err(e) => error = e
                                                }

                                            }
                                        },
                                        _ =>  error = "SolrQueryResponse JSON parsing error (response): docs is not a JSON list".to_string()
                                    }
                                },
                                None => error = "SolrQueryResponse JSON parsing error (response): docs not found".to_string()
                            }
                        },
                        None => error = "SolrQueryResponse JSON parsing error: response not found".to_string()
                    }
               },
               _ => error = "SolrQueryResponse JSON parsing error: query response is not a JSON object.".to_string()
            },
            Err(e) => error = format!("SolrQueryResponse JSON parsing error: {}", e).to_string()
        }
        if error.len() == 0 {
            Ok(response)
        } else {
            Err(SolrError{time: 0, status: 0, message: error})
        }
    }

    fn parse_doc(doc_json: &Json) -> Result<SolrDocument, String> {
        match doc_json {
            & Object(ref tm) => {
                let mut doc = SolrDocument{fields: Vec::with_capacity(tm.len())};
                for (k, json_v) in tm.iter() {
                    let v = match json_v {
                        & I64(i64) => SolrI64(i64),
                        & U64(u64) => SolrU64(u64),
                        & F64(f64) => SolrF64(f64),
                        & String(ref string) => SolrString(string.clone()),
                        & Boolean(bool) => SolrBoolean(bool),
                        _ => SolrNull
                    };
                    doc.fields.push(SolrField{name: k.clone(), value: v});
                }
                Ok(doc)
            },
            _ => Err("SolrQueryResponse JSON parsing error (response => docs): doc is not an object".to_string())
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![allow(ctypes)]
#![feature(asm)]

extern crate core;

use core::iter::Iterator;
use core::str::StrExt;
use core::option::Option;

use core::marker::Copy;

impl Copy for Color {}

enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

struct IntRange {
    cur: int,
    max: int
}

impl IntRange {
    fn next(&mut self) -> Option<int> {
        if self.cur < self.max {
            self.cur += 1;
            Option::Some(self.cur - 1)
        } else {
            Option::None
        }
    }
}

fn range(lo: int, hi: int) -> IntRange {
    IntRange { cur: lo, max: hi }
}

fn clear_screen(background: Color) {
    let mut r = range(0, 80 * 25);
    loop {
        match r.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + x * 2) as *mut u16) = (background as u16) << 12;
                }
            },
            Option::None =>{break}
        }
    }
}

fn print_string(string: &str) {
    let mut bytes = string.bytes();
    let mut count = 0;
    loop {
        match bytes.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + count) as *mut u8) = x;
                    *((0xb8000 + count + 1) as *mut u8) = 0x0f;
                }
                count = count + 2;
            },
            Option::None =>{break}
        }
    }
}

fn move_cursor(row: u8, col: u8) {
    let pos = row*80 + col;
    outb(0x3D4,15);
    outb(0x3D5,pos);
    outb(0x3D4,14);
    outb(0x3D5,pos);
}

fn outb(port:u16, value:u8) {
    unsafe {
        asm!(
        "out $0,$1"
        :
        : "{ax}"(value), "{dx}"(port)
        :
        :
        )
    }
}

#[no_mangle]
#[no_split_stack]
pub fn main() {
    clear_screen(Color::LightRed);
    move_cursor(0,0);
    print_string("Hello world");
}
<commit_msg>Move cursor after printing string<commit_after>#![no_std]
#![allow(ctypes)]
#![feature(asm)]

extern crate core;

use core::iter::Iterator;
use core::str::StrExt;
use core::option::Option;

use core::marker::Copy;

impl Copy for Color {}

enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

struct IntRange {
    cur: int,
    max: int
}

impl IntRange {
    fn next(&mut self) -> Option<int> {
        if self.cur < self.max {
            self.cur += 1;
            Option::Some(self.cur - 1)
        } else {
            Option::None
        }
    }
}

fn range(lo: int, hi: int) -> IntRange {
    IntRange { cur: lo, max: hi }
}

fn clear_screen(background: Color) {
    let mut r = range(0, 80 * 25);
    loop {
        match r.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + x * 2) as *mut u16) = (background as u16) << 12;
                }
            },
            Option::None =>{break}
        }
    }
}

fn print_string(string: &str) {
    let mut bytes = string.bytes();
    let mut count = 0;
    loop {
        match bytes.next() {
            Option::Some(x) => {
                unsafe {
                    *((0xb8000 + count) as *mut u8) = x;
                    *((0xb8000 + count + 1) as *mut u8) = 0x0f;
                }
                count = count + 2;
            },
            Option::None =>{break}
        }
    }
    move_cursor(0,string.len() as u8);
}

fn move_cursor(row: u8, col: u8) {
    let pos:u16 = (row*80 + col) as u16;
    outb(0x3D4,15);
    outb(0x3D5,(pos & 0xff) as u8);
    outb(0x3D4,14);
    outb(0x3D5,((pos >> 8) & 0xff) as u8);
}

fn outb(port:u16, value:u8) {
    unsafe {
        asm!(
        "out $0,$1"
        :
        : "{ax}"(value), "{dx}"(port)
        :
        :
        )
    }
}

#[no_mangle]
#[no_split_stack]
pub fn main() {
    clear_screen(Color::LightRed);
    print_string("Hello world");
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate parser;
use std::io;

#[cfg(not(test))]
fn main() {
  let input = io::stdin().read_to_end().unwrap();
  match parser::parse( input ) {
    Some( ref node ) => println!( "{}", node ),
    _ => println!( "Couldn't parse input." )
  }
}

<commit_msg>Basic flags handling for main<commit_after>#![feature(macro_rules)]

extern crate getopts;
extern crate parser;
use getopts::{optflag, getopts};
use std::os;
use std::io;

fn printUsage( opts: &[getopts::OptGroup] ) {
  let args = os::args();
  let short = getopts::short_usage( args[0], opts );
  let usage = getopts::usage( short, opts );
  println!( "{}", usage );
}

#[cfg(not(test))]
fn main() {
  let opts = [
    optflag( "h", "help", "Print this help menu." ),
    // TODO: Should actually take a PEG grammar file and input, and then print
    // parsed tree of input.
    optflag( "p", "print-tree", "Print parsed tree." )
  ];

  let args = os::args();
  let matches = match getopts( args.tail(), opts ) {
    Ok( m ) => m,
    Err( erorr ) => fail!( erorr.to_err_msg() )
  };

  if matches.opt_present( "h" ) {
    printUsage( opts );
    return;
  }

  if matches.opt_present( "p" ) {
    let input = io::stdin().read_to_end().unwrap();
    match parser::parse( input ) {
      Some( ref node ) => println!( "{}", node ),
      _ => println!( "Couldn't parse input." )
    }
  }
}

<|endoftext|>