<commit_before>use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use semver;
use git2;
use serde_json;

use app::App;
use dependency::Kind;
use util::{CargoResult, internal};

#[derive(Serialize, Deserialize, Debug)]
pub struct Crate {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<Kind>,
}

fn index_file(base: &Path, name: &str) -> PathBuf {
    let name = name.chars()
        .flat_map(|c| c.to_lowercase())
        .collect::<String>();
    match name.len() {
        1 => base.join("1").join(&name),
        2 => base.join("2").join(&name),
        3 => base.join("3").join(&name[..1]).join(&name),
        _ => base.join(&name[0..2]).join(&name[2..4]).join(&name),
    }
}

pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo = &*repo;
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, &krate.name);

    commit_and_push(repo, || {
        // Add the crate to its relevant file
        fs::create_dir_all(dst.parent().unwrap())?;
        let mut prev = String::new();
        if fs::metadata(&dst).is_ok() {
            File::open(&dst).and_then(
                |mut f| f.read_to_string(&mut prev),
            )?;
        }
        let s = serde_json::to_string(krate).unwrap();
        let new = prev + &s;
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!("Updating crate `{}#{}`", krate.name, krate.vers),
            dst.clone(),
        ))
    })
}

/// Yanks or unyanks a crate version. This requires finding the index
/// file, deserlialise the crate from JSON, change the yank boolean to
/// `true` or `false`, write all the lines back out, and commit and
/// push the changes.
// TODO: factor out the tasks this function does into smaller, separate
// functions.
pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, krate);

    commit_and_push(&repo, || {
        let mut prev = String::new();
        File::open(&dst).and_then(
            |mut f| f.read_to_string(&mut prev),
        )?;
        let new = prev.lines()
            .map(|line| {
                let mut git_crate = serde_json::from_str::<Crate>(line).map_err(|_| {
                    internal(&format_args!("couldn't decode: `{}`", line))
                })?;
                if git_crate.name != krate || git_crate.vers != version.to_string() {
                    return Ok(line.to_string());
                }
                git_crate.yanked = Some(yanked);
                Ok(serde_json::to_string(&git_crate).unwrap())
            })
            .collect::<CargoResult<Vec<String>>>();
        let new = new?.join("\n");
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!(
                "{} crate `{}#{}`",
                if yanked { "Yanking" } else { "Unyanking" },
                krate,
                version
            ),
            dst.clone(),
        ))
    })
}

fn commit_and_push<F>(repo: &git2::Repository, mut f: F) -> CargoResult<()>
where
    F: FnMut() -> CargoResult<(String, PathBuf)>,
{
    let repo_path = repo.workdir().unwrap();

    // Attempt to commit in a loop. It's possible that we're going to need to
    // rebase our repository, and after that it's possible that we're going to
    // race to commit the changes. For now we just cap out the maximum number of
    // retries at a fixed number.
    for _ in 0..20 {
        let (msg, dst) = f()?;

        // git add $file
        let mut index = repo.index()?;
        let mut repo_path = repo_path.iter();
        let dst = dst.iter()
            .skip_while(|s| Some(*s) == repo_path.next())
            .collect::<PathBuf>();
        index.add_path(&dst)?;
        index.write()?;
        let tree_id = index.write_tree()?;
        let tree = repo.find_tree(tree_id)?;

        // git commit -m "..."
        let head = repo.head()?;
        let parent = repo.find_commit(head.target().unwrap())?;
        let sig = repo.signature()?;
        repo.commit(
            Some("HEAD"),
            &sig,
            &sig,
            &msg,
            &tree,
            &[&parent],
        )?;

        // git push
        let mut ref_status = None;
        let mut origin = repo.find_remote("origin")?;
        let res = {
            let mut callbacks = git2::RemoteCallbacks::new();
            callbacks.credentials(credentials);
            callbacks.push_update_reference(|refname, status| {
                assert_eq!(refname, "refs/heads/master");
                ref_status = status.map(|s| s.to_string());
                Ok(())
            });
            let mut opts = git2::PushOptions::new();
            opts.remote_callbacks(callbacks);
            origin.push(&["refs/heads/master"], Some(&mut opts))
        };
        match res {
            Ok(()) if ref_status.is_none() => return Ok(()),
            Ok(()) => info!("failed to push a ref: {:?}", ref_status),
            Err(e) => info!("failure to push: {}", e),
        }

        let mut callbacks = git2::RemoteCallbacks::new();
        callbacks.credentials(credentials);
        origin.update_tips(
            Some(&mut callbacks),
            true,
            git2::AutotagOption::Unspecified,
            None,
        )?;

        // Ok, we need to update, so fetch and reset --hard
        origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?;
        let head = repo.head()?.target().unwrap();
        let obj = repo.find_object(head, None)?;
        repo.reset(&obj, git2::ResetType::Hard, None)?;
    }

    Err(internal("Too many rebase failures"))
}

pub fn credentials(
    _user: &str,
    _user_from_url: Option<&str>,
    _cred: git2::CredentialType,
) -> Result<git2::Cred, git2::Error> {
    match (env::var("GIT_HTTP_USER"), env::var("GIT_HTTP_PWD")) {
        (Ok(u), Ok(p)) => git2::Cred::userpass_plaintext(&u, &p),
        _ => Err(git2::Error::from_str("no authentication set")),
    }
}
<commit_msg>Add documentation comments for commit_and_push() function<commit_after>use std::collections::HashMap;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use semver;
use git2;
use serde_json;

use app::App;
use dependency::Kind;
use util::{CargoResult, internal};

#[derive(Serialize, Deserialize, Debug)]
pub struct Crate {
    pub name: String,
    pub vers: String,
    pub deps: Vec<Dependency>,
    pub cksum: String,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: Option<bool>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Dependency {
    pub name: String,
    pub req: String,
    pub features: Vec<String>,
    pub optional: bool,
    pub default_features: bool,
    pub target: Option<String>,
    pub kind: Option<Kind>,
}

fn index_file(base: &Path, name: &str) -> PathBuf {
    let name = name.chars()
        .flat_map(|c| c.to_lowercase())
        .collect::<String>();
    match name.len() {
        1 => base.join("1").join(&name),
        2 => base.join("2").join(&name),
        3 => base.join("3").join(&name[..1]).join(&name),
        _ => base.join(&name[0..2]).join(&name[2..4]).join(&name),
    }
}

pub fn add_crate(app: &App, krate: &Crate) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo = &*repo;
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, &krate.name);

    commit_and_push(repo, || {
        // Add the crate to its relevant file
        fs::create_dir_all(dst.parent().unwrap())?;
        let mut prev = String::new();
        if fs::metadata(&dst).is_ok() {
            File::open(&dst).and_then(
                |mut f| f.read_to_string(&mut prev),
            )?;
        }
        let s = serde_json::to_string(krate).unwrap();
        let new = prev + &s;
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!("Updating crate `{}#{}`", krate.name, krate.vers),
            dst.clone(),
        ))
    })
}

/// Yanks or unyanks a crate version. This requires finding the index
/// file, deserlialise the crate from JSON, change the yank boolean to
/// `true` or `false`, write all the lines back out, and commit and
/// push the changes.
pub fn yank(app: &App, krate: &str, version: &semver::Version, yanked: bool) -> CargoResult<()> {
    let repo = app.git_repo.lock().unwrap();
    let repo_path = repo.workdir().unwrap();
    let dst = index_file(repo_path, krate);

    commit_and_push(&repo, || {
        let mut prev = String::new();
        File::open(&dst).and_then(
            |mut f| f.read_to_string(&mut prev),
        )?;
        let new = prev.lines()
            .map(|line| {
                let mut git_crate = serde_json::from_str::<Crate>(line).map_err(|_| {
                    internal(&format_args!("couldn't decode: `{}`", line))
                })?;
                if git_crate.name != krate || git_crate.vers != version.to_string() {
                    return Ok(line.to_string());
                }
                git_crate.yanked = Some(yanked);
                Ok(serde_json::to_string(&git_crate).unwrap())
            })
            .collect::<CargoResult<Vec<String>>>();
        let new = new?.join("\n");
        let mut f = File::create(&dst)?;
        f.write_all(new.as_bytes())?;
        f.write_all(b"\n")?;

        Ok((
            format!(
                "{} crate `{}#{}`",
                if yanked { "Yanking" } else { "Unyanking" },
                krate,
                version
            ),
            dst.clone(),
        ))
    })
}

