<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() },
    }
}

/// Handle requests for "/" landing page
pub fn landing(req: &mut Request) -> IronResult<Response> {
    let tera = get_templates!(req);
    let c = Context::new();
    let content = tera.render("landing.html", &c).expect("Template render failed. Oh well.");
    Ok(Response::with((mime!(Text/Html), status::Ok, content)))
}
<commit_msg>render_to_req<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>> {
    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 "/" landing page
pub fn landing(req: &mut Request) -> IronResult<Response> {
    let c = Context::new();
    render_to_req(req, "landing.html", c)
}
<|endoftext|>


<commit_before>use ast::{Node,TransformedNode,CompileErr};
use ast::transform::{Transform, TransformResult, TransformContext, RenderContext};
use scope::{ScopeData};
use std::rc::Rc;
use std::cell::RefCell;
use std::io::{Write, Read};
use tok;
use std::fs;
use filter;

/// Top level statements, can be Blocks of instructions
/// like Show/Hide/Mixin or single top-level statements,
/// e.g. variable definitions and imports
#[derive(Debug, Clone)]
pub enum Block<'a> {
    Show(Vec<&'a Node<'a>>),
    Hide(Vec<&'a Node<'a>>),
    Import(String),
}

#[derive(Debug, Clone, PartialEq)]
pub enum PlainBlock<'a> {
    Show(Vec<&'a TransformedNode<'a>>),
    Hide(Vec<&'a TransformedNode<'a>>),
}

impl <'a> Transform<'a> for Block<'a> {
    fn transform(&self, ctx: TransformContext<'a>)
            -> Result<Option<&'a TransformedNode<'a>>, CompileErr> {
        let block_ctx = TransformContext {
            scope: Rc::new(RefCell::new(
                ScopeData::new(Some(ctx.scope.clone()))
            )),
            transform_arena: ctx.transform_arena,
            ast_arena: ctx.ast_arena,
        };

        // collect transformed statements from lines in this block
        let mut t_statements : Vec<&TransformedNode> = Vec::new();
        match self {
            &Block::Show(ref statements) | &Block::Hide(ref statements) => {
                for statement in statements {
                    if let Some(t_statement) = statement.transform(block_ctx.clone())? {
                        match *t_statement {
                            TransformedNode::ExpandedNodes(ref resolved_stmts) => {
                                for stmt in resolved_stmts {
                                    // always add condition statements
                                    if let TransformedNode::ConditionStmt(_) = **stmt {
                                        t_statements.push(stmt);
                                    } else if let Some(index) = t_statements.iter().position(|other| *other == *stmt) {
                                        // replace existing same statement if possible
                                        t_statements[index] = stmt;
                                    } else {
                                        t_statements.push(stmt);
                                    }
                                }
                            },
                            _ => {
                                // always add condition statements
                                if let &TransformedNode::ConditionStmt(_) = t_statement {
                                    t_statements.push(t_statement);
                                } else if let Some(index) = t_statements.iter().position(|other| *other == t_statement) {
                                    // replace existing same statement if possible
                                    t_statements[index] = t_statement;
                                } else {
                                    t_statements.push(t_statement);
                                }
                            }
                        }
                    }
                }
            }
            &Block::Import(ref path) => {
                let mut file = fs::File::open(path)?;
                let mut contents = String::new();
                file.read_to_string(&mut contents)?;

                let tokens = Box::new(tok::tokenize(&contents));
                {
                    match filter::parse_Filter(ctx.ast_arena, tokens.into_iter()) {
                        Ok(&Node::Filter(ref filter)) => {
                            if let Some(&TransformedNode::Root(ref nodes)) =
                                    filter.transform_begin(ctx.ast_arena, ctx.scope.clone()).unwrap() {
                                for n in nodes {
                                    t_statements.push(n);
                                }
                                return Ok(Some(ctx.alloc_transformed(TransformedNode::ExpandedNodes(
                                    t_statements
                                ))))
                            } else {
                                return Ok(None);
                            }
                        },
                        _ => return Err(CompileErr::Unknown)
                    }
                }
            }
        }

        Ok(Some(ctx.alloc_transformed(TransformedNode::Block(
            match self {
                &Block::Show(_) => PlainBlock::Show(t_statements),
                &Block::Hide(_) => PlainBlock::Hide(t_statements),
                node => {
                    println!("{:?}", node);
                    unimplemented!()
                }
            }
        ))))
    }
}

impl <'a> TransformResult for PlainBlock<'a> {
    fn render(&self, ctx: RenderContext, buf: &mut Write) -> Result<(), CompileErr> {
        let nodes = match *self {
            PlainBlock::Show(ref nodes) => {
                buf.write("Show\n".as_ref())?;
                nodes
            },
            PlainBlock::Hide(ref nodes) => {
                buf.write("Hide\n".as_ref())?;
                nodes
            }
        };
        for n in nodes {
            n.render(ctx.increase_indent(), buf)?;
        }
        Ok(())
    }
}
<commit_msg>refactor statement dedup logic<commit_after>use ast::{Node,TransformedNode,CompileErr};
use ast::transform::{Transform, TransformResult, TransformContext, RenderContext};
use scope::{ScopeData};
use std::rc::Rc;
use std::cell::RefCell;
use std::io::{Write, Read};
use tok;
use std::fs;
use filter;

/// Top level statements, can be Blocks of instructions
/// like Show/Hide/Mixin or single top-level statements,
/// e.g. variable definitions and imports
#[derive(Debug, Clone)]
pub enum Block<'a> {
    Show(Vec<&'a Node<'a>>),
    Hide(Vec<&'a Node<'a>>),
    Import(String),
}

#[derive(Debug, Clone, PartialEq)]
pub enum PlainBlock<'a> {
    Show(Vec<&'a TransformedNode<'a>>),
    Hide(Vec<&'a TransformedNode<'a>>),
}

trait NodeList<'a> {
    fn push_statement(&mut self, value: &'a TransformedNode);
}

impl <'a> NodeList<'a> for Vec<&'a TransformedNode<'a>> {
    fn push_statement(&mut self, value: &'a TransformedNode) {
        if let &TransformedNode::ConditionStmt(_) = value {
            self.push(value);
        } else if let Some(index) = self.iter().position(|other| *other == value) {
            // replace existing same statement if possible
            self[index] = value;
        } else {
            self.push(value);
        }
    }
}

impl <'a> Transform<'a> for Block<'a> {
    fn transform(&self, ctx: TransformContext<'a>)
            -> Result<Option<&'a TransformedNode<'a>>, CompileErr> {
        let block_ctx = TransformContext {
            scope: Rc::new(RefCell::new(
                ScopeData::new(Some(ctx.scope.clone()))
            )),
            transform_arena: ctx.transform_arena,
            ast_arena: ctx.ast_arena,
        };

        // collect transformed statements from lines in this block
        let mut t_statements : Vec<&TransformedNode> = Vec::new();
        match self {
            &Block::Show(ref statements) | &Block::Hide(ref statements) => {
                for statement in statements {
                    if let Some(t_statement) = statement.transform(block_ctx.clone())? {
                        match *t_statement {
                            TransformedNode::ExpandedNodes(ref resolved_stmts) => {
                                for stmt in resolved_stmts {
                                    t_statements.push_statement(stmt);
                                }
                            },
                            _ => {
                                t_statements.push_statement(t_statement);
                            }
                        }
                    }
                }
            }
            &Block::Import(ref path) => {
                let mut file = fs::File::open(path)?;
                let mut contents = String::new();
                file.read_to_string(&mut contents)?;

                let tokens = Box::new(tok::tokenize(&contents));
                {
                    match filter::parse_Filter(ctx.ast_arena, tokens.into_iter()) {
                        Ok(&Node::Filter(ref filter)) => {
                            if let Some(&TransformedNode::Root(ref nodes)) =
                                    filter.transform_begin(ctx.ast_arena, ctx.scope.clone()).unwrap() {
                                for n in nodes {
                                    t_statements.push(n);
                                }
                                return Ok(Some(ctx.alloc_transformed(TransformedNode::ExpandedNodes(
                                    t_statements
                                ))))
                            } else {
                                return Ok(None);
                            }
                        },
                        _ => return Err(CompileErr::Unknown)
                    }
                }
            }
        }

        Ok(Some(ctx.alloc_transformed(TransformedNode::Block(
            match self {
                &Block::Show(_) => PlainBlock::Show(t_statements),
                &Block::Hide(_) => PlainBlock::Hide(t_statements),
                node => {
                    println!("{:?}", node);
                    unimplemented!()
                }
            }
        ))))
    }
}