/// Commits and pushes to the crates.io index.
///
/// There are currently 2 instances of the crates.io backend running
/// on Heroku, and they race against each other e.g. if 2 pushes occur,
/// then one will succeed while the other will need to be rebased before
/// being pushed.
///
/// A maximum of 20 attempts to commit and push to the index currently
/// accounts for the amount of traffic publishing crates, though this will
/// eventually need to be changed past a certain point.
///
/// Notes:
/// Currently, this function is called from the HTTP thread and is blocking.
/// This could be changed to run from a different thread and use a callback
/// upon completion to the HTTP thread.
fn commit_and_push<F>(repo: &git2::Repository, mut f: F) -> CargoResult<()>
where
    F: FnMut() -> CargoResult<(String, PathBuf)>,
{
    let repo_path = repo.workdir().unwrap();

    // Attempt to commit in a loop. It's possible that we're going to need to
    // rebase our repository, and after that it's possible that we're going to
    // race to commit the changes. For now we just cap out the maximum number of
    // retries at a fixed number.
    for _ in 0..20 {
        let (msg, dst) = f()?;

        // git add $file
        let mut index = repo.index()?;
        let mut repo_path = repo_path.iter();
        let dst = dst.iter()
            .skip_while(|s| Some(*s) == repo_path.next())
            .collect::<PathBuf>();
        index.add_path(&dst)?;
        index.write()?;
        let tree_id = index.write_tree()?;
        let tree = repo.find_tree(tree_id)?;

        // git commit -m "..."
        let head = repo.head()?;
        let parent = repo.find_commit(head.target().unwrap())?;
        let sig = repo.signature()?;
        repo.commit(
            Some("HEAD"),
            &sig,
            &sig,
            &msg,
            &tree,
            &[&parent],
        )?;

        // git push
        let mut ref_status = None;
        let mut origin = repo.find_remote("origin")?;
        let res = {
            let mut callbacks = git2::RemoteCallbacks::new();
            callbacks.credentials(credentials);
            callbacks.push_update_reference(|refname, status| {
                assert_eq!(refname, "refs/heads/master");
                ref_status = status.map(|s| s.to_string());
                Ok(())
            });
            let mut opts = git2::PushOptions::new();
            opts.remote_callbacks(callbacks);
            origin.push(&["refs/heads/master"], Some(&mut opts))
        };
        match res {
            Ok(()) if ref_status.is_none() => return Ok(()),
            Ok(()) => info!("failed to push a ref: {:?}", ref_status),
            Err(e) => info!("failure to push: {}", e),
        }

        let mut callbacks = git2::RemoteCallbacks::new();
        callbacks.credentials(credentials);
        origin.update_tips(
            Some(&mut callbacks),
            true,
            git2::AutotagOption::Unspecified,
            None,
        )?;

        // Ok, we need to update, so fetch and reset --hard
        origin.fetch(&["refs/heads/*:refs/heads/*"], None, None)?;
        let head = repo.head()?.target().unwrap();
        let obj = repo.find_object(head, None)?;
        repo.reset(&obj, git2::ResetType::Hard, None)?;
    }

    Err(internal("Too many rebase failures"))
}

pub fn credentials(
    _user: &str,
    _user_from_url: Option<&str>,
    _cred: git2::CredentialType,
) -> Result<git2::Cred, git2::Error> {
    match (env::var("GIT_HTTP_USER"), env::var("GIT_HTTP_PWD")) {
        (Ok(u), Ok(p)) => git2::Cred::userpass_plaintext(&u, &p),
        _ => Err(git2::Error::from_str("no authentication set")),
    }
}
<|endoftext|>


<commit_before>//! Parse and read Elma level files.

use std::io::{ Cursor, Read, Write };
use std::fs::File;
use std::ffi::CString;
use byteorder::{ ReadBytesExt, WriteBytesExt, LittleEndian };
use super::{ cstring_read, Position, read_n };
use super::rand::Rng;

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: u32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: u32 = 0x00845D52;

/// Type of object.
pub enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

/// Object struct. Every level requires one ObjectType::Player Object and at least one ObjectType::Exit Object.
pub struct Object {
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Type of Object, see ObjectType.
    pub object_type: ObjectType,
    /// Applies to ObjectType::Apple only.
    ///
    /// 0 = normal
    /// 1 = gravity up
    /// 2 = gravity down
    /// 3 = gravity left
    /// 4 = gravity right
    // TODO: enum with gravity
    pub gravity: u32,
    /// Applies to ObjectType::Apple only. Valid values are 1 to 9.
    pub animation: u32
}

/// Polygon struct.
#[derive(Debug, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Polygon {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture struct.
pub struct Picture {
    /// Picture name.
    pub name: CString,
    /// Texture name.
    pub texture: CString,
    /// Mask name.
    pub mask: CString,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: u32,
    /// Clipping.
    ///
    /// 0 = unclipped
    /// 1 = ground
    /// 2 = sky
    // TODO: make enum
    pub clip: u32
}

/// Level struct that contains all level information.
pub struct Level {
    /// Elma or Across level.
    pub version: String,
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Random number that links level file to replay files.
    pub link: u32,
    /// Contains four integrity checks (See create_integrity()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: CString,
    /// LGR file name.
    pub lgr: CString,
    /// Ground texture name.
    pub ground: CString,
    /// Sky texture name.
    pub sky: CString,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Level {
        Level {
            version: "Elma".to_string(),
            raw: vec![],
            link: 0,
            integrity: [0.0f64; 4],
            name: CString::new("").unwrap(),
            lgr: CString::new("default").unwrap(),
            ground: CString::new("ground").unwrap(),
            sky: CString::new("sky").unwrap(),
            polygons: vec![],
            objects: vec![],
            pictures: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test.lev");
    /// ```
    pub fn load_level (filename: &str) -> Level {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let mut buffer = Cursor::new(&self.raw);
        let mut _data :Vec<u8>;

        // Elma = POT14, Across = POT06.
        // TODO: make Across compatible in 2025.
        let version = read_n(&mut buffer, 5);
        self.version = match version.as_slice() {
            [80, 79, 84, 49, 52] => "Elma".to_string(),
            [80, 79, 84, 48, 54] => "Across".to_string(),
            _ => panic!("Not a valid level file.")
        };

        // Link.
        _data = read_n(&mut buffer, 2); // Never used
        self.link = buffer.read_u32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = buffer.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        self.name = cstring_read(read_n(&mut buffer, 51));
        // LGR name.
        self.lgr = cstring_read(read_n(&mut buffer, 16));
        // Ground texture name.
        self.ground = cstring_read(read_n(&mut buffer, 10));
        // Sky texture name.
        self.sky = cstring_read(read_n(&mut buffer, 10));

        // Polygons.
        let poly_count = (buffer.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as u16;
        for _ in 0..poly_count {
            let grass = buffer.read_u32::<LittleEndian>().unwrap() > 0;
            let vertex_count = buffer.read_u32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = buffer.read_f64::<LittleEndian>().unwrap();
                let y = buffer.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (buffer.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as u16;
        for _ in 0..object_count {
            let x = buffer.read_f64::<LittleEndian>().unwrap();
            let y = buffer.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = match buffer.read_u32::<LittleEndian>().unwrap() {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple,
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type")
            };
            let gravity = buffer.read_u32::<LittleEndian>().unwrap();
            let animation = buffer.read_u32::<LittleEndian>().unwrap();

            self.objects.push(Object {
                position: position,
                object_type: object_type,
                gravity: gravity,
                animation: animation
            });
        }

        // Pictures.
        let picture_count = (buffer.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as u16;
        for _ in 0..picture_count {
            let name = cstring_read(read_n(&mut buffer, 10));
            let texture = cstring_read(read_n(&mut buffer, 10));
            let mask = cstring_read(read_n(&mut buffer, 10));
            let x = buffer.read_f64::<LittleEndian>().unwrap();
            let y = buffer.read_f64::<LittleEndian>().unwrap();
            let distance = buffer.read_u32::<LittleEndian>().unwrap();
            let clip = buffer.read_u32::<LittleEndian>().unwrap();

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = buffer.read_u32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }
    }

    /// Combines the Level struct fields to generate the raw binary data.
    fn convert_to_raw (&self) {
        // TODO: convert
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.convert_to_raw();
        self.raw
    }

    /// Saves level as a file.
    pub fn save_lev (self, filename: &str) {
        self.convert_to_raw();
        let mut file = File::create(&filename).unwrap();
        // TODO: write stuff.
    }
}
<commit_msg>Add some preliminary top10 entry struct<commit_after>//! Read and write Elma level files.

use std::io::{ Cursor, Read, Write };
use std::fs::File;
use std::ffi::CString;
use byteorder::{ ReadBytesExt, WriteBytesExt, LittleEndian };
use super::{ cstring_read, Position, read_n };
use super::rand::Rng;

// Magic arbitrary number; signifies end-of-data. Followed by Top10 list(s).
const EOD: u32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: u32 = 0x00845D52;

/// Type of object.
pub enum ObjectType {
    Apple,
    Exit,
    Killer,
    Player
}

/// Object struct. Every level requires one ObjectType::Player Object and at least one ObjectType::Exit Object.
pub struct Object {
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Type of Object, see ObjectType.
    pub object_type: ObjectType,
    /// Applies to ObjectType::Apple only.
    ///
    /// 0 = normal
    /// 1 = gravity up
    /// 2 = gravity down
    /// 3 = gravity left
    /// 4 = gravity right
    // TODO: enum with gravity
    pub gravity: u32,
    /// Applies to ObjectType::Apple only. Valid values are 1 to 9.
    pub animation: u32
}

/// Polygon struct.
#[derive(Debug, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Polygon {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture struct.
pub struct Picture {
    /// Picture name.
    pub name: CString,
    /// Texture name.
    pub texture: CString,
    /// Mask name.
    pub mask: CString,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: u32,
    /// Clipping.
    ///
    /// 0 = unclipped
    /// 1 = ground
    /// 2 = sky
    // TODO: make enum
    pub clip: u32
}

/// Top10 list entry struct.
pub struct ListEntry {
    /// Player name.
    pub name: CString,
    /// Time.
    pub time: f64
}

/// Level struct that contains all level information.
pub struct Level {
    /// Elma or Across level.
    pub version: String,
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Random number that links level file to replay files.
    pub link: u32,
    /// Contains four integrity checks (See create_integrity()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: CString,
    /// LGR file name.
    pub lgr: CString,
    /// Ground texture name.
    pub ground: CString,
    /// Sky texture name.
    pub sky: CString,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Level {
        Level {
            version: "Elma".to_string(),
            raw: vec![],
            link: 0,
            integrity: [0.0f64; 4],
            name: CString::new("").unwrap(),
            lgr: CString::new("default").unwrap(),
            ground: CString::new("ground").unwrap(),
            sky: CString::new("sky").unwrap(),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test.lev");
    /// ```
    pub fn load_level (filename: &str) -> Level {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let mut buffer = Cursor::new(&self.raw);
        let mut _data :Vec<u8>;

        // Elma = POT14, Across = POT06.
        // TODO: make Across compatible in 2025.
        let version = read_n(&mut buffer, 5);
        self.version = match version.as_slice() {
            [80, 79, 84, 49, 52] => "Elma".to_string(),
            [80, 79, 84, 48, 54] => "Across".to_string(),
            _ => panic!("Not a valid level file.")
        };

        // Link.
        _data = read_n(&mut buffer, 2); // Never used
        self.link = buffer.read_u32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = buffer.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        self.name = cstring_read(read_n(&mut buffer, 51));
        // LGR name.
        self.lgr = cstring_read(read_n(&mut buffer, 16));
        // Ground texture name.
        self.ground = cstring_read(read_n(&mut buffer, 10));
        // Sky texture name.
        self.sky = cstring_read(read_n(&mut buffer, 10));

        // Polygons.
        let poly_count = (buffer.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as u16;
        for _ in 0..poly_count {
            let grass = buffer.read_u32::<LittleEndian>().unwrap() > 0;
            let vertex_count = buffer.read_u32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = buffer.read_f64::<LittleEndian>().unwrap();
                let y = buffer.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (buffer.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as u16;
        for _ in 0..object_count {
            let x = buffer.read_f64::<LittleEndian>().unwrap();
            let y = buffer.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = match buffer.read_u32::<LittleEndian>().unwrap() {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple,
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type")
            };
            let gravity = buffer.read_u32::<LittleEndian>().unwrap();
            let animation = buffer.read_u32::<LittleEndian>().unwrap();

            self.objects.push(Object {
                position: position,
                object_type: object_type,
                gravity: gravity,
                animation: animation
            });
        }

        // Pictures.
        let picture_count = (buffer.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as u16;
        for _ in 0..picture_count {
            let name = cstring_read(read_n(&mut buffer, 10));
            let texture = cstring_read(read_n(&mut buffer, 10));
            let mask = cstring_read(read_n(&mut buffer, 10));
            let x = buffer.read_f64::<LittleEndian>().unwrap();
            let y = buffer.read_f64::<LittleEndian>().unwrap();
            let distance = buffer.read_u32::<LittleEndian>().unwrap();
            let clip = buffer.read_u32::<LittleEndian>().unwrap();

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = buffer.read_u32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // Top10 single-player list.
        // TODO: do it

        // Top10 multi-player list.
        // TODO: do it
    }

    /// Combines the Level struct fields to generate the raw binary data.
    fn convert_to_raw (&self) {
        // TODO: convert
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.convert_to_raw();
        self.raw
    }

    /// Saves level as a file.
    pub fn save_lev (self, filename: &str) {
        self.convert_to_raw();
        let mut file = File::create(&filename).unwrap();
        // TODO: write stuff.
    }
}
<|endoftext|>


<commit_before>//! Ergonomic, checked cast functions for primitive types
//!
//! This crate provides one checked cast function for each numeric primitive. Use these functions
//! to perform a cast from any other numeric primitive:
//!
//! ```
//! extern crate cast;
//!
//! use cast::{u8, u16, Error};
//!
//! # fn main() {
//! // Infallible operations, like integer promotion, are equivalent to a normal cast with `as`
//! assert_eq!(u16(0u8), 0u16);
//!
//! // Everything else will return a `Result` depending on the success of the operation
//! assert_eq!(u8(0u16), Ok(0u8));
//! assert_eq!(u8(256u16), Err(Error::Overflow));
//! assert_eq!(u8(-1i8), Err(Error::Underflow));
//! assert_eq!(u8(1. / 0.), Err(Error::Infinite));
//! assert_eq!(u8(0. / 0.), Err(Error::NaN));
//! # }
//! ```
//!
//! There are no namespace problems between these functions, the "primitive modules" in `core`/`std`
//! and the built-in primitive types, so all them can be in the same scope:
//!
//! ```
//! extern crate cast;
//!
//! use std::u8;
//! use cast::{u8, u16};
//!
//! # fn main() {
//! // `u8` as a type
//! let x: u8 = 0;
//! // `u8` as a module
//! let y = u16(u8::MAX);
//! // `u8` as a function
//! let z = u8(y).unwrap();
//! # }
//! ```
//!
//! The checked cast functionality is also usable with type aliases via the `cast` static method:
//!
//! ```
//! extern crate cast;
//!
//! use std::os::raw::c_ulonglong;
//! // NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311
//! use cast::From as _0;
//!
//!
//! # fn main() {
//! assert_eq!(c_ulonglong::cast(0u8), 0u64);
//! # }
//! ```
//!
//! This crate also provides a `From` trait that can be used, for example, to create a generic
//! function that accepts any type that can be infallibly casted to `u32`.
//!
//! ```
//! extern crate cast;
//!
//! fn to_u32<T>(x: T) -> u32
//!     // reads as: "where u32 can be casted from T with output u32"
//!     where u32: cast::From<T, Output=u32>,
//! {
//!     cast::u32(x)
//! }
//!
//! # fn main() {
//! assert_eq!(to_u32(0u8), 0u32);
//! assert_eq!(to_u32(1u16), 1u32);
//! assert_eq!(to_u32(2u32), 2u32);
//!
//! // to_u32(-1i32);  // Compile error
//! # }
//! ```
//!

#![deny(missing_docs)]
#![deny(warnings)]
#![allow(const_err)]
#![no_std]

#![cfg_attr(all(feature = "unstable", test), feature(plugin))]
#![cfg_attr(all(feature = "unstable", test), plugin(quickcheck_macros))]

#[cfg(all(feature = "unstable", test))]
extern crate quickcheck;

#[cfg(test)]
mod test;

/// Cast errors
#[derive(Debug, PartialEq)]
pub enum Error {
    /// Infinite value casted to a type that can only represent finite values
    Infinite,
    /// NaN value casted to a type that can't represent a NaN value
    NaN,
    /// Source value is greater than the maximum value that the destination type can hold
    Overflow,
    /// Source value is smaller than the minimum value that the destination type can hold
    Underflow,
}

/// The "cast from" operation
pub trait From<Src> {
    /// The result of the cast operation: either `Self` or `Result<Self, Error>`
    type Output;

    /// Checked cast from `Src` to `Self`
    fn cast(Src) -> Self::Output;
}

macro_rules! fns {
    ($($ty:ident),+) => {
        $(
            /// Checked cast function
            pub fn $ty<T>(x: T) -> <$ty as From<T>>::Output
                where $ty: From<T>
            {
                <$ty as From<T>>::cast(x)
            }
         )+
    }
}

fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);

/// `$dst` can hold any value of `$src`
macro_rules! promotion {
    ($($src:ty => $($dst: ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = $dst;

                    fn cast(src: $src) -> $dst {
                        src as $dst
                    }
                }
            )+
        )+
    }
}

/// `$dst` can hold any positive value of `$src`
macro_rules! half_promotion {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    fn cast(src: $src) -> Self::Output {
                        if src < 0 {
                            Err(Error::Underflow)
                        } else {
                            Ok(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

/// From an unsigned `$src` to a smaller `$dst`
macro_rules! from_unsigned {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    fn cast(src: $src) -> Self::Output {
                        use core::$dst;

                        if src > $dst::MAX as $src {
                            Err(Error::Overflow)
                        } else {
                            Ok(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

/// From a signed `$src` to a smaller `$dst`
macro_rules! from_signed {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    fn cast(src: $src) -> Self::Output {
                        use core::$dst;

                        Err(if src < $dst::MIN as $src {
                            Error::Underflow
                        } else if src > $dst::MAX as $src {
                            Error::Overflow
                        } else {
                            return Ok(src as $dst);
                        })
                    }
                }
            )+
        )+
    }
}

/// From a float `$src` to an integer `$dst`
macro_rules! from_float {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    fn cast(src: $src) -> Self::Output {
                        use core::{$dst, $src};

                        Err(if src != src {
                            Error::NaN
                        } else if src == $src::INFINITY || src == $src::NEG_INFINITY {
                            Error::Infinite
                        } else if src < $dst::MIN as $src {
                            Error::Underflow
                        } else if src > $dst::MAX as $src {
                            Error::Overflow
                        } else {
                            return Ok(src as $dst);
                        })
                    }
                }
            )+
        )+
    }
}

// PLAY TETRIS! ;-)

#[cfg(target_pointer_width = "32")]
mod _32 {
    use {Error, From};

    // Signed
    promotion! {
        i8    => f32, f64, i8, i16, i32, isize, i64;
        i16   => f32, f64,     i16, i32, isize, i64;
        i32   => f32, f64,          i32, isize, i64;
        isize => f32, f64,          i32, isize, i64;
        i64   => f32, f64,                      i64;
    }

    half_promotion! {
        i8    =>                                     u8, u16, u32, usize, u64;
        i16   =>                                         u16, u32, usize, u64;
        i32   =>                                              u32, usize, u64;
        isize =>                                              u32, usize, u64;
        i64   =>                                                          u64;
    }

    from_signed! {

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        isize =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32, isize,      u8, u16, u32, usize;
    }

    // Unsigned
    promotion! {
        u8    => f32, f64,     i16, i32, isize, i64, u8, u16, u32, usize, u64;
        u16   => f32, f64,          i32, isize, i64,     u16, u32, usize, u64;
        u32   => f32, f64,                      i64,          u32, usize, u64;
        usize => f32, f64,                      i64,          u32, usize, u64;
        u64   => f32, f64,                                                u64;
    }

    from_unsigned! {
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32, isize,      u8, u16;
        usize =>           i8, i16, i32, isize,      u8, u16;
        u64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize;
    }

    // Float
    promotion! {
        f32   => f32, f64;
        f64   =>      f64;
    }

    from_float! {
        f32   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
        f64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
    }
}

#[cfg(target_pointer_width = "64")]
mod _64 {
    use {Error, From};

    // Signed
    promotion! {
        i8    => f32, f64, i8, i16, i32, i64, isize;
        i16   => f32, f64,     i16, i32, i64, isize;
        i32   => f32, f64,          i32, i64, isize;
        i64   => f32, f64,               i64, isize;
        isize => f32, f64,               i64, isize;
    }

    half_promotion! {
        i8    =>                                     u8, u16, u32, u64, usize;
        i16   =>                                         u16, u32, u64, usize;
        i32   =>                                              u32, u64, usize;
        i64   =>                                                   u64, usize;
        isize =>                                                   u64, usize;
    }

    from_signed! {

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32,             u8, u16, u32;
        isize =>           i8, i16, i32,             u8, u16, u32;
    }

    // Unsigned
    promotion! {
        u8    => f32, f64,     i16, i32, i64, isize, u8, u16, u32, u64, usize;
        u16   => f32, f64,          i32, i64, isize,     u16, u32, u64, usize;
        u32   => f32, f64,               i64, isize,          u32, u64, usize;
        u64   => f32, f64,                                         u64, usize;
        usize => f32, f64,                                         u64, usize;
    }

    from_unsigned! {
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32,             u8, u16;
        u64   =>           i8, i16, i32, i64, isize, u8, u16, u32;
        usize =>           i8, i16, i32, i64, isize, u8, u16, u32;
    }

    // Float
    promotion! {
        f32  => f32, f64;
        f64  =>      f64;
    }

    from_float! {
        f32  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
        f64  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
    }
}

// The missing piece
impl From<f64> for f32 {
    type Output = Result<f32, Error>;

    fn cast(src: f64) -> Self::Output {
        use core::{f32, f64};

        if src != src || src == f64::INFINITY || src == f64::NEG_INFINITY {
            Ok(src as f32)
        } else if src < f32::MIN as f64 {
            Err(Error::Underflow)
        } else if src > f32::MAX as f64 {
            Err(Error::Overflow)
        } else {
            Ok(src as f32)
        }
    }
}
<commit_msg>Add #[inline] to all functions<commit_after>//! Ergonomic, checked cast functions for primitive types
//!
//! This crate provides one checked cast function for each numeric primitive. Use these functions
//! to perform a cast from any other numeric primitive:
//!
//! ```
//! extern crate cast;
//!
//! use cast::{u8, u16, Error};
//!
//! # fn main() {
//! // Infallible operations, like integer promotion, are equivalent to a normal cast with `as`
//! assert_eq!(u16(0u8), 0u16);
//!
//! // Everything else will return a `Result` depending on the success of the operation
//! assert_eq!(u8(0u16), Ok(0u8));
//! assert_eq!(u8(256u16), Err(Error::Overflow));
//! assert_eq!(u8(-1i8), Err(Error::Underflow));
//! assert_eq!(u8(1. / 0.), Err(Error::Infinite));
//! assert_eq!(u8(0. / 0.), Err(Error::NaN));
//! # }
//! ```
//!
//! There are no namespace problems between these functions, the "primitive modules" in `core`/`std`
//! and the built-in primitive types, so all them can be in the same scope:
//!
//! ```
//! extern crate cast;
//!
//! use std::u8;
//! use cast::{u8, u16};
//!
//! # fn main() {
//! // `u8` as a type
//! let x: u8 = 0;
//! // `u8` as a module
//! let y = u16(u8::MAX);
//! // `u8` as a function
//! let z = u8(y).unwrap();
//! # }
//! ```
//!
//! The checked cast functionality is also usable with type aliases via the `cast` static method:
//!
//! ```
//! extern crate cast;
//!
//! use std::os::raw::c_ulonglong;
//! // NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311
//! use cast::From as _0;
//!
//!
//! # fn main() {
//! assert_eq!(c_ulonglong::cast(0u8), 0u64);
//! # }
//! ```
//!
//! This crate also provides a `From` trait that can be used, for example, to create a generic
//! function that accepts any type that can be infallibly casted to `u32`.
//!
//! ```
//! extern crate cast;
//!
//! fn to_u32<T>(x: T) -> u32
//!     // reads as: "where u32 can be casted from T with output u32"
//!     where u32: cast::From<T, Output=u32>,
//! {
//!     cast::u32(x)
//! }
//!
//! # fn main() {
//! assert_eq!(to_u32(0u8), 0u32);
//! assert_eq!(to_u32(1u16), 1u32);
//! assert_eq!(to_u32(2u32), 2u32);
//!
//! // to_u32(-1i32);  // Compile error
//! # }
//! ```
//!

#![deny(missing_docs)]
#![deny(warnings)]
#![allow(const_err)]
#![no_std]

#![cfg_attr(all(feature = "unstable", test), feature(plugin))]
#![cfg_attr(all(feature = "unstable", test), plugin(quickcheck_macros))]

#[cfg(all(feature = "unstable", test))]
extern crate quickcheck;

#[cfg(test)]
mod test;

/// Cast errors
#[derive(Debug, PartialEq)]
pub enum Error {
    /// Infinite value casted to a type that can only represent finite values
    Infinite,
    /// NaN value casted to a type that can't represent a NaN value
    NaN,
    /// Source value is greater than the maximum value that the destination type can hold
    Overflow,
    /// Source value is smaller than the minimum value that the destination type can hold
    Underflow,
}

/// The "cast from" operation
pub trait From<Src> {
    /// The result of the cast operation: either `Self` or `Result<Self, Error>`
    type Output;

    /// Checked cast from `Src` to `Self`
    fn cast(Src) -> Self::Output;
}

macro_rules! fns {
    ($($ty:ident),+) => {
        $(
            /// Checked cast function
            #[inline]
            pub fn $ty<T>(x: T) -> <$ty as From<T>>::Output
                where $ty: From<T>
            {
                <$ty as From<T>>::cast(x)
            }
         )+
    }
}

fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);

/// `$dst` can hold any value of `$src`
macro_rules! promotion {
    ($($src:ty => $($dst: ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = $dst;

                    #[inline]
                    fn cast(src: $src) -> $dst {
                        src as $dst
                    }
                }
            )+
        )+
    }
}

/// `$dst` can hold any positive value of `$src`
macro_rules! half_promotion {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    #[inline]
                    fn cast(src: $src) -> Self::Output {
                        if src < 0 {
                            Err(Error::Underflow)
                        } else {
                            Ok(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

/// From an unsigned `$src` to a smaller `$dst`
macro_rules! from_unsigned {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    #[inline]
                    fn cast(src: $src) -> Self::Output {
                        use core::$dst;

                        if src > $dst::MAX as $src {
                            Err(Error::Overflow)
                        } else {
                            Ok(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

/// From a signed `$src` to a smaller `$dst`
macro_rules! from_signed {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    #[inline]
                    fn cast(src: $src) -> Self::Output {
                        use core::$dst;

                        Err(if src < $dst::MIN as $src {
                            Error::Underflow
                        } else if src > $dst::MAX as $src {
                            Error::Overflow
                        } else {
                            return Ok(src as $dst);
                        })
                    }
                }
            )+
        )+
    }
}

/// From a float `$src` to an integer `$dst`
macro_rules! from_float {
    ($($src:ident => $($dst:ident),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Result<$dst, Error>;

                    #[inline]
                    fn cast(src: $src) -> Self::Output {
                        use core::{$dst, $src};

                        Err(if src != src {
                            Error::NaN
                        } else if src == $src::INFINITY || src == $src::NEG_INFINITY {
                            Error::Infinite
                        } else if src < $dst::MIN as $src {
                            Error::Underflow
                        } else if src > $dst::MAX as $src {
                            Error::Overflow
                        } else {
                            return Ok(src as $dst);
                        })
                    }
                }
            )+
        )+
    }
}

// PLAY TETRIS! ;-)

#[cfg(target_pointer_width = "32")]
mod _32 {
    use {Error, From};

    // Signed
    promotion! {
        i8    => f32, f64, i8, i16, i32, isize, i64;
        i16   => f32, f64,     i16, i32, isize, i64;
        i32   => f32, f64,          i32, isize, i64;
        isize => f32, f64,          i32, isize, i64;
        i64   => f32, f64,                      i64;
    }

    half_promotion! {
        i8    =>                                     u8, u16, u32, usize, u64;
        i16   =>                                         u16, u32, usize, u64;
        i32   =>                                              u32, usize, u64;
        isize =>                                              u32, usize, u64;
        i64   =>                                                          u64;
    }

    from_signed! {

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        isize =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32, isize,      u8, u16, u32, usize;
    }

    // Unsigned
    promotion! {
        u8    => f32, f64,     i16, i32, isize, i64, u8, u16, u32, usize, u64;
        u16   => f32, f64,          i32, isize, i64,     u16, u32, usize, u64;
        u32   => f32, f64,                      i64,          u32, usize, u64;
        usize => f32, f64,                      i64,          u32, usize, u64;
        u64   => f32, f64,                                                u64;
    }

    from_unsigned! {
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32, isize,      u8, u16;
        usize =>           i8, i16, i32, isize,      u8, u16;
        u64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize;
    }

    // Float
    promotion! {
        f32   => f32, f64;
        f64   =>      f64;
    }

    from_float! {
        f32   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
        f64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
    }
}

#[cfg(target_pointer_width = "64")]
mod _64 {
    use {Error, From};

    // Signed
    promotion! {
        i8    => f32, f64, i8, i16, i32, i64, isize;
        i16   => f32, f64,     i16, i32, i64, isize;
        i32   => f32, f64,          i32, i64, isize;
        i64   => f32, f64,               i64, isize;
        isize => f32, f64,               i64, isize;
    }

    half_promotion! {
        i8    =>                                     u8, u16, u32, u64, usize;
        i16   =>                                         u16, u32, u64, usize;
        i32   =>                                              u32, u64, usize;
        i64   =>                                                   u64, usize;
        isize =>                                                   u64, usize;
    }

    from_signed! {

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32,             u8, u16, u32;
        isize =>           i8, i16, i32,             u8, u16, u32;
    }

    // Unsigned
    promotion! {
        u8    => f32, f64,     i16, i32, i64, isize, u8, u16, u32, u64, usize;
        u16   => f32, f64,          i32, i64, isize,     u16, u32, u64, usize;
        u32   => f32, f64,               i64, isize,          u32, u64, usize;
        u64   => f32, f64,                                         u64, usize;
        usize => f32, f64,                                         u64, usize;
    }

    from_unsigned! {
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32,             u8, u16;
        u64   =>           i8, i16, i32, i64, isize, u8, u16, u32;
        usize =>           i8, i16, i32, i64, isize, u8, u16, u32;
    }

    // Float
    promotion! {
        f32  => f32, f64;
        f64  =>      f64;
    }

    from_float! {
        f32  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
        f64  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
    }
}

// The missing piece
impl From<f64> for f32 {
    type Output = Result<f32, Error>;

    #[inline]
    fn cast(src: f64) -> Self::Output {
        use core::{f32, f64};

        if src != src || src == f64::INFINITY || src == f64::NEG_INFINITY {
            Ok(src as f32)
        } else if src < f32::MIN as f64 {
            Err(Error::Underflow)
        } else if src > f32::MAX as f64 {
            Err(Error::Overflow)
        } else {
            Ok(src as f32)
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]
#![allow(dead_code)]
#![feature(slice_patterns)]

//! # Rules
//! Rules uses regular expressions to do pattern matching using syntax
//! based upon the Perl 6 regex grammar. The Perl 6 grammar has been heavily
//! revised from Perl 5 and should not be equated with it. This may look
//! nothing like any regex you have seen before.
//!
//! # Syntax
//!
//! Currently, this is designed for ASCII and may not behave properly
//! with Unicode.
//!
//! Whitespace is generally ignored so that a regex can be more readable
//! and less dense.
//!
//! ```plain
//! r"fred"    // Normal way
//! r"f r e d" // Completely equivalent
//! // Will match `apples_oranges` or any other deliminator
//! r"apples . oranges"
//! ```
//!
//! # Literals
//!
//! Alphanumerics, underscores (`_`), and everything enclosed within
//! quotes (`"`) and ticks (`'`) are the only literals.
//!
//! ```plain
//! hello_world   // Matches `hello_world`.
//! "carrot cake" // Matches `carrot cake`.
//! 'apple pie'   // Matches `apple pie`.
//! ```
//!
//! Everything else must be escaped with a backslash (`\*`) to literally match.
//!
//! ```plain
//! it\'s\ my\ birthday // Matches `it's my birthday`.
//! ```
//!
//! # Set operators
//!
//! These operators can be applied to groups which will be analyzed later:
//!
//! ```plain
//! +       Union                // [123] + [345] = [12345]
//! |       Union                // Same
//! &       Intersection         // [123] & [345] = [3]
//! -       Difference           // [123] - [345] = [12]
//! ^       Symmetric difference // [123] ^ [345] = [1245]
//! ```
//!
//! # Character classes
//!
//! ## Default character classes
//!
//! Character | Matches               | Inverse
//! ----------|-----------------------|--------
//! `.`       | Any character         | N/A
//! `\d`      | Digit                 | `\D`
//! `\h`      | Horizontal whitespace | `\H`
//! `\n`      | Newline               | `\N`
//! `\s`      | Any whitespace        | `\S`
//! `\t`      | Tab                   | `\T`
//! `\w`      | Alphanumeric or `_`   | `\W`
//!
//! ## Custom character classes
//!
//! Characters inside a set of `<[ ]>` form a custom character
//! class:
//!
//! ```plain
//! // Matches `a` or `b` or `c`
//! <[ a b c ]>
//!
//! // `..` expresses a range so this matches
//! // from `a` to `g` or a digit
//! <[ a .. g \d ]>
//!
//! // The `[]` bind the sets together into (non-capturing)
//! // groups so set operators can be used.
//! <[0-9] - [13579]> // Matches an even number
//! <\d - [13579]>    // Same
//! <[0-6] ^ [5-9]>   // Matches a `5` or `6`
//! <-[0-6]>          // Negation: anything but 0-6
//! ```
//!
//! # Comments
//!
//! Comments are allowed inside a regex.
//!
//! ```plain
//! // This matches `myregex`
//! r"my // This is a comment which goes to the end of the line
//! regex"
//! ```

pub mod collapse;
pub mod parse;
pub mod re;
pub mod range_set;
pub mod unicode;

<commit_msg>Document `<>` usage some<commit_after>#![allow(unused_variables)]
#![allow(dead_code)]
#![feature(slice_patterns)]

//! # Rules
//! Rules uses regular expressions to do pattern matching using syntax
//! based upon the Perl 6 regex grammar. The Perl 6 grammar has been heavily
//! revised from Perl 5 and should not be equated with it. This may look
//! nothing like any regex you have seen before.
//!
//! # Syntax
//!
//! Currently, this is designed for ASCII and may not behave properly
//! with Unicode.
//!
//! Whitespace is generally ignored so that a regex can be more readable
//! and less dense.
//!
//! ```plain
//! r"fred"    // Normal way
//! r"f r e d" // Completely equivalent
//! // Will match `apples_oranges` or any other deliminator
//! r"apples . oranges"
//! ```
//!
//! # Literals
//!
//! Alphanumerics, underscores (`_`), and everything enclosed within
//! quotes (`"`) and ticks (`'`) are the only literals.
//!
//! ```plain
//! hello_world   // Matches `hello_world`.
//! "carrot cake" // Matches `carrot cake`.
//! 'apple pie'   // Matches `apple pie`.
//! ```
//!
//! Everything else must be escaped with a backslash (`\*`) to literally match.
//!
//! ```plain
//! it\'s\ my\ birthday // Matches `it's my birthday`.
//! ```
//!
//! # Chevrons: `<>`
//!
//! Chevrons are considered a metacharacter grouping operator whose behaviour
//! changes depending on the first character found inside. The behavior for
//! each different character is:
//!
//! First character | Example | Result
//! ----------------|---------|-------
//! Whitespace | `< big small >` | Alternative quotes matches `[ 'big' | 'small' ]`
//! alphabetic | `<alpha>` | Named character class which captures
//! `?` | `<?before foo>` | A positive zero width assertion
//! `!` | `<!before foo>` | A negative zero width assertion
//! `[` | `<[ ab ]>` | A character class matches `[ 'a' | 'b' ]`
//! `-` | `<-[a] + [b]>` | Negated character class: `[ab]` negated
//! `+` | `<+ [a] >` | Doesn't modify the class.
//!
//! # Lookaround
//!
//! * lookahead - `foo <?after bar>` matches `foo` in `foobar`
//! * negative lookahead - `foo <!after bar>` matches `foo` in `foobaz`
//! * lookbehind - `<?before foo> bar` matches `bar` in `foobar`
//! * negative lookbehind - `<!before foo> bar` matches `bar` in `sushibar`
//!
//! An example with both:
//! `<?before foo> bar <?after baz>`  matches `bar` in `foobarbaz`
//!
//! # Set operators
//!
//! These operators can be applied to groups which will be analyzed later:
//!
//! ```plain
//! +       Union                // [123] + [345] = [12345]
//! |       Union                // Same
//! &       Intersection         // [123] & [345] = [3]
//! -       Difference           // [123] - [345] = [12]
//! ^       Symmetric difference // [123] ^ [345] = [1245]
//! ```
//!
//! # Character classes
//!
//! ## Default character classes
//!
//! Character | Matches               | Inverse
//! ----------|-----------------------|--------
//! `.`       | Any character         | N/A
//! `\d`      | Digit                 | `\D`
//! `\h`      | Horizontal whitespace | `\H`
//! `\n`      | Newline               | `\N`
//! `\s`      | Any whitespace        | `\S`
//! `\t`      | Tab                   | `\T`
//! `\w`      | Alphanumeric or `_`   | `\W`
//!
//! ## Custom character classes
//!
//! Characters inside a set of `<[ ]>` form a custom character
//! class:
//!
//! ```plain
//! // Matches `a` or `b` or `c`
//! <[ a b c ]>
//!
//! // `..` expresses a range so this matches
//! // from `a` to `g` or a digit
//! <[ a .. g \d ]>
//!
//! // The `[]` bind the sets together into (non-capturing)
//! // groups so set operators can be used.
//! <[0-9] - [13579]> // Matches an even number
//! <\d - [13579]>    // Same
//! <[0-6] ^ [5-9]>   // Matches a `5` or `6`
//! <-[0-6]>          // Negation: anything but 0-6
//! ```
//!
//! # Comments
//!
//! Comments are allowed inside a regex.
//!
//! ```plain
//! // This matches `myregex`
//! r"my // This is a comment which goes to the end of the line
//! regex"
//! ```

pub mod collapse;
pub mod parse;
pub mod re;
pub mod range_set;
pub mod unicode;

<|endoftext|>


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

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::Registry;
use std::rc::Rc;
use syntax::ast::TokenTree;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::parse::token::{self, DelimToken, Token};

mod parser_any_macro;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("interpolate_idents", interpolate_idents);
}

fn interpolate_idents<'a>(cx: &'a mut ExtCtxt,
              _: Span,
              tts: &[TokenTree]) -> Box<MacResult + 'a> {
    fn concat_idents(tts: &Vec<TokenTree>, delim: DelimToken) -> Option<TokenTree> {
        match delim {
            DelimToken::Bracket => {
                let mut new_ident = String::new();
                let mut new_span: Option<Span> = None;

                for token in tts.iter() {
                    match token {
                        &TokenTree::Token(ref span, Token::Ident(ref ident)) => {
                            match new_span {
                                Some(ref mut s) => { s.hi = span.hi; },
                                None => { new_span = Some(span.clone()); },
                            }
                            new_ident.push_str(&ident.name.as_str());
                        },
                        _ => return None,
                    }
                }

                match new_span {
                    Some(s) => {
                        let new_ident = token::str_to_ident(&new_ident[..]);
                        Some(TokenTree::Token(s, Token::Ident(new_ident)))
                    },
                    None => None
                }
            },
            _ => None,
        }
    }

    fn map_tts(tts: &[TokenTree]) -> Vec<TokenTree> {
        tts.iter().map(|t| {
            match t {
                &TokenTree::Delimited(ref s, ref d) => {
                    match concat_idents(&d.tts, d.delim) {
                        Some(t) => t,
                        None => {
                            TokenTree::Delimited(s.clone(), Rc::new(syntax::ast::Delimited {
                                delim: d.delim,
                                open_span: d.open_span,
                                tts: map_tts(&*d.tts),
                                close_span: d.close_span,
                            }))
                        },
                    }
                },
                &TokenTree::Sequence(ref s, ref d) => {
                    TokenTree::Sequence(s.clone(), Rc::new(syntax::ast::SequenceRepetition {
                        tts: map_tts(&*d.tts),
                        separator: d.separator.clone(),
                        op: d.op,
                        num_captures: d.num_captures,
                    }))
                },
                _ => t.clone(),
            }
        }).collect()
    }

    let parser = cx.new_parser_from_tts(&map_tts(tts)[..]);
    Box::new(parser_any_macro::ParserAnyMacro::new(parser)) as Box<MacResult>
}
<commit_msg>rustup<commit_after>#![feature(plugin_registrar, rustc_private)]

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::Registry;
use syntax::tokenstream::TokenTree;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::parse::token::{self, DelimToken, Token};

mod parser_any_macro;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("interpolate_idents", interpolate_idents);
}

fn interpolate_idents<'a>(cx: &'a mut ExtCtxt,
              _: Span,
              tts: &[TokenTree]) -> Box<MacResult + 'a> {
    fn concat_idents(tts: &Vec<TokenTree>, delim: DelimToken) -> Option<TokenTree> {
        match delim {
            DelimToken::Bracket => {
                let mut new_ident = String::new();
                let mut new_span: Option<Span> = None;

                for token in tts.iter() {
                    match token {
                        &TokenTree::Token(ref span, Token::Ident(ref ident)) => {
                            match new_span {
                                Some(ref mut s) => { s.hi = span.hi; },
                                None => { new_span = Some(span.clone()); },
                            }
                            new_ident.push_str(&ident.name.as_str());
                        },
                        _ => return None,
                    }
                }

                match new_span {
                    Some(s) => {
                        let new_ident = token::str_to_ident(&new_ident[..]);
                        Some(TokenTree::Token(s, Token::Ident(new_ident)))
                    },
                    None => None
                }
            },
            _ => None,
        }
    }

    fn map_tts(tts: &[TokenTree]) -> Vec<TokenTree> {
        tts.iter().map(|t| {
            match t {
                &TokenTree::Delimited(ref s, ref d) => {
                    match concat_idents(&d.tts, d.delim) {
                        Some(t) => t,
                        None => {
                            TokenTree::Delimited(s.clone(), syntax::tokenstream::Delimited {
                                delim: d.delim,
                                open_span: d.open_span,
                                tts: map_tts(&*d.tts),
                                close_span: d.close_span,
                            })
                        },
                    }
                },
                &TokenTree::Sequence(ref s, ref d) => {
                    TokenTree::Sequence(s.clone(), syntax::tokenstream::SequenceRepetition {
                        tts: map_tts(&*d.tts),
                        separator: d.separator.clone(),
                        op: d.op,
                        num_captures: d.num_captures,
                    })
                },
                _ => t.clone(),
            }
        }).collect()
    }

    let parser = cx.new_parser_from_tts(&map_tts(tts)[..]);
    Box::new(parser_any_macro::ParserAnyMacro::new(parser)) as Box<MacResult>
}
<|endoftext|>


<commit_before>/// for HTTPS
extern crate hyper;
/// to decode JSON data
extern crate rustc_serialize;

use std::fmt;
use std::io::Read;
use std::result::{Result};
use rustc_serialize::json::Json;
use hyper::{Client};

/// the struct to keep
pub struct TheMovieDB {
	/// the all mighty api key we need for each request
	api_key: &'static str,
	/// the base url for themoviedb.org
	base_url: &'static str,
	/// the base url for all images, comes from the /configuration URL
	image_base_url: String,
	/// the HTTPS client we use for getting data from the API
	http_client: Client,
}

impl fmt::Debug for TheMovieDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TheMovieDB => ApiKey: {}, BaseURL: {}, ImageBaseURL: {}",
		 self.api_key,
		 self.base_url,
		 self.image_base_url)
    }
}

impl TheMovieDB {
	/// Constructs a new TheMovieDB instance.
	///
	/// # Examples
	///
	/// ```
	/// use std::rc::Rc;
	///
	/// let five = Rc::new(5);
	/// ```
	fn new(themoviedb_api_key: &'static str) -> Result<TheMovieDB, String> {
		let mut new_instance = TheMovieDB{api_key: themoviedb_api_key,
			base_url: "https://api.themoviedb.org/3",
			image_base_url: "".to_string(),
			http_client: Client::new()};

		let configuration_data = match new_instance.get_json_data_for("/configuration") {
			Ok(c) => c,
			Err(error_string) => return Err(error_string)
		};

		let json_obj = match configuration_data.as_object() {
			Some(o) => o,
			None => return Err("Error while getting JSON object".to_string())
		};

		new_instance.image_base_url = json_obj.get("images").unwrap().as_object().unwrap().get("secure_base_url").unwrap().to_string();

		Ok(new_instance)
	}

	/// Returns a URL as String for the given API method
	///
	/// It also automatically adds the api key
	fn get_url_for(& self, url_string: &'static str) -> String {
		if url_string.contains("?") {
			format!("{}{}&api_key={}", self.base_url, url_string, self.api_key)
		} else {
			format!("{}{}?api_key={}", self.base_url, url_string, self.api_key)
		}
	}

	/// Returns the data for a given API method or an error string if something has failed
	fn get_json_data_for(& self, url_string: &'static str) -> Result<Json, String> {
		let call_url = self.get_url_for(url_string);

		let mut response = match self.http_client.get(&call_url).send() {
			Ok(r) => r,
			Err(_) => {
				return Err("Error during HTTPS request".to_string());
			}
 		};

		if hyper::Ok != response.status {
			return Err("No HTTPS Status 200 (OK)".to_string());
		}

		let mut result = String::new();
		if response.read_to_string(& mut result).is_err() {
			return Err("Error reading response".to_string());
		}

		let json_data = match Json::from_str(&result) {
			Ok(d) => d,
			Err(_) => return Err("Error while readin JSON data".to_string())
		};

		Ok(json_data)
	}
}

#[test]
fn initialization_test() {
	// TODO: Real tests ;)
	assert!(TheMovieDB::new("6da14fa0b6231874a56ee667a505cdcc").is_ok());
}
<commit_msg>Reworked test setup and changed from strings to Actual URL objects<commit_after>/// for HTTPS
extern crate hyper;
/// to decode JSON data
extern crate rustc_serialize;

use std::fmt;
use std::io::Read;
use std::result::{Result};
use rustc_serialize::json::Json;
use hyper::{Client, Url};

static TESTAPIKEY: &'static str = "YOUR API KEY FROM themoviedb.org";

/// the struct to keep
pub struct TheMovieDB {
	/// the all mighty api key we need for each request
	api_key: &'static str,
	/// the base url for themoviedb.org
	base_url: &'static str,
	/// the base url for all images, comes from the /configuration URL
	image_base_url: String,
	/// the HTTPS client we use for getting data from the API
	http_client: Client,
}

impl fmt::Debug for TheMovieDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TheMovieDB => ApiKey: {}, BaseURL: {}, ImageBaseURL: {}",
		 self.api_key,
		 self.base_url,
		 self.image_base_url)
    }
}

impl TheMovieDB {
	/// Constructs a new TheMovieDB instance.
	///
	/// # Examples
	///
	/// ```
	/// use std::rc::Rc;
	///
	/// let five = Rc::new(5);
	/// ```
	fn new(themoviedb_api_key: &'static str) -> Result<TheMovieDB, String> {
		let mut new_instance = TheMovieDB{api_key: themoviedb_api_key,
			base_url: "https://api.themoviedb.org/3",
			image_base_url: "".to_string(),
			http_client: Client::new()};

		let configuration_data = match new_instance.get_json_data_for("/configuration") {
			Ok(c) => c,
			Err(error_string) => return Err(error_string)
		};

		let json_obj = match configuration_data.as_object() {
			Some(o) => o,
			None => return Err("Error while getting JSON object".to_string())
		};

		new_instance.image_base_url = json_obj.get("images").unwrap().as_object().unwrap().get("secure_base_url").unwrap().to_string();

		Ok(new_instance)
	}