impl <'a> TransformResult for PlainBlock<'a> {
    fn render(&self, ctx: RenderContext, buf: &mut Write) -> Result<(), CompileErr> {
        let nodes = match *self {
            PlainBlock::Show(ref nodes) => {
                buf.write("Show\n".as_ref())?;
                nodes
            },
            PlainBlock::Hide(ref nodes) => {
                buf.write("Hide\n".as_ref())?;
                nodes
            }
        };
        for n in nodes {
            n.render(ctx.increase_indent(), buf)?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Defines the most basic types and constants like the pieces,
//! colors, squares, files, and ranks.
//!
//! This module also defines few simple functions.

/// `WHITE` or `BLACK`.
pub type Color = usize;

pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

/// `KING`, `QUEEN`, `ROOK`, `BISHOP`, `KINGHT`, `PAWN` or `NO_PIECE`.
pub type PieceType = usize;

pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const NO_PIECE: PieceType = 6;

/// From 0 to 7 (0 is rank 1, 7 is rank 8).
pub type Rank = usize;

pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

/// From 0 to 7 (0 is file A, 7 is file H).
pub type File = usize;

pub const FILE_A: File = 0;
pub const FILE_B: File = 1;
pub const FILE_C: File = 2;
pub const FILE_D: File = 3;
pub const FILE_E: File = 4;
pub const FILE_F: File = 5;
pub const FILE_G: File = 6;
pub const FILE_H: File = 7;

/// From 0 to 63 (0 is A1, 63 is H8).
pub type Square = usize;

pub const A1: Square = 0 + 0 * 8;
pub const B1: Square = 1 + 0 * 8;
pub const C1: Square = 2 + 0 * 8;
pub const D1: Square = 3 + 0 * 8;
pub const E1: Square = 4 + 0 * 8;
pub const F1: Square = 5 + 0 * 8;
pub const G1: Square = 6 + 0 * 8;
pub const H1: Square = 7 + 0 * 8;
pub const A2: Square = 0 + 1 * 8;
pub const B2: Square = 1 + 1 * 8;
pub const C2: Square = 2 + 1 * 8;
pub const D2: Square = 3 + 1 * 8;
pub const E2: Square = 4 + 1 * 8;
pub const F2: Square = 5 + 1 * 8;
pub const G2: Square = 6 + 1 * 8;
pub const H2: Square = 7 + 1 * 8;
pub const A3: Square = 0 + 2 * 8;
pub const B3: Square = 1 + 2 * 8;
pub const C3: Square = 2 + 2 * 8;
pub const D3: Square = 3 + 2 * 8;
pub const E3: Square = 4 + 2 * 8;
pub const F3: Square = 5 + 2 * 8;
pub const G3: Square = 6 + 2 * 8;
pub const H3: Square = 7 + 2 * 8;
pub const A4: Square = 0 + 3 * 8;
pub const B4: Square = 1 + 3 * 8;
pub const C4: Square = 2 + 3 * 8;
pub const D4: Square = 3 + 3 * 8;
pub const E4: Square = 4 + 3 * 8;
pub const F4: Square = 5 + 3 * 8;
pub const G4: Square = 6 + 3 * 8;
pub const H4: Square = 7 + 3 * 8;
pub const A5: Square = 0 + 4 * 8;
pub const B5: Square = 1 + 4 * 8;
pub const C5: Square = 2 + 4 * 8;
pub const D5: Square = 3 + 4 * 8;
pub const E5: Square = 4 + 4 * 8;
pub const F5: Square = 5 + 4 * 8;
pub const G5: Square = 6 + 4 * 8;
pub const H5: Square = 7 + 4 * 8;
pub const A6: Square = 0 + 5 * 8;
pub const B6: Square = 1 + 5 * 8;
pub const C6: Square = 2 + 5 * 8;
pub const D6: Square = 3 + 5 * 8;
pub const E6: Square = 4 + 5 * 8;
pub const F6: Square = 5 + 5 * 8;
pub const G6: Square = 6 + 5 * 8;
pub const H6: Square = 7 + 5 * 8;
pub const A7: Square = 0 + 6 * 8;
pub const B7: Square = 1 + 6 * 8;
pub const C7: Square = 2 + 6 * 8;
pub const D7: Square = 3 + 6 * 8;
pub const E7: Square = 4 + 6 * 8;
pub const F7: Square = 5 + 6 * 8;
pub const G7: Square = 6 + 6 * 8;
pub const H7: Square = 7 + 6 * 8;
pub const A8: Square = 0 + 7 * 8;
pub const B8: Square = 1 + 7 * 8;
pub const C8: Square = 2 + 7 * 8;
pub const D8: Square = 3 + 7 * 8;
pub const E8: Square = 4 + 7 * 8;
pub const F8: Square = 5 + 7 * 8;
pub const G8: Square = 6 + 7 * 8;
pub const H8: Square = 7 + 7 * 8;

/// Number of searched positions.
pub type NodeCount = u64;

/// A set of squares on the chessboard.
///
/// `u64` bit-sets called *bitboards* can be used to represent a set
/// of squares on the chessboard. For example, the set of squares that
/// are occupied by white rooks in the beginning of the game is: `1 <<
/// A1 | 1 << H1`. `0` represents the empty set, `0xffffffffffffffff`
/// represents the set of all 64 squares on the board.
pub type Bitboard = u64;

/// Evaluation value in centipawns.
///
/// Positive values mean that the position is favorable for the side
/// to move. Negative values mean the position is favorable for the
/// other side (not to move). A value of `0` means that the chances
/// are equal. For example: a value of `100` might mean that the side
/// to move is a pawn ahead.
///
/// The constant `VALUE_UNKNOWN` equals to `-32768`, and has the
/// special meaning of "unknown value".
pub type Value = i16;

pub const VALUE_MAX: Value = ::std::i16::MAX;
pub const VALUE_MIN: Value = -VALUE_MAX;
pub const VALUE_UNKNOWN: Value = VALUE_MIN - 1;

/// `QUEENSIDE` or `KINGSIDE`.
pub type CastlingSide = usize; // 0 or 1

pub const QUEENSIDE: CastlingSide = 0;
pub const KINGSIDE: CastlingSide = 1;

/// Describes how pieces are placed on the board.
#[derive(Clone, Copy)]
pub struct PiecesPlacement {
    /// An array of occupation bitboards indexed by piece type.  For
    /// example, `piece_placement.piece_type[PAWN]` gives the set of
    /// all pawns on the board (white and black).
    pub piece_type: [Bitboard; 6],

    /// An array of occupation bitboards indexed by color.  For
    /// example, `piece_placement.color[WHITE]` gives the set of all
    /// white pieces and pawns on the board.
    pub color: [Bitboard; 2],
}

impl PiecesPlacement {
    /// Returns a human-readable representation of the placement of
    /// pieces.
    pub fn pretty_string(&self) -> String {
        let mut s = String::new();
        for rank in (0..8).rev() {
            for file in 0..8 {
                let square = square(file, rank);
                let bb = 1 << square;
                let piece = match bb {
                    x if x & self.piece_type[KING] != 0 => 'k',
                    x if x & self.piece_type[QUEEN] != 0 => 'q',
                    x if x & self.piece_type[ROOK] != 0 => 'r',
                    x if x & self.piece_type[BISHOP] != 0 => 'b',
                    x if x & self.piece_type[KNIGHT] != 0 => 'n',
                    x if x & self.piece_type[PAWN] != 0 => 'p',
                    _ => '.',
                };
                if bb & self.color[WHITE] != 0 {
                    s.push(piece.to_uppercase().next().unwrap());
                } else {
                    s.push(piece);
                }
            }
            s.push('\n');
        }
        s
    }
}

/// Holds information about which player can castle on which side.
///
/// The castling rights are held in a `usize` value. The lowest 4 bits
/// of the value contain the whole needed information. It is laid out
/// in the following way:
///
/// ```text
///  usize                    3   2   1   0
///  +----------------------+---+---+---+---+
///  |                      |   |   |   |   |
///  |    Unused (zeros)    |Castling flags |
///  |                      |   |   |   |   |
///  +----------------------+---+---+---+---+
///
///  bit 0 -- if set, white can castle on queen-side;
///  bit 1 -- if set, white can castle on king-side;
///  bit 2 -- if set, black can castle on queen-side;
///  bit 3 -- if set, black can castle on king-side.
/// ```
#[derive(Clone, Copy)]
pub struct CastlingRights(usize);

impl CastlingRights {
    /// Creates a new instance.
    ///
    /// The least significant 4 bits of `value` are used as a raw
    /// value for the new instance.
    #[inline(always)]
    pub fn new(value: usize) -> CastlingRights {
        CastlingRights(value & 0b1111)
    }

    /// Returns the contained raw value (between 0 and 15).
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }

    /// Grants a given player the right to castle on a given side.
    ///
    /// This method returns `true` if the player had the right to
    /// castle on the given side before this method was called, and
    /// `false` otherwise.
    pub fn grant(&mut self, player: Color, side: CastlingSide) -> bool {
        assert!(player <= 1);
        assert!(side <= 1);
        let before = self.0;
        let mask = 1 << (player << 1) << side;
        self.0 |= mask;
        !before & mask == 0
    }

    /// Updates the castling rights after played move.
    ///
    /// `orig_square` and `dest_square` describe the played move.
    #[inline(always)]
    pub fn update(&mut self, orig_square: Square, dest_square: Square) {
        debug_assert!(orig_square <= 63);
        debug_assert!(dest_square <= 63);

        const WQ: usize = 1 << 0;
        const WK: usize = 1 << 1;
        const WB: usize = WQ | WK;
        const BQ: usize = 1 << 2;
        const BK: usize = 1 << 3;
        const BB: usize = BQ | BK;

        // On each move, the value of `CASTLING_RELATION` for the
        // origin and destination squares should be AND-ed with the
        // castling rights value, to derive the updated castling
        // rights.
        const CASTLING_RELATION: [usize; 64] = [
            !WQ, !0,  !0,  !0,  !WB, !0,  !0,  !WK,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !BQ, !0,  !0,  !0,  !BB, !0,  !0,  !BK,
        ];
        self.0 &= CASTLING_RELATION[orig_square] & CASTLING_RELATION[dest_square];
    }

    /// Returns if a given player has the rights to castle on a given
    /// side.
    #[inline(always)]
    pub fn can_castle(&self, player: Color, side: CastlingSide) -> bool {
        debug_assert!(player <= 1);
        debug_assert!(side <= 1);
        (1 << (player << 1) << side) & self.0 != 0
    }
}

/// Returns the square on given file and rank.
#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    debug_assert!(file < 8);
    debug_assert!(rank < 8);
    rank * 8 + file
}

/// Returns the rank of a given square.
#[inline(always)]
pub fn rank(square: Square) -> Rank {
    debug_assert!(square <= 63);
    square >> 3
}

/// Returns the file of a given square.
#[inline(always)]
pub fn file(square: Square) -> File {
    debug_assert!(square <= 63);
    square % 8
}

/// Returns the algebraic notation for a given square.
pub fn notation(square: Square) -> &'static str {
    lazy_static! {
        static ref NOTATION: Vec<String> = (0..64).map(|i| format!("{}{}",
            ["a", "b", "c", "d", "e", "f", "g", "h"][file(i)],
            ["1", "2", "3", "4", "5", "6", "7", "8"][rank(i)])
        ).collect();
    }
    NOTATION[square].as_str()
}
<commit_msg>implement Debug and Display for basetypes<commit_after>//! Defines the most basic types and constants like the pieces,
//! colors, squares, files, and ranks.
//!
//! This module also defines few simple functions.
use std::fmt;