	fn search(& self, search_term: &'static str) -> Result<String, String> {
		let search_data = match self.get_json_data_for(search_term) {
			Ok(d) => d,
			Err(error_string) => return Err(error_string)
		};

		println!("{:?}", search_data);

		Err("FAILED".to_string())
	}

	/// Returns a URL as String for the given API method
	///
	/// It also automatically adds the api key
	fn get_url_for(& self, url_string: &'static str) -> Result<Url, String> {
//		if url_string.contains("?") {
			let result_url = match Url::parse(&format!("{}{}&api_key={}", self.base_url, url_string, self.api_key)) {
				Ok(u) => u,
				Err(_) => return Err(format!("Error buildign URL"))
			};
			Ok(result_url)
		// } else {
		// 	format!("{}{}?api_key={}", self.base_url, url_string, self.api_key)
//		}
	}

	/// Returns the data for a given API method or an error string if something has failed
	fn get_json_data_for(& self, url_string: &'static str) -> Result<Json, String> {
		let call_url = match self.get_url_for(url_string) {
			Ok(u) => u,
			Err(error_string) => return Err(error_string)
		};

		let call_url_string = format!("{}", call_url);
		let mut response = match self.http_client.get(call_url).send() {
			Ok(r) => r,
			Err(_) => {
				return Err(format!("Error during HTTPS request with URL {}", call_url_string));
			}
 		};

		if hyper::Ok != response.status {
			return Err(format!("No HTTPS Status 200 (OK) for url: {}", call_url_string));
		}

		let mut result = String::new();
		if response.read_to_string(& mut result).is_err() {
			return Err("Error reading response".to_string());
		}

		let json_data = match Json::from_str(&result) {
			Ok(d) => d,
			Err(_) => return Err("Error while readin JSON data".to_string())
		};

		Ok(json_data)
	}
}

#[test]
fn initialization_test() {
	TheMovieDB::new(TESTAPIKEY).unwrap();
}

#[test]
fn search_test() {
	let themoviedb = TheMovieDB::new(TESTAPIKEY).unwrap();
	let search_result = themoviedb.search("The Avengers").unwrap();
}
<|endoftext|>


<commit_before>extern crate log;

use std::io::{Write, stderr};
use std::sync::Mutex;

use log::{Log, LogLevelFilter, LogMetadata, LogRecord, SetLoggerError};

pub struct Writer(pub Box<Write + Send>);

struct Logger {
    writers: Mutex<Vec<Writer>>,
}

impl Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool { true }