/// `WHITE` or `BLACK`.
pub type Color = usize;

pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

/// `KING`, `QUEEN`, `ROOK`, `BISHOP`, `KINGHT`, `PAWN` or `NO_PIECE`.
pub type PieceType = usize;

pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const NO_PIECE: PieceType = 6;

/// From 0 to 7 (0 is rank 1, 7 is rank 8).
pub type Rank = usize;

pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

/// From 0 to 7 (0 is file A, 7 is file H).
pub type File = usize;

pub const FILE_A: File = 0;
pub const FILE_B: File = 1;
pub const FILE_C: File = 2;
pub const FILE_D: File = 3;
pub const FILE_E: File = 4;
pub const FILE_F: File = 5;
pub const FILE_G: File = 6;
pub const FILE_H: File = 7;

/// From 0 to 63 (0 is A1, 63 is H8).
pub type Square = usize;

pub const A1: Square = 0 + 0 * 8;
pub const B1: Square = 1 + 0 * 8;
pub const C1: Square = 2 + 0 * 8;
pub const D1: Square = 3 + 0 * 8;
pub const E1: Square = 4 + 0 * 8;
pub const F1: Square = 5 + 0 * 8;
pub const G1: Square = 6 + 0 * 8;
pub const H1: Square = 7 + 0 * 8;
pub const A2: Square = 0 + 1 * 8;
pub const B2: Square = 1 + 1 * 8;
pub const C2: Square = 2 + 1 * 8;
pub const D2: Square = 3 + 1 * 8;
pub const E2: Square = 4 + 1 * 8;
pub const F2: Square = 5 + 1 * 8;
pub const G2: Square = 6 + 1 * 8;
pub const H2: Square = 7 + 1 * 8;
pub const A3: Square = 0 + 2 * 8;
pub const B3: Square = 1 + 2 * 8;
pub const C3: Square = 2 + 2 * 8;
pub const D3: Square = 3 + 2 * 8;
pub const E3: Square = 4 + 2 * 8;
pub const F3: Square = 5 + 2 * 8;
pub const G3: Square = 6 + 2 * 8;
pub const H3: Square = 7 + 2 * 8;
pub const A4: Square = 0 + 3 * 8;
pub const B4: Square = 1 + 3 * 8;
pub const C4: Square = 2 + 3 * 8;
pub const D4: Square = 3 + 3 * 8;
pub const E4: Square = 4 + 3 * 8;
pub const F4: Square = 5 + 3 * 8;
pub const G4: Square = 6 + 3 * 8;
pub const H4: Square = 7 + 3 * 8;
pub const A5: Square = 0 + 4 * 8;
pub const B5: Square = 1 + 4 * 8;
pub const C5: Square = 2 + 4 * 8;
pub const D5: Square = 3 + 4 * 8;
pub const E5: Square = 4 + 4 * 8;
pub const F5: Square = 5 + 4 * 8;
pub const G5: Square = 6 + 4 * 8;
pub const H5: Square = 7 + 4 * 8;
pub const A6: Square = 0 + 5 * 8;
pub const B6: Square = 1 + 5 * 8;
pub const C6: Square = 2 + 5 * 8;
pub const D6: Square = 3 + 5 * 8;
pub const E6: Square = 4 + 5 * 8;
pub const F6: Square = 5 + 5 * 8;
pub const G6: Square = 6 + 5 * 8;
pub const H6: Square = 7 + 5 * 8;
pub const A7: Square = 0 + 6 * 8;
pub const B7: Square = 1 + 6 * 8;
pub const C7: Square = 2 + 6 * 8;
pub const D7: Square = 3 + 6 * 8;
pub const E7: Square = 4 + 6 * 8;
pub const F7: Square = 5 + 6 * 8;
pub const G7: Square = 6 + 6 * 8;
pub const H7: Square = 7 + 6 * 8;
pub const A8: Square = 0 + 7 * 8;
pub const B8: Square = 1 + 7 * 8;
pub const C8: Square = 2 + 7 * 8;
pub const D8: Square = 3 + 7 * 8;
pub const E8: Square = 4 + 7 * 8;
pub const F8: Square = 5 + 7 * 8;
pub const G8: Square = 6 + 7 * 8;
pub const H8: Square = 7 + 7 * 8;

/// Number of searched positions.
pub type NodeCount = u64;

/// A set of squares on the chessboard.
///
/// `u64` bit-sets called *bitboards* can be used to represent a set
/// of squares on the chessboard. For example, the set of squares that
/// are occupied by white rooks in the beginning of the game is: `1 <<
/// A1 | 1 << H1`. `0` represents the empty set, `0xffffffffffffffff`
/// represents the set of all 64 squares on the board.
pub type Bitboard = u64;

/// Evaluation value in centipawns.
///
/// Positive values mean that the position is favorable for the side
/// to move. Negative values mean the position is favorable for the
/// other side (not to move). A value of `0` means that the chances
/// are equal. For example: a value of `100` might mean that the side
/// to move is a pawn ahead.
///
/// The constant `VALUE_UNKNOWN` equals to `-32768`, and has the
/// special meaning of "unknown value".
pub type Value = i16;