    fn log(&self, rec: &LogRecord) {
        let mut writers = match self.writers.lock() {
            Ok(writers) => writers,
            Err(err) => {
                let _ = writeln!(stderr(), "{:?}", err);
                return;
            },
        };
        let loc = rec.location();
        for i in 0..writers.len() {
            let _ = writeln!(writers[i].0,
                             "{}:{}:{}:{}",
                             rec.level(),
                             loc.file(),
                             loc.line(),
                             rec.args());
        }
    }
}

pub fn init(writers: Vec<Writer>) -> Result<(), SetLoggerError> {
    log::set_logger(|max_level| {
        max_level.set(LogLevelFilter::max());
        Box::new(Logger { writers: Mutex::new(writers) })
    })
}
<commit_msg>Add level filter<commit_after>extern crate log;

use std::io::{Write, stderr};
use std::sync::Mutex;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};

pub struct Writer(pub Box<Write + Send>);

struct Logger {
    writers: Mutex<Vec<Writer>>,
    level: LogLevel,
}

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool { metadata.level() <= self.level }

    fn log(&self, rec: &LogRecord) {
        let mut writers = match self.writers.lock() {
            Ok(writers) => writers,
            Err(err) => {
                let _ = writeln!(stderr(), "{:?}", err);
                return;
            },
        };
        let loc = rec.location();
        for i in 0..writers.len() {
            let w = &mut writers[i].0;
            let _ = writeln!(w, "{}:{}:{}:{}", rec.level(), loc.file(), loc.line(), rec.args());
        }
    }
}

pub fn init(writers: Vec<Writer>, level: LogLevel) -> Result<(), SetLoggerError> {
    log::set_logger(|max_level| {
        max_level.set(level.to_log_level_filter());
        let logger = Logger {
            writers: Mutex::new(writers),
            level: level,
        };
        Box::new(logger)
    })
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 the slack-rs authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Low-level, direct interface for the [Slack Web
//! API](https://api.slack.com/methods).

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod mods;
pub use mods::*;

mod types;
pub use types::*;

pub mod requests;

#[cfg(feature = "reqwest")]
pub use requests::default_client;

fn get_slack_url_for_method(method: &str) -> String {
    format!("https://slack.com/api/{}", method)
}

fn optional_struct_or_empty_array<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
    where T: serde::Deserialize<'de> + Default,
          D: serde::Deserializer<'de>
{
    use std::marker::PhantomData;
    use serde::de;

    struct StructOrEmptyArray<T>(PhantomData<T>);

    impl<'de, T> de::Visitor<'de> for StructOrEmptyArray<T>
        where T: de::Deserialize<'de> + Default
    {
        type Value = Option<T>;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("struct or empty array")
        }

        fn visit_seq<A>(self, mut seq: A) -> Result<Option<T>, A::Error>
            where A: de::SeqAccess<'de>
        {
            match seq.next_element::<T>()? {
                Some(_) => Err(de::Error::custom("non-empty array is not valid")),
                None => Ok(Some(T::default())),
            }
        }

        fn visit_unit<E>(self) -> Result<Option<T>, E>
            where E: de::Error
        {
            Ok(None)
        }

        fn visit_map<M>(self, access: M) -> Result<Option<T>, M::Error>
            where M: de::MapAccess<'de>
        {
            T::deserialize(de::value::MapAccessDeserializer::new(access)).map(Some)
        }
    }

    deserializer.deserialize_any(StructOrEmptyArray(PhantomData))
}

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

    #[test]
    fn test_user_profile_fields_empty_array_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": []}"#).unwrap();
        assert_eq!(0, user_profile.fields.unwrap().len());
    }

    #[test]
    fn test_user_profile_fields_empty_map_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": {}}"#).unwrap();
        assert_eq!(0, user_profile.fields.unwrap().len());
    }

    #[test]
    fn test_user_profile_fields_nonempty_map_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": {"some_field": {"alt": "foo", "label": "bar"}}}"#).unwrap();
        assert_eq!(1, user_profile.fields.unwrap().len());
    }

    #[test]
    fn test_user_profile_fields_null_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": null}"#).unwrap();
        assert!(user_profile.fields.is_none());
    }

    #[test]
    fn test_user_profile_fields_undefined_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{}"#).unwrap();
        assert!(user_profile.fields.is_none());
    }
}
<commit_msg>remove Default requirement, but return None when encountering []<commit_after>// Copyright 2015-2016 the slack-rs authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Low-level, direct interface for the [Slack Web
//! API](https://api.slack.com/methods).

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod mods;
pub use mods::*;