pub const VALUE_MAX: Value = ::std::i16::MAX;
pub const VALUE_MIN: Value = -VALUE_MAX;
pub const VALUE_UNKNOWN: Value = VALUE_MIN - 1;

/// `QUEENSIDE` or `KINGSIDE`.
pub type CastlingSide = usize; // 0 or 1

pub const QUEENSIDE: CastlingSide = 0;
pub const KINGSIDE: CastlingSide = 1;

/// Describes how pieces are placed on the board.
#[derive(Clone, Copy, Debug)]
pub struct PiecesPlacement {
    /// An array of occupation bitboards indexed by piece type.  For
    /// example, `piece_placement.piece_type[PAWN]` gives the set of
    /// all pawns on the board (white and black).
    pub piece_type: [Bitboard; 6],

    /// An array of occupation bitboards indexed by color.  For
    /// example, `piece_placement.color[WHITE]` gives the set of all
    /// white pieces and pawns on the board.
    pub color: [Bitboard; 2],
}

impl fmt::Display for PiecesPlacement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = String::new();
        for rank in (0..8).rev() {
            s.push('\n');
            for file in 0..8 {
                let square = square(file, rank);
                let bb = 1 << square;
                let piece = match bb {
                    x if x & self.piece_type[KING] != 0 => 'k',
                    x if x & self.piece_type[QUEEN] != 0 => 'q',
                    x if x & self.piece_type[ROOK] != 0 => 'r',
                    x if x & self.piece_type[BISHOP] != 0 => 'b',
                    x if x & self.piece_type[KNIGHT] != 0 => 'n',
                    x if x & self.piece_type[PAWN] != 0 => 'p',
                    _ => '.',
                };
                if bb & self.color[WHITE] != 0 {
                    s.push(piece.to_uppercase().next().unwrap());
                } else {
                    s.push(piece);
                }
            }
        }
        writeln!(f, "{}", s)
    }
}

/// Holds information about which player can castle on which side.
///
/// The castling rights are held in a `usize` value. The lowest 4 bits
/// of the value contain the whole needed information. It is laid out
/// in the following way:
///
/// ```text
///  usize                    3   2   1   0
///  +----------------------+---+---+---+---+
///  |                      |   |   |   |   |
///  |    Unused (zeros)    |Castling flags |
///  |                      |   |   |   |   |
///  +----------------------+---+---+---+---+
///
///  bit 0 -- if set, white can castle on queen-side;
///  bit 1 -- if set, white can castle on king-side;
///  bit 2 -- if set, black can castle on queen-side;
///  bit 3 -- if set, black can castle on king-side.
/// ```
#[derive(Clone, Copy, Debug)]
pub struct CastlingRights(usize);

impl CastlingRights {
    /// Creates a new instance.
    ///
    /// The least significant 4 bits of `value` are used as a raw
    /// value for the new instance.
    #[inline(always)]
    pub fn new(value: usize) -> CastlingRights {
        CastlingRights(value & 0b1111)
    }

    /// Returns the contained raw value (between 0 and 15).
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }

    /// Grants a given player the right to castle on a given side.
    ///
    /// This method returns `true` if the player had the right to
    /// castle on the given side before this method was called, and
    /// `false` otherwise.
    pub fn grant(&mut self, player: Color, side: CastlingSide) -> bool {
        assert!(player <= 1);
        assert!(side <= 1);
        let before = self.0;
        let mask = 1 << (player << 1) << side;
        self.0 |= mask;
        !before & mask == 0
    }

    /// Updates the castling rights after played move.
    ///
    /// `orig_square` and `dest_square` describe the played move.
    #[inline(always)]
    pub fn update(&mut self, orig_square: Square, dest_square: Square) {
        debug_assert!(orig_square <= 63);
        debug_assert!(dest_square <= 63);

        const WQ: usize = 1 << 0;
        const WK: usize = 1 << 1;
        const WB: usize = WQ | WK;
        const BQ: usize = 1 << 2;
        const BK: usize = 1 << 3;
        const BB: usize = BQ | BK;

        // On each move, the value of `CASTLING_RELATION` for the
        // origin and destination squares should be AND-ed with the
        // castling rights value, to derive the updated castling
        // rights.
        const CASTLING_RELATION: [usize; 64] = [
            !WQ, !0,  !0,  !0,  !WB, !0,  !0,  !WK,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !0,  !0,  !0,  !0,  !0,  !0,  !0,  !0,
            !BQ, !0,  !0,  !0,  !BB, !0,  !0,  !BK,
        ];
        self.0 &= CASTLING_RELATION[orig_square] & CASTLING_RELATION[dest_square];
    }

    /// Returns if a given player has the rights to castle on a given
    /// side.
    #[inline(always)]
    pub fn can_castle(&self, player: Color, side: CastlingSide) -> bool {
        debug_assert!(player <= 1);
        debug_assert!(side <= 1);
        (1 << (player << 1) << side) & self.0 != 0
    }
}

impl fmt::Display for CastlingRights {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut value = self.value();
        for s in ["Q", "K", "q", "k"].iter() {
            if value & 1 == 1 {
                try!(f.write_str(s));
            }
            value >>= 1;
        }
        Ok(())
    }
}

/// Returns the square on given file and rank.
#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    debug_assert!(file < 8);
    debug_assert!(rank < 8);
    rank * 8 + file
}

/// Returns the rank of a given square.
#[inline(always)]
pub fn rank(square: Square) -> Rank {
    debug_assert!(square <= 63);
    square >> 3
}

/// Returns the file of a given square.
#[inline(always)]
pub fn file(square: Square) -> File {
    debug_assert!(square <= 63);
    square % 8
}

/// Returns the algebraic notation for a given square.
pub fn notation(square: Square) -> &'static str {
    lazy_static! {
        static ref NOTATION: Vec<String> = (0..64).map(|i| format!("{}{}",
            ["a", "b", "c", "d", "e", "f", "g", "h"][file(i)],
            ["1", "2", "3", "4", "5", "6", "7", "8"][rank(i)])
        ).collect();
    }
    NOTATION[square].as_str()
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use y4m;

#[macro_use]
extern crate scan_fmt;

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use crate::muxer::*;
use rav1e::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use std::fs::File;
use std::io::BufWriter;

fn read_frame<T: Pixel, D: Decoder>(ctx: &mut Context<T>, decoder: &mut D, video_info: VideoDetails) {
  match decoder.read_frame(&video_info) {
    Ok(frame) => {
      match video_info.bit_depth {
        8 | 10 | 12 => {}
        _ => panic!("unknown input bit depth!")
      }

      let _ = ctx.send_frame(Some(Arc::new(frame)));
    }
    _ => {
      let frames_to_be_coded = ctx.get_frame_count();
      // This is a hack, instead when EOF is reached simply "close" the encoder to input (flag)
      ctx.set_limit(frames_to_be_coded);
      ctx.flush();
    }
  };
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel>(
  ctx: &mut Context<T>,
  output_file: &mut dyn Write,
  y4m_dec: &mut y4m::Decoder<'_, Box<dyn Read>>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
) -> Result<Vec<FrameSummary>, ()> {
  let y4m_details = y4m_dec.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      write_ivf_frame(output_file, pkt.number as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreFrames) => {
      read_frame(ctx, y4m_dec, y4m_details);
    }
    Err(EncoderStatus::NeedMoreData) | Err(EncoderStatus::EnoughData) => {
      // Expected statuses, continue without error
    }
    Err(EncoderStatus::Failure) | Err(EncoderStatus::InvalidKey) | Err(EncoderStatus::ParseError) => {
      panic!("Failed to encode video");
    }
  }
  Ok(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, &ctx.first_pass_data).expect("Serialization should not fail");
  Ok(())
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let mut y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc
  };

  // FIXME for now, unconditionally create Context<u16>
  let mut ctx: Context<u16> = cfg.new_context();

  let stderr = io::stderr();
  let mut err = stderr.lock();

  let _ = writeln!(
    err,
    "{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  write_ivf_header(
    &mut cli.io.output,
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let mut progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  ctx.set_limit(cli.limit as u64);

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  while let Ok(frame_info) = process_frame(&mut ctx, &mut cli.io.output, &mut y4m_dec, y4m_enc.as_mut()) {
    for frame in frame_info {
      progress.add_frame(frame);
      let _ = if cli.verbose {
        writeln!(err, "{} - {}", frame, progress)
      } else {
        write!(err, "\r{}                    ", progress)
      };
    }

    if !ctx.needs_more_frames(progress.frames_encoded() as u64) {
      break;
    }

    cli.io.output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) = write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap()) {
      let _ = writeln!(err, "\nError: Failed to write stats file! {}\n", e);
    }
  }
  let _ = write!(err, "\n{}\n", progress.print_summary());
}
<commit_msg>rav1e: use u8 pixels for bitdepth 8<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use y4m;