mod types;
pub use types::*;

pub mod requests;

#[cfg(feature = "reqwest")]
pub use requests::default_client;

fn get_slack_url_for_method(method: &str) -> String {
    format!("https://slack.com/api/{}", method)
}

fn optional_struct_or_empty_array<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
    where T: serde::Deserialize<'de>,
          D: serde::Deserializer<'de>
{
    use std::marker::PhantomData;
    use serde::de;

    struct StructOrEmptyArray<T>(PhantomData<T>);

    impl<'de, T> de::Visitor<'de> for StructOrEmptyArray<T>
        where T: de::Deserialize<'de>
    {
        type Value = Option<T>;

        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
            formatter.write_str("struct or empty array")
        }

        fn visit_seq<A>(self, mut seq: A) -> Result<Option<T>, A::Error>
            where A: de::SeqAccess<'de>
        {
            match seq.next_element::<T>()? {
                Some(_) => Err(de::Error::custom("non-empty array is not valid")),
                None => Ok(None),
            }
        }

        fn visit_unit<E>(self) -> Result<Option<T>, E>
            where E: de::Error
        {
            Ok(None)
        }

        fn visit_map<M>(self, access: M) -> Result<Option<T>, M::Error>
            where M: de::MapAccess<'de>
        {
            T::deserialize(de::value::MapAccessDeserializer::new(access)).map(Some)
        }
    }

    deserializer.deserialize_any(StructOrEmptyArray(PhantomData))
}

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

    #[test]
    fn test_user_profile_fields_empty_array_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": []}"#).unwrap();
        assert!(user_profile.fields.is_none());
    }

    #[test]
    fn test_user_profile_fields_empty_map_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": {}}"#).unwrap();
        assert_eq!(0, user_profile.fields.unwrap().len());
    }

    #[test]
    fn test_user_profile_fields_nonempty_map_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": {"some_field": {"alt": "foo", "label": "bar"}}}"#).unwrap();
        assert_eq!(1, user_profile.fields.unwrap().len());
    }

    #[test]
    fn test_user_profile_fields_null_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{"fields": null}"#).unwrap();
        assert!(user_profile.fields.is_none());
    }

    #[test]
    fn test_user_profile_fields_undefined_deserialize() {
        let user_profile: UserProfile = serde_json::from_str(r#"{}"#).unwrap();
        assert!(user_profile.fields.is_none());
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Keegan McAllister.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

#[cfg(not(test))]
#[link(name="afl-llvm-rt", kind="static")]
extern "C" {
    fn __afl_manual_init();
}

#[cfg(not(test))]
/// Initialize the afl runtime.
///
/// Only needed when the env var `AFL_DEFER_FORKSRV` is set.
///
/// It's undefined behavior to call this function from multiple
/// threads. You almost certainly need to call it before any
/// additional threads are created.
///
/// However, calling this more than once in a single-threaded
/// program, or calling it when not running with
/// `AFL_DEFER_FORKSRV` is safe and a no-op.
pub unsafe fn init() {
    __afl_manual_init();
}

#[cfg(test)]
mod test {
    use std::process::{Command, Stdio};
    use std::fs;
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new("target/debug/cargo-afl-fuzz")
            .stdout(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg("target/debug/examples/hello")
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        let mut entries = fs::read_dir(temp_dir_path.join("queue")).expect("Could not read AFL out directory");
        assert!(entries.next().is_some());
    }
}
<commit_msg>Check for existence of 'fuzzer_stats' file for integration test.<commit_after>// Copyright 2015 Keegan McAllister.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

#[cfg(not(test))]
#[link(name="afl-llvm-rt", kind="static")]
extern "C" {
    fn __afl_manual_init();
}

#[cfg(not(test))]
/// Initialize the afl runtime.
///
/// Only needed when the env var `AFL_DEFER_FORKSRV` is set.
///
/// It's undefined behavior to call this function from multiple
/// threads. You almost certainly need to call it before any
/// additional threads are created.
///
/// However, calling this more than once in a single-threaded
/// program, or calling it when not running with
/// `AFL_DEFER_FORKSRV` is safe and a no-op.
pub unsafe fn init() {
    __afl_manual_init();
}

#[cfg(test)]
mod test {
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new("target/debug/cargo-afl-fuzz")
            .stdout(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg("target/debug/examples/hello")
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
}
<|endoftext|>