#[macro_use]
extern crate scan_fmt;

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use crate::muxer::*;
use rav1e::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use std::fs::File;
use std::io::BufWriter;

fn read_frame<T: Pixel, D: Decoder>(ctx: &mut Context<T>, decoder: &mut D, video_info: VideoDetails) {
  match decoder.read_frame(&video_info) {
    Ok(frame) => {
      match video_info.bit_depth {
        8 | 10 | 12 => {}
        _ => panic!("unknown input bit depth!")
      }

      let _ = ctx.send_frame(Some(Arc::new(frame)));
    }
    _ => {
      let frames_to_be_coded = ctx.get_frame_count();
      // This is a hack, instead when EOF is reached simply "close" the encoder to input (flag)
      ctx.set_limit(frames_to_be_coded);
      ctx.flush();
    }
  };
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel>(
  ctx: &mut Context<T>,
  output_file: &mut dyn Write,
  y4m_dec: &mut y4m::Decoder<'_, Box<dyn Read>>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
) -> Result<Vec<FrameSummary>, ()> {
  let y4m_details = y4m_dec.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      write_ivf_frame(output_file, pkt.number as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreFrames) => {
      read_frame(ctx, y4m_dec, y4m_details);
    }
    Err(EncoderStatus::NeedMoreData) | Err(EncoderStatus::EnoughData) => {
      // Expected statuses, continue without error
    }
    Err(EncoderStatus::Failure) | Err(EncoderStatus::InvalidKey) | Err(EncoderStatus::ParseError) => {
      panic!("Failed to encode video");
    }
  }
  Ok(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, &ctx.first_pass_data).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel>(
  cfg: Config, limit: usize, verbose: bool, mut progress: ProgressInfo,
  mut err: std::io::StderrLock, mut output: &mut dyn Write,
  mut y4m_dec: &mut y4m::Decoder<'_, Box<dyn Read>>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  ctx.set_limit(limit as u64);

  while let Ok(frame_info) =
    process_frame(&mut ctx, &mut output, &mut y4m_dec, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      let _ = if verbose {
        writeln!(err, "{} - {}", frame, progress)
      } else {
        write!(err, "\r{}                    ", progress)
      };
    }

    if !ctx.needs_more_frames(progress.frames_encoded() as u64) {
      break;
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      let _ = writeln!(err, "\nError: Failed to write stats file! {}\n", e);
    }
  }
  let _ = write!(err, "\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc
  };

  let stderr = io::stderr();
  let mut err = stderr.lock();

  let _ = writeln!(
    err,
    "{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  write_ivf_header(
    &mut cli.io.output,
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  if video_info.bit_depth == 8 {
    do_encode::<u8>(
      cfg, cli.limit, cli.verbose, progress, err, &mut cli.io.output, &mut y4m_dec, y4m_enc
    )
  } else {
    do_encode::<u16>(
      cfg, cli.limit, cli.verbose, progress, err, &mut cli.io.output, &mut y4m_dec, y4m_enc
    )
  }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate config;
#[macro_use]
extern crate failure;
extern crate r2d2;
extern crate rocket;

use std::error::Error as StdError;
use std::io::{self, ErrorKind};
use std::process::{self, Command, Output};

use clap::App;

mod common;

fn check_out(output: &Result<Output, io::Error>) {
    match output {
        &Ok(ref o) if !o.status.success() => {
            eprintln!("got non-zero exit code, output was:\n\tstdout:\n{}\n\tstderr:\n{}",
                    String::from_utf8_lossy(&o.stdout),
                    String::from_utf8_lossy(&o.stderr));
            process::exit(255);
        },
        &Err(ref e) => {
            match e.kind() {
                ErrorKind::NotFound => {
                    eprintln!("Could not find `diesel` binary, please use `cargo install diesel_cli` to install it");
                },
                _ => eprintln!("got error {}", e.description()),
            }
            process::exit(255);
        },
        &Ok(_) => {},
    }
}

fn main() {
    let yaml = load_yaml!("setup.yml");
    let app = App::from_yaml(yaml)
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"));
    let config = common::configure(app).unwrap();
    let db_url = common::db_conn_string(&config).unwrap();
    println!("using database url `{}' to setup the aardwolf database", &db_url);
    let output = Command::new("diesel")
        .arg("setup")
        .arg("--migration-dir")
        .arg("aardwolf-models/migrations")
        .env("DATABASE_URL", &db_url)
        .output();
    check_out(&output);
    println!("database migrations were successfully run, you're ready to go!");*/
}
<commit_msg>Fix typo in setup.rs<commit_after>#[macro_use] extern crate clap;
extern crate config;
#[macro_use]
extern crate failure;
extern crate r2d2;
extern crate rocket;

use std::error::Error as StdError;
use std::io::{self, ErrorKind};
use std::process::{self, Command, Output};

use clap::App;

mod common;

fn check_out(output: &Result<Output, io::Error>) {
    match output {
        &Ok(ref o) if !o.status.success() => {
            eprintln!("got non-zero exit code, output was:\n\tstdout:\n{}\n\tstderr:\n{}",
                    String::from_utf8_lossy(&o.stdout),
                    String::from_utf8_lossy(&o.stderr));
            process::exit(255);
        },
        &Err(ref e) => {
            match e.kind() {
                ErrorKind::NotFound => {
                    eprintln!("Could not find `diesel` binary, please use `cargo install diesel_cli` to install it");
                },
                _ => eprintln!("got error {}", e.description()),
            }
            process::exit(255);
        },
        &Ok(_) => {},
    }
}

fn main() {
    let yaml = load_yaml!("setup.yml");
    let app = App::from_yaml(yaml)
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"));
    let config = common::configure(app).unwrap();
    let db_url = common::db_conn_string(&config).unwrap();
    println!("using database url `{}' to setup the aardwolf database", &db_url);
    let output = Command::new("diesel")
        .arg("setup")
        .arg("--migration-dir")
        .arg("aardwolf-models/migrations")
        .env("DATABASE_URL", &db_url)
        .output();
    check_out(&output);
    println!("database migrations were successfully run, you're ready to go!");
}
<|endoftext|>


<commit_before>//! Project changelog

/// Release 0.6.0 (2020-04-0?)
///
/// * Introduced a new method [`os::unix::Library::get_singlethreaded`];
/// * Added (untested) support for building when targetting Redox and Fuchsia;
/// * The APIs exposed by this library no longer panic and instead return an `Err` when it used
///   to panic.
///
/// ## Breaking changes
///
/// * Minimum required (stable) version of Rust to build this library is now 1.40.0;
/// * This crate now implements a custom [`Error`] type and all APIs now return this type rather
///   than returning the `std::io::Error`;
/// * `libloading::Result` has been removed;
/// * Removed the dependency on the C compiler to build this library on UNIX-like platforms.
///   `libloading` used to utilize a snippet written in C to work-around the unlikely possibility
///   of the target having a thread-unsafe implementation of the `dlerror` function. The effect of
///   the work-around was very opportunistic: it would not work if the function was called by
///   forgoing `libloading`.
///
///   Starting with 0.6.0, [`Library::get`] on platforms where `dlerror` is not MT-safe (such as
///   FreeBSD, DragonflyBSD or NetBSD) will unconditionally return an error when the underlying
///   `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary
///   consider using [`os::unix::Library::get_singlethreaded`] instead.
///
/// [`Library::get`]: crate::Library::get
/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
/// [`Error`]: crate::Error
pub mod r0_6_0 {}

/// Release 0.5.2 (2019-07-07)
///
/// * Added API to convert OS-specific `Library` and `Symbol` conversion to underlying resources.
pub mod r0_5_2 {}

/// Release 0.5.1 (2019-06-01)
///
/// * Build on Haiku targets.
pub mod r0_5_1 {}

/// Release 0.5.0 (2018-01-11)
///
/// * Update to `winapi = ^0.3`;
///
/// ## Breaking changes
///
/// * libloading now requires a C compiler to build on UNIX;
///   * This is a temporary measure until the [`linkage`] attribute is stabilised;
///   * Necessary to resolve [#32].
///
/// [`linkage`]: https://github.com/rust-lang/rust/issues/29603
/// [#32]: https://github.com/nagisa/rust_libloading/issues/32
pub mod r0_5_0 {}

/// Release 0.4.3 (2017-12-07)
///
/// * Bump lazy-static dependency to `^1.0`;
/// * `cargo test --release` now works when testing libloading.
pub mod r0_4_3 {}

/// Release 0.4.2 (2017-09-24)
///
/// * Improved error and race-condition handling on Windows;
/// * Improved documentation about thread-safety of Library;
/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
pub mod r0_4_2 {}

/// Release 0.4.1 (2017-08-29)
///
/// * Solaris support
pub mod r0_4_1 {}

/// Release 0.4.0 (2017-05-01)
///
/// * Remove build-time dependency on target_build_utils (and by extension serde/phf);
/// * Require at least version 1.14.0 of rustc to build;
///   * Actually, it is cargo which has to be more recent here. The one shipped with rustc 1.14.0
///     is what’s being required from now on.
pub mod r0_4_0 {}

/// Release 0.3.4 (2017-03-25)
///
/// * Remove rogue println!
pub mod r0_3_4 {}

/// Release 0.3.3 (2017-03-25)
///
/// * Panics when `Library::get` is called for incompatibly sized type such as named function
///   types (which are zero-sized).
pub mod r0_3_3 {}

/// Release 0.3.2 (2017-02-10)
///
/// * Minimum version required is now rustc 1.12.0;
/// * Updated dependency versions (most notably target_build_utils to 0.3.0)
pub mod r0_3_2 {}

/// Release 0.3.1 (2016-10-01)
///
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Send` where `T: Send`;
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Sync` where `T: Sync`;
/// * `Library` and `os::*::Library` now implement `Sync` (they were `Send` in 0.3.0 already).
pub mod r0_3_1 {}

/// Release 0.3.0 (2016-07-27)
///
/// * Greatly improved documentation, especially around platform-specific behaviours;
/// * Improved test suite by building our own library to test against;
/// * All `Library`-ies now implement `Send`.
/// * Added `impl From<os::platform::Library> for Library` and `impl From<Library> for
/// os::platform::Library` allowing wrapping and extracting the platform-specific library handle;
/// * Added methods to wrap (`Symbol::from_raw`) and unwrap (`Symbol::into_raw`) the safe `Symbol`
/// wrapper into unsafe `os::platform::Symbol`.
///
/// The last two additions focus on not restricting potential usecases of this library, allowing
/// users of the library to circumvent safety checks if need be.
///
/// ## Breaking Changes
///
/// `Library::new` defaults to `RTLD_NOW` instead of `RTLD_LAZY` on UNIX for more consistent
/// cross-platform behaviour. If a library loaded with `Library::new` had any linking errors, but
/// unresolved references weren’t forced to be resolved, the library would’ve “just worked”,
/// whereas now the call to `Library::new` will return an error signifying presence of such error.
///
/// ## os::platform
/// * Added `os::unix::Library::open` which allows specifying arbitrary flags (e.g. `RTLD_LAZY`);
/// * Added `os::windows::Library::get_ordinal` which allows finding a function or variable by its
/// ordinal number;
pub mod r0_3_0 {}
<commit_msg>Fill in the date in the changelog<commit_after>//! Project changelog

/// Release 0.6.0 (2020-04-05)
///
/// * Introduced a new method [`os::unix::Library::get_singlethreaded`];
/// * Added (untested) support for building when targetting Redox and Fuchsia;
/// * The APIs exposed by this library no longer panic and instead return an `Err` when it used
///   to panic.
///
/// ## Breaking changes
///
/// * Minimum required (stable) version of Rust to build this library is now 1.40.0;
/// * This crate now implements a custom [`Error`] type and all APIs now return this type rather
///   than returning the `std::io::Error`;
/// * `libloading::Result` has been removed;
/// * Removed the dependency on the C compiler to build this library on UNIX-like platforms.
///   `libloading` used to utilize a snippet written in C to work-around the unlikely possibility
///   of the target having a thread-unsafe implementation of the `dlerror` function. The effect of
///   the work-around was very opportunistic: it would not work if the function was called by
///   forgoing `libloading`.
///
///   Starting with 0.6.0, [`Library::get`] on platforms where `dlerror` is not MT-safe (such as
///   FreeBSD, DragonflyBSD or NetBSD) will unconditionally return an error when the underlying
///   `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary
///   consider using [`os::unix::Library::get_singlethreaded`] instead.
///
/// [`Library::get`]: crate::Library::get
/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded
/// [`Error`]: crate::Error
pub mod r0_6_0 {}

/// Release 0.5.2 (2019-07-07)
///
/// * Added API to convert OS-specific `Library` and `Symbol` conversion to underlying resources.
pub mod r0_5_2 {}

/// Release 0.5.1 (2019-06-01)
///
/// * Build on Haiku targets.
pub mod r0_5_1 {}

/// Release 0.5.0 (2018-01-11)
///
/// * Update to `winapi = ^0.3`;
///
/// ## Breaking changes
///
/// * libloading now requires a C compiler to build on UNIX;
///   * This is a temporary measure until the [`linkage`] attribute is stabilised;
///   * Necessary to resolve [#32].
///
/// [`linkage`]: https://github.com/rust-lang/rust/issues/29603
/// [#32]: https://github.com/nagisa/rust_libloading/issues/32
pub mod r0_5_0 {}

/// Release 0.4.3 (2017-12-07)
///
/// * Bump lazy-static dependency to `^1.0`;
/// * `cargo test --release` now works when testing libloading.
pub mod r0_4_3 {}

/// Release 0.4.2 (2017-09-24)
///
/// * Improved error and race-condition handling on Windows;
/// * Improved documentation about thread-safety of Library;
/// * Added `Symbol::<Option<T>::lift_option() -> Option<Symbol<T>>` convenience method.
pub mod r0_4_2 {}

/// Release 0.4.1 (2017-08-29)
///
/// * Solaris support
pub mod r0_4_1 {}

/// Release 0.4.0 (2017-05-01)
///
/// * Remove build-time dependency on target_build_utils (and by extension serde/phf);
/// * Require at least version 1.14.0 of rustc to build;
///   * Actually, it is cargo which has to be more recent here. The one shipped with rustc 1.14.0
///     is what’s being required from now on.
pub mod r0_4_0 {}

/// Release 0.3.4 (2017-03-25)
///
/// * Remove rogue println!
pub mod r0_3_4 {}

/// Release 0.3.3 (2017-03-25)
///
/// * Panics when `Library::get` is called for incompatibly sized type such as named function
///   types (which are zero-sized).
pub mod r0_3_3 {}

/// Release 0.3.2 (2017-02-10)
///
/// * Minimum version required is now rustc 1.12.0;
/// * Updated dependency versions (most notably target_build_utils to 0.3.0)
pub mod r0_3_2 {}

/// Release 0.3.1 (2016-10-01)
///
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Send` where `T: Send`;
/// * `Symbol<T>` and `os::*::Symbol<T>` now implement `Sync` where `T: Sync`;
/// * `Library` and `os::*::Library` now implement `Sync` (they were `Send` in 0.3.0 already).
pub mod r0_3_1 {}

/// Release 0.3.0 (2016-07-27)
///
/// * Greatly improved documentation, especially around platform-specific behaviours;
/// * Improved test suite by building our own library to test against;
/// * All `Library`-ies now implement `Send`.
/// * Added `impl From<os::platform::Library> for Library` and `impl From<Library> for
/// os::platform::Library` allowing wrapping and extracting the platform-specific library handle;
/// * Added methods to wrap (`Symbol::from_raw`) and unwrap (`Symbol::into_raw`) the safe `Symbol`
/// wrapper into unsafe `os::platform::Symbol`.
///
/// The last two additions focus on not restricting potential usecases of this library, allowing
/// users of the library to circumvent safety checks if need be.
///
/// ## Breaking Changes
///
/// `Library::new` defaults to `RTLD_NOW` instead of `RTLD_LAZY` on UNIX for more consistent
/// cross-platform behaviour. If a library loaded with `Library::new` had any linking errors, but
/// unresolved references weren’t forced to be resolved, the library would’ve “just worked”,
/// whereas now the call to `Library::new` will return an error signifying presence of such error.
///
/// ## os::platform
/// * Added `os::unix::Library::open` which allows specifying arbitrary flags (e.g. `RTLD_LAZY`);
/// * Added `os::windows::Library::get_ordinal` which allows finding a function or variable by its
/// ordinal number;
pub mod r0_3_0 {}
<|endoftext|>


<commit_before>use getopts::{Options,Matches};
use std::net::{TcpStream,SocketAddr};
use std::io::{BufStream,Write};
use std::old_io;

pub fn connect(matches: &Matches) {
    let host = matches.free.get(0).unwrap();
    let port = match matches.free.get(1).unwrap().parse::<u16>() {
        Ok(n) => { n }
        Err(_) => {
            panic!("not in possible range".to_string());
        }
    };
    match TcpStream::connect(&(host.as_slice(), port)) {
        Ok(stream) => {
            readwrite(&stream);
        },
        Err(f) => {
            // just exit
        }
    }
}

fn readwrite(stream: &TcpStream) {
    let mut buf_stream = BufStream::new(stream);
    let mut stdin_reader = old_io::stdin();
    let mut read_buf = [0, 4096];
    loop {
        match stream.peer_addr() {
            Ok(addr) => { /* */ },
            Err(f) => {
                // Hack for when other end closes socket, will exit.
                return;
            }
        }
        // Have to block here, so we can't responsively terminate if server closes socket.
        match stdin_reader.read(&mut read_buf) {
            Ok(n) => {
                buf_stream.write_all(&read_buf).unwrap();
                buf_stream.flush(); // overkill, probably
            },
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<commit_msg>Bugfix for connecter: write only n bytes. Otherwise we'll write stuff from the read_buf that we don't need to.<commit_after>use getopts::{Options,Matches};
use std::net::{TcpStream,SocketAddr};
use std::io::{BufStream,Write};
use std::old_io;

pub fn connect(matches: &Matches) {
    let host = matches.free.get(0).unwrap();
    let port = match matches.free.get(1).unwrap().parse::<u16>() {
        Ok(n) => { n }
        Err(_) => {
            panic!("not in possible range".to_string());
        }
    };
    match TcpStream::connect(&(host.as_slice(), port)) {
        Ok(stream) => {
            readwrite(&stream);
        },
        Err(f) => {
            // just exit
        }
    }
}

fn readwrite(stream: &TcpStream) {
    let mut buf_stream = BufStream::new(stream);
    let mut stdin_reader = old_io::stdin();
    let mut read_buf = [0, 4096];
    loop {
        match stream.peer_addr() {
            Ok(addr) => { /* */ },
            Err(f) => {
                // Hack for when other end closes socket, will exit.
                return;
            }
        }
        // Have to block here, so we can't responsively terminate if server closes socket.
        match stdin_reader.read(&mut read_buf) {
            Ok(n) => {
                buf_stream.write_all(&read_buf.slice_to(n)).unwrap();
                buf_stream.flush(); // overkill, probably
            },
            Err(f) => {
                panic!(f.to_string());
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::{ u32 };

use store::Store;
use store::Store::{ Array, Bitmap };

#[deriving(PartialEq)]
pub struct Container {
    key: u16,
    len: u16,
    store: Store,
}

impl Container {
    pub fn new(key: u16) -> Container {
        Container {
            key: key,
            len: 0,
            store: Array(Vec::new()),
        }
    }
}

impl Container {
    #[inline]
    pub fn key(&self) -> u16 { self.key }

    #[inline]
    pub fn len(&self) -> u16 { self.len }

    #[inline]
    pub fn insert(&mut self, index: u16) -> bool {
        if self.store.insert(index) {
            self.len += 1;
            if self.len == 4097 {
                self.store = self.store.to_bitmap();
            }
            true
        } else {
            false
        }
    }

    #[inline]
    pub fn remove(&mut self, index: u16) -> bool {
        if self.store.remove(index) {
            self.len -= 1;
            if self.len == 4096 {
                self.store = self.store.to_array();
            }
            true
        } else {
            false
        }
    }

    #[inline]
    pub fn contains(&self, index: u16) -> bool {
        self.store.contains(index)
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> Box<Iterator<u16> + 'a> {
        let result: Box<Iterator<u16> + 'a>;
        match self.store {
            Array(ref vec) => result = box vec.iter().map(|x| *x),
            Bitmap(ref bits) => result = box BitmapIter::new(bits),
        }
        result
    }

    #[inline]
    pub fn is_disjoint(&self, other: &Self) -> bool {
        self.store.is_disjoint(&other.store)
    }

    #[inline]
    pub fn is_subset(&self, other: &Self) -> bool {
        if self.len > other.len {
            false
        } else {
            self.store.is_subset(&other.store)
        }
    }

    #[inline]
    pub fn union_with(&mut self, other: &Self) {
        self.store.union_with(&other.store);
        self.len = self.store.len();
    }

    #[inline]
    pub fn min(&self) -> u16 {
        self.store.min()
    }

    #[inline]
    pub fn max(&self) -> u16 {
        self.store.max()
    }
}

struct BitmapIter<'a> {
    key: uint,
    bit: uint,
    bits: &'a [u32; 2048],
}

impl<'a> BitmapIter<'a> {
    fn new(bits: &'a [u32; 2048]) -> BitmapIter<'a> {
        BitmapIter {
            key: 0,
            bit: 0,
            bits: bits,
        }
    }
}

impl<'a> Iterator<u16> for BitmapIter<'a> {
    fn next(&mut self) -> Option<u16> {
        loop {
            if self.key == 2049 {
                break;
            }
            self.bit += 1;
            if self.bit == u32::BITS {
                self.bit = 0;
                self.key += 1;
            }
            if self.key == 2048 {
                break;
            }
            if (self.bits[self.key] & (1 << self.bit)) != 0 {
                break;
            }
        }
        if self.key == 2049 {
            None
        } else {
            Some((self.key * u32::BITS + self.bit) as u16)
        }
    }
}
<commit_msg>Alternative workaround for rust-lang/rust#20419<commit_after>use std::{ u32 };

use store::Store;
use store::Store::{ Array, Bitmap };

#[deriving(PartialEq)]
pub struct Container {
    key: u16,
    len: u16,
    store: Store,
}

impl Container {
    pub fn new(key: u16) -> Container {
        Container {
            key: key,
            len: 0,
            store: Array(Vec::new()),
        }
    }
}

impl Container {
    #[inline]
    pub fn key(&self) -> u16 { self.key }

    #[inline]
    pub fn len(&self) -> u16 { self.len }

    #[inline]
    pub fn insert(&mut self, index: u16) -> bool {
        if self.store.insert(index) {
            self.len += 1;
            if self.len == 4097 {
                self.store = self.store.to_bitmap();
            }
            true
        } else {
            false
        }
    }

    #[inline]
    pub fn remove(&mut self, index: u16) -> bool {
        if self.store.remove(index) {
            self.len -= 1;
            if self.len == 4096 {
                self.store = self.store.to_array();
            }
            true
        } else {
            false
        }
    }

    #[inline]
    pub fn contains(&self, index: u16) -> bool {
        self.store.contains(index)
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> Box<Iterator<u16> + 'a> {
        match self.store {
            Array(ref vec) => box vec.iter().map(|x| *x) as Box<Iterator<u16> + 'a>,
            Bitmap(ref bits) => box BitmapIter::new(bits) as Box<Iterator<u16> + 'a>,
        }
    }

    #[inline]
    pub fn is_disjoint(&self, other: &Self) -> bool {
        self.store.is_disjoint(&other.store)
    }

    #[inline]
    pub fn is_subset(&self, other: &Self) -> bool {
        if self.len > other.len {
            false
        } else {
            self.store.is_subset(&other.store)
        }
    }

    #[inline]
    pub fn union_with(&mut self, other: &Self) {
        self.store.union_with(&other.store);
        self.len = self.store.len();
    }

    #[inline]
    pub fn min(&self) -> u16 {
        self.store.min()
    }

    #[inline]
    pub fn max(&self) -> u16 {
        self.store.max()
    }
}

struct BitmapIter<'a> {
    key: uint,
    bit: uint,
    bits: &'a [u32; 2048],
}

impl<'a> BitmapIter<'a> {
    fn new(bits: &'a [u32; 2048]) -> BitmapIter<'a> {
        BitmapIter {
            key: 0,
            bit: 0,
            bits: bits,
        }
    }
}

impl<'a> Iterator<u16> for BitmapIter<'a> {
    fn next(&mut self) -> Option<u16> {
        loop {
            if self.key == 2049 {
                break;
            }
            self.bit += 1;
            if self.bit == u32::BITS {
                self.bit = 0;
                self.key += 1;
            }
            if self.key == 2048 {
                break;
            }
            if (self.bits[self.key] & (1 << self.bit)) != 0 {
                break;
            }
        }
        if self.key == 2049 {
            None
        } else {
            Some((self.key * u32::BITS + self.bit) as u16)
        }
    }
}
<|endoftext|>


<commit_before>use ffi::h5g::{H5G_info_t, H5Gget_info, H5Gcreate2, H5Gopen2};
use ffi::h5l::{H5Lmove, H5L_SAME_LOC};
use ffi::h5p::H5P_DEFAULT;

use error::Result;
use group::Group;
use location::Location;
use object::Object;
use util::string_to_cstr;

use std::default::Default;

pub trait Container: Location {
    #[doc(hidden)]
    fn group_info(&self) -> Result<H5G_info_t> {
        let info: *mut H5G_info_t = &mut H5G_info_t::default();
        h5call!(H5Gget_info(self.id(), info)).and(Ok(unsafe { *info }))
    }

    /// Returns the number of objects in the container (0 if the container is invalid).
    fn len(&self) -> u64 {
        self.group_info().map(|info| info.nlinks).unwrap_or(0)
    }

    /// Create a new group in a container which can be a file or another group.
    fn create_group<S: Into<String>>(&self, name: S) -> Result<Group> {
        Ok(Group::from_id(h5try!(H5Gcreate2(
            self.id(), string_to_cstr(name), H5P_DEFAULT, 0, H5P_DEFAULT))))
    }

    /// Opens an existing group in a container which can be a file or another group.
    fn group<S: Into<String>>(&self, name: S) -> Result<Group> {
        Ok(Group::from_id(h5try!(H5Gopen2(
            self.id(), string_to_cstr(name), H5P_DEFAULT))))
    }

    /// Relinks an object. Note: `from` and `to` are relative to the current object.
    fn relink<S1: Into<String>, S2: Into<String>>(&self, name: S1, path: S2) -> Result<()> {
        h5call!(H5Lmove(self.id(), string_to_cstr(name), H5L_SAME_LOC,
                        string_to_cstr(path), H5P_DEFAULT, H5P_DEFAULT)).and(Ok(()))
    }
}

#[cfg(test)]
mod tests {
    use error::silence_errors;
    use test::with_tmp_file;
    use super::Container;
    use location::Location;
    use object::Object;

    #[test]
    pub fn test_group() {
        silence_errors();
        with_tmp_file(|file| {
            assert_err!(file.group("a"), "unable to open group: object 'a' doesn't exist");
            file.create_group("a");
            let a = file.group("a").unwrap();
            assert!(a.name() == "/a");
            assert!(a.file().id() == file.id());
            a.create_group("b");
            let b = file.group("/a/b").unwrap();
            assert!(b.name() == "/a/b");
            assert!(b.file().id() == file.id());
        })
    }

    #[test]
    pub fn test_len() {
        with_tmp_file(|file| {
            assert_eq!(file.len(), 0);
            file.create_group("foo").unwrap();
            assert_eq!(file.len(), 1);
            assert_eq!(file.group("foo").unwrap().len(), 0);
            file.create_group("bar").unwrap().create_group("baz").unwrap();
            assert_eq!(file.len(), 2);
            assert_eq!(file.group("bar").unwrap().len(), 1);
            assert_eq!(file.group("/bar/baz").unwrap().len(), 0);
        })
    }

    #[test]
    pub fn test_relink() {
        silence_errors();
        with_tmp_file(|file| {
            file.create_group("test").unwrap();
            file.group("test").unwrap();
            assert_err!(file.relink("test", "foo/test"),
                        "unable to move link: component not found");
            file.create_group("foo").unwrap();
            assert_err!(file.relink("bar", "/baz"),
                        "unable to move link: name doesn't exist");
            file.relink("test", "/foo/test").unwrap();
            file.group("/foo/test").unwrap();
            assert_err!(file.group("test"),
                        "unable to open group: object 'test' doesn't exist");
        })
    }
}
<commit_msg>Fix tests on Linux<commit_after>use ffi::h5g::{H5G_info_t, H5Gget_info, H5Gcreate2, H5Gopen2};
use ffi::h5l::{H5Lmove, H5L_SAME_LOC};
use ffi::h5p::H5P_DEFAULT;

use error::Result;
use group::Group;
use location::Location;
use object::Object;
use util::string_to_cstr;

use std::default::Default;

pub trait Container: Location {
    #[doc(hidden)]
    fn group_info(&self) -> Result<H5G_info_t> {
        let info: *mut H5G_info_t = &mut H5G_info_t::default();
        h5call!(H5Gget_info(self.id(), info)).and(Ok(unsafe { *info }))
    }

    /// Returns the number of objects in the container (0 if the container is invalid).
    fn len(&self) -> u64 {
        self.group_info().map(|info| info.nlinks).unwrap_or(0)
    }

    /// Create a new group in a container which can be a file or another group.
    fn create_group<S: Into<String>>(&self, name: S) -> Result<Group> {
        Ok(Group::from_id(h5try!(H5Gcreate2(
            self.id(), string_to_cstr(name), H5P_DEFAULT, 0, H5P_DEFAULT))))
    }

    /// Opens an existing group in a container which can be a file or another group.
    fn group<S: Into<String>>(&self, name: S) -> Result<Group> {
        Ok(Group::from_id(h5try!(H5Gopen2(
            self.id(), string_to_cstr(name), H5P_DEFAULT))))
    }

    /// Relinks an object. Note: `from` and `to` are relative to the current object.
    fn relink<S1: Into<String>, S2: Into<String>>(&self, name: S1, path: S2) -> Result<()> {
        h5call!(H5Lmove(self.id(), string_to_cstr(name), H5L_SAME_LOC,
                        string_to_cstr(path), H5P_DEFAULT, H5P_DEFAULT)).and(Ok(()))
    }
}

#[cfg(test)]
mod tests {
    use error::silence_errors;
    use test::with_tmp_file;
    use super::Container;
    use location::Location;
    use object::Object;

    #[test]
    pub fn test_group() {
        silence_errors();
        with_tmp_file(|file| {
            assert_err!(file.group("a"), "unable to open group: object.+doesn't exist");
            file.create_group("a");
            let a = file.group("a").unwrap();
            assert!(a.name() == "/a");
            assert!(a.file().id() == file.id());
            a.create_group("b");
            let b = file.group("/a/b").unwrap();
            assert!(b.name() == "/a/b");
            assert!(b.file().id() == file.id());
        })
    }

    #[test]
    pub fn test_len() {
        with_tmp_file(|file| {
            assert_eq!(file.len(), 0);
            file.create_group("foo").unwrap();
            assert_eq!(file.len(), 1);
            assert_eq!(file.group("foo").unwrap().len(), 0);
            file.create_group("bar").unwrap().create_group("baz").unwrap();
            assert_eq!(file.len(), 2);
            assert_eq!(file.group("bar").unwrap().len(), 1);
            assert_eq!(file.group("/bar/baz").unwrap().len(), 0);
        })
    }

    #[test]
    pub fn test_relink() {
        silence_errors();
        with_tmp_file(|file| {
            file.create_group("test").unwrap();
            file.group("test").unwrap();
            assert_err!(file.relink("test", "foo/test"),
                        "unable to move link: component not found");
            file.create_group("foo").unwrap();
            assert_err!(file.relink("bar", "/baz"),
                        "unable to move link: name doesn't exist");
            file.relink("test", "/foo/test").unwrap();
            file.group("/foo/test").unwrap();
            assert_err!(file.group("test"),
                        "unable to open group: object.+doesn't exist");
        })
    }
}
<|endoftext|>


<commit_before>pub use self::close::close;
pub use self::data::data;
pub use self::init::init;

use std::collections::HashMap;
use std::sync::Mutex;

lazy_static! {
    pub static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

pub static OK: i8 = 0;
pub static ERR_INVALID: i8 = -1;
pub static ERR_HTSI: i8 = -128;

mod init;
mod data;
mod close;
<commit_msg>include StatusCode in mod setup - remove static i8 for used CTAPI status<commit_after>pub use self::close::close;
pub use self::data::data;
pub use self::init::init;
pub use self::status::StatusCode;

use std::collections::HashMap;
use std::sync::Mutex;

lazy_static! {
    pub static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

mod close;
mod data;
mod init;
mod status;<|endoftext|>