<commit_before>/*!
This module is concerned with how `cargo-script` extracts the manfiest from a script file.
*/

use toml;

use consts;
use error::{Blame, Result};
use Input;

/**
Splits input into a complete Cargo manifest and unadultered Rust source.
*/
pub fn split_input(input: &Input, deps: &[(String, String)]) -> Result<(String, String)> {
    let (part_mani, source, template) = match *input {
        Input::File(_, _, content, _) => {
            let content = strip_hashbang(content);
            let (manifest, source) = find_embedded_manifest(content)
                .unwrap_or(("", content));

            (manifest, source, consts::FILE_TEMPLATE)
        },
        Input::Expr(content) => ("", content, consts::EXPR_TEMPLATE),
        Input::Loop(content, count) => {
            let templ = if count { consts::LOOP_COUNT_TEMPLATE } else { consts::LOOP_TEMPLATE };
            ("", content, templ)
        },
    };

    let source = template.replace("%%", source);

    info!("part_mani: {:?}", part_mani);
    info!("source: {:?}", source);

    let part_mani = try!(toml::Parser::new(part_mani).parse()
        .ok_or("could not parse embedded manifest"));
    info!("part_mani: {:?}", part_mani);

    // It's-a mergin' time!
    let def_mani = try!(default_manifest(input));
    let dep_mani = try!(deps_manifest(deps));

    let mani = try!(merge_manifest(def_mani, part_mani));
    let mani = try!(merge_manifest(mani, dep_mani));
    info!("mani: {:?}", mani);

    let mani_str = format!("{}", toml::Value::Table(mani));
    info!("mani_str: {}", mani_str);

    Ok((mani_str, source))
}

/**
Returns a slice of the input string with the leading hashbang, if there is one, omitted.
*/
fn strip_hashbang(s: &str) -> &str {
    use std::str::pattern::{Pattern, Searcher};
    use util::ToMultiPattern;

    if s.starts_with("#!") && !s.starts_with("#![") {
        let mut search = vec!["\r\n", "\n"].to_multi_pattern().into_searcher(s);
        match search.next_match() {
            Some((_, b)) => &s[b..],
            None => s
        }
    } else {
        s
    }
}

#[test]
fn test_strip_hashbang() {
    assert_eq!(strip_hashbang("\
#!/usr/bin/env cargo-script-run
and the rest
\
        "), "\
and the rest
\
        ");
    assert_eq!(strip_hashbang("\
#![thingy]
and the rest
\
        "), "\
#![thingy]
and the rest
\
        ");
}

/**
Locates a manifest embedded in Rust source.

Returns `Some((manifest, source))` if it finds a manifest, `None` otherwise.
*/
fn find_embedded_manifest(s: &str) -> Option<(&str, &str)> {
    find_prefix_manifest(s)
}

/**
Locates a "prefix manifest" embedded in a Cargoified Rust Script file.
*/
fn find_prefix_manifest(content: &str) -> Option<(&str, &str)> {
    /*
    The trick with this is that we *will not* assume the input is correctly formed, or that we've been passed a file that even *has* an embedded manifest; *i.e.* we might have been run with a plain Rust source file.

    We look for something which indicates the end of the embedded manifest.  *Officially*, this is a line which contains nothing but whitespace and *at least* three hyphens.  In *truth*, we will also look for anything that looks like Rust code.

    Specifically, we check for a line starting with any of the strings in `SPLIT_MARKERS`.  This should *hopefully* cover every possible valid Rust program.

    Once we've done that, we just chop the script content up in the appropriate places.
    */
    let lines = content.lines_any();

    let mut manifest_end = None;
    let mut source_start = None;

    for line in lines {
        // Did we get a dash separator?
        let mut dashes = 0;
        if line.chars().all(|c| {
            if c == '-' { dashes += 1 }
            c.is_whitespace() || c == '-'
        }) && dashes >= 3 {
            info!("splitting because of dash divider in line {:?}", line);
            manifest_end = Some(&line[0..0]);
            source_start = Some(&line[line.len()..]);
            break;
        }

        // Ok, it's-a guessin' time!  Yes, this is *evil*.
        const SPLIT_MARKERS: &'static [&'static str] = &[
            "//", "/*", "#![", "#[", "pub ",
            "extern ", "use ", "mod ", "type ",
            "struct ", "enum ", "fn ", "impl ", "impl<",
            "static ", "const ",
        ];

        let line_trimmed = line.trim_left();

        for marker in SPLIT_MARKERS {
            if line_trimmed.starts_with(marker) {
                info!("splitting because of marker '{:?}'", marker);
                manifest_end = Some(&line[0..]);
                source_start = Some(&line[0..]);
                break;
            }
        }
    }

    let (manifest, source) = match (manifest_end, source_start) {
        (Some(me), Some(ss)) => {
            (&content[..content.subslice_offset(me)],
                &content[content.subslice_offset(ss)..])
        },
        _ => return None
    };

    // If the manifest doesn't contain anything but whitespace... then we can't really say we *found* a manifest...
    if manifest.chars().all(char::is_whitespace) {
        return None;
    }

    // Found one!
    Some((manifest, source))
}

/**
Generates a default Cargo manifest for the given input.
*/
fn default_manifest(input: &Input) -> Result<toml::Table> {
    let mani_str = consts::DEFAULT_MANIFEST.replace("%n", input.safe_name());
    toml::Parser::new(&mani_str).parse()
        .ok_or("could not parse default manifest, somehow".into())
}

/**
Generates a partial Cargo manifest containing the specified dependencies.
*/
fn deps_manifest(deps: &[(String, String)]) -> Result<toml::Table> {
    let mut mani_str = String::new();
    mani_str.push_str("[dependencies]\n");

    for &(ref name, ref ver) in deps {
        mani_str.push_str(name);
        mani_str.push_str("=");

        // We only want to quote the version if it *isn't* a table.
        let quotes = match ver.starts_with("{") { true => "", false => "\"" };
        mani_str.push_str(quotes);
        mani_str.push_str(ver);
        mani_str.push_str(quotes);
        mani_str.push_str("\n");
    }

    toml::Parser::new(&mani_str).parse()
        .ok_or("could not parse dependency manifest".into())
}

/**
Given two Cargo manifests, merges the second *into* the first.

Note that the "merge" in this case is relatively simple: only *top-level* tables are actually merged; everything else is just outright replaced.
*/
fn merge_manifest(mut into_t: toml::Table, from_t: toml::Table) -> Result<toml::Table> {
    for (k, v) in from_t {
        match v {
            toml::Value::Table(from_t) => {
                use std::collections::btree_map::Entry::*;

                // Merge.
                match into_t.entry(k) {
                    Vacant(e) => {
                        e.insert(toml::Value::Table(from_t));
                    },
                    Occupied(e) => {
                        let into_t = try!(as_table_mut(e.into_mut())
                            .ok_or((Blame::Human, "cannot merge manifests: cannot merge \
                                table and non-table values")));
                        into_t.extend(from_t);
                    }
                }
            },
            v => {
                // Just replace.
                into_t.insert(k, v);
            },
        }
    }

    return Ok(into_t);

    fn as_table_mut(t: &mut toml::Value) -> Option<&mut toml::Table> {
        match *t {
            toml::Value::Table(ref mut t) => Some(t),
            _ => None
        }
    }
}
<commit_msg>Added some tests for `find_embedded_manifest`.<commit_after>/*!
This module is concerned with how `cargo-script` extracts the manfiest from a script file.
*/

use toml;

use consts;
use error::{Blame, Result};
use Input;

/**
Splits input into a complete Cargo manifest and unadultered Rust source.
*/
pub fn split_input(input: &Input, deps: &[(String, String)]) -> Result<(String, String)> {
    let (part_mani, source, template) = match *input {
        Input::File(_, _, content, _) => {
            let content = strip_hashbang(content);
            let (manifest, source) = find_embedded_manifest(content)
                .unwrap_or(("", content));

            (manifest, source, consts::FILE_TEMPLATE)
        },
        Input::Expr(content) => ("", content, consts::EXPR_TEMPLATE),
        Input::Loop(content, count) => {
            let templ = if count { consts::LOOP_COUNT_TEMPLATE } else { consts::LOOP_TEMPLATE };
            ("", content, templ)
        },
    };

    let source = template.replace("%%", source);

    info!("part_mani: {:?}", part_mani);
    info!("source: {:?}", source);

    let part_mani = try!(toml::Parser::new(part_mani).parse()
        .ok_or("could not parse embedded manifest"));
    info!("part_mani: {:?}", part_mani);

    // It's-a mergin' time!
    let def_mani = try!(default_manifest(input));
    let dep_mani = try!(deps_manifest(deps));

    let mani = try!(merge_manifest(def_mani, part_mani));
    let mani = try!(merge_manifest(mani, dep_mani));
    info!("mani: {:?}", mani);

    let mani_str = format!("{}", toml::Value::Table(mani));
    info!("mani_str: {}", mani_str);

    Ok((mani_str, source))
}

/**
Returns a slice of the input string with the leading hashbang, if there is one, omitted.
*/
fn strip_hashbang(s: &str) -> &str {
    use std::str::pattern::{Pattern, Searcher};
    use util::ToMultiPattern;

    if s.starts_with("#!") && !s.starts_with("#![") {
        let mut search = vec!["\r\n", "\n"].to_multi_pattern().into_searcher(s);
        match search.next_match() {
            Some((_, b)) => &s[b..],
            None => s
        }
    } else {
        s
    }
}

#[test]
fn test_strip_hashbang() {
    assert_eq!(strip_hashbang("\
#!/usr/bin/env cargo-script-run
and the rest
\
        "), "\
and the rest
\
        ");
    assert_eq!(strip_hashbang("\
#![thingy]
and the rest
\
        "), "\
#![thingy]
and the rest
\
        ");
}

/**
Locates a manifest embedded in Rust source.

Returns `Some((manifest, source))` if it finds a manifest, `None` otherwise.
*/
fn find_embedded_manifest(s: &str) -> Option<(&str, &str)> {
    find_prefix_manifest(s)
}

#[test]
fn test_find_embedded_manifest() {
    let fem = find_embedded_manifest;

    assert_eq!(fem("fn main() {}"), None);

    assert_eq!(fem(
"
fn main() {}
"),
    None);

    assert_eq!(fem(
"[dependencies]
time = \"0.1.25\"
---
fn main() {}
"),
    Some((
"[dependencies]
time = \"0.1.25\"
",
"
fn main() {}
"
    )));

    assert_eq!(fem(
"[dependencies]
time = \"0.1.25\"

fn main() {}
"),
    Some((
"[dependencies]
time = \"0.1.25\"

",
"fn main() {}
"
    )));
}

/**
Locates a "prefix manifest" embedded in a Cargoified Rust Script file.
*/
fn find_prefix_manifest(content: &str) -> Option<(&str, &str)> {
    /*
    The trick with this is that we *will not* assume the input is correctly formed, or that we've been passed a file that even *has* an embedded manifest; *i.e.* we might have been run with a plain Rust source file.

    We look for something which indicates the end of the embedded manifest.  *Officially*, this is a line which contains nothing but whitespace and *at least* three hyphens.  In *truth*, we will also look for anything that looks like Rust code.

    Specifically, we check for a line starting with any of the strings in `SPLIT_MARKERS`.  This should *hopefully* cover every possible valid Rust program.

    Once we've done that, we just chop the script content up in the appropriate places.
    */
    let lines = content.lines_any();

    let mut manifest_end = None;
    let mut source_start = None;

    for line in lines {
        // Did we get a dash separator?
        let mut dashes = 0;
        if line.chars().all(|c| {
            if c == '-' { dashes += 1 }
            c.is_whitespace() || c == '-'
        }) && dashes >= 3 {
            info!("splitting because of dash divider in line {:?}", line);
            manifest_end = Some(&line[0..0]);
            source_start = Some(&line[line.len()..]);
            break;
        }

        // Ok, it's-a guessin' time!  Yes, this is *evil*.
        const SPLIT_MARKERS: &'static [&'static str] = &[
            "//", "/*", "#![", "#[", "pub ",
            "extern ", "use ", "mod ", "type ",
            "struct ", "enum ", "fn ", "impl ", "impl<",
            "static ", "const ",
        ];

        let line_trimmed = line.trim_left();

        for marker in SPLIT_MARKERS {
            if line_trimmed.starts_with(marker) {
                info!("splitting because of marker '{:?}'", marker);
                manifest_end = Some(&line[0..]);
                source_start = Some(&line[0..]);
                break;
            }
        }
    }

    let (manifest, source) = match (manifest_end, source_start) {
        (Some(me), Some(ss)) => {
            (&content[..content.subslice_offset(me)],
                &content[content.subslice_offset(ss)..])
        },
        _ => return None
    };

    // If the manifest doesn't contain anything but whitespace... then we can't really say we *found* a manifest...
    if manifest.chars().all(char::is_whitespace) {
        return None;
    }

    // Found one!
    Some((manifest, source))
}

/**
Generates a default Cargo manifest for the given input.
*/
fn default_manifest(input: &Input) -> Result<toml::Table> {
    let mani_str = consts::DEFAULT_MANIFEST.replace("%n", input.safe_name());
    toml::Parser::new(&mani_str).parse()
        .ok_or("could not parse default manifest, somehow".into())
}

/**
Generates a partial Cargo manifest containing the specified dependencies.
*/
fn deps_manifest(deps: &[(String, String)]) -> Result<toml::Table> {
    let mut mani_str = String::new();
    mani_str.push_str("[dependencies]\n");

    for &(ref name, ref ver) in deps {
        mani_str.push_str(name);
        mani_str.push_str("=");

        // We only want to quote the version if it *isn't* a table.
        let quotes = match ver.starts_with("{") { true => "", false => "\"" };
        mani_str.push_str(quotes);
        mani_str.push_str(ver);
        mani_str.push_str(quotes);
        mani_str.push_str("\n");
    }

    toml::Parser::new(&mani_str).parse()
        .ok_or("could not parse dependency manifest".into())
}

/**
Given two Cargo manifests, merges the second *into* the first.

Note that the "merge" in this case is relatively simple: only *top-level* tables are actually merged; everything else is just outright replaced.
*/
fn merge_manifest(mut into_t: toml::Table, from_t: toml::Table) -> Result<toml::Table> {
    for (k, v) in from_t {
        match v {
            toml::Value::Table(from_t) => {
                use std::collections::btree_map::Entry::*;

                // Merge.
                match into_t.entry(k) {
                    Vacant(e) => {
                        e.insert(toml::Value::Table(from_t));
                    },
                    Occupied(e) => {
                        let into_t = try!(as_table_mut(e.into_mut())
                            .ok_or((Blame::Human, "cannot merge manifests: cannot merge \
                                table and non-table values")));
                        into_t.extend(from_t);
                    }
                }
            },
            v => {
                // Just replace.
                into_t.insert(k, v);
            },
        }
    }

    return Ok(into_t);

    fn as_table_mut(t: &mut toml::Value) -> Option<&mut toml::Table> {
        match *t {
            toml::Value::Table(ref mut t) => Some(t),
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>pub mod variables;
pub mod relationships;
pub mod expressions;

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use math::variables::{AbstVar, new_var, new_const};
    use math::relationships::Relationship;
    use math::expressions::Expression;

    #[test]
    fn can_create_variables() {
        let v: AbstVar = new_var("x", 2.0);
        assert_eq!(AbstVar::Variable {
                       name: "x".to_string(),
                       coefficient: 2.0,
                   },
                   v);
        assert_eq!("x", v.name());
        assert_eq!(2.0, v.coefficient());
    }

    #[test]
    fn can_set_coefficient() {
        let abst_var_state: RefCell<AbstVar> = RefCell::new(new_var("x", 2.0));
        {
            let mut abst_var = abst_var_state.borrow_mut();
            abst_var.set_coefficient(3.0);
        }
        assert_eq!(3.0, abst_var_state.borrow().coefficient());
    }

    #[test]
    fn can_set_value() {
        let abst_var_state: RefCell<AbstVar> = RefCell::new(new_const("days", 365.0));
        {
            let mut abst_var = abst_var_state.borrow_mut();
            abst_var.set_value(366.0);
        }
        assert_eq!(366.0, abst_var_state.borrow().value());
    }

    #[test]
    fn can_create_constants() {
        let c: AbstVar = new_const("barrels in stock", 450.0);
        assert_eq!(AbstVar::Constant {
                       name: "barrels in stock".to_string(),
                       value: 450.0,
                   },
                   c);
        assert_eq!("barrels in stock", c.name());
        assert_eq!(450.0, c.value());
    }

    #[test]
    fn can_create_relationships() {
        let r: Relationship = Relationship::EQ;
        assert_eq!(Relationship::EQ, r);
        let r: Relationship = Relationship::LEQ;
        assert_eq!(Relationship::LEQ, r);
        let r: Relationship = Relationship::GEQ;
        assert_eq!(Relationship::GEQ, r);
    }

    #[test]
    fn can_create_expressions() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        assert_eq!("Z", e.lhs()[0].name());
        assert_eq!(1.0, e.lhs()[0].coefficient());
        assert_eq!(Relationship::EQ, *e.rel());
        assert_eq!("x", e.rhs()[0].name());
        assert_eq!(2.0, e.rhs()[0].coefficient());
        assert_eq!("y", e.rhs()[1].name());
        assert_eq!(3.0, e.rhs()[1].coefficient());
        assert_eq!("bonus", e.rhs()[2].name());
        assert_eq!(1000.0, e.rhs()[2].value());
    }

    #[test]
    fn can_mul_both_sides_of_expressions() {
        let mut e1: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::GEQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        e1.mul_both_sides(-1.0);
        assert_eq!("Z", e1.lhs()[0].name());
        assert_eq!(-1.0, e1.lhs()[0].coefficient());
        assert_eq!(Relationship::LEQ, *e1.rel());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].coefficient());
        assert_eq!("y", e1.rhs()[1].name());
        assert_eq!(-3.0, e1.rhs()[1].coefficient());
        assert_eq!("bonus", e1.rhs()[2].name());
        assert_eq!(-1000.0, e1.rhs()[2].value());
    }
}
<commit_msg>Refactored order of tests.<commit_after>pub mod variables;
pub mod relationships;
pub mod expressions;

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use math::variables::{AbstVar, new_var, new_const};
    use math::relationships::Relationship;
    use math::expressions::Expression;

    #[test]
    fn can_create_variables() {
        let v: AbstVar = new_var("x", 2.0);
        assert_eq!(AbstVar::Variable {
                       name: "x".to_string(),
                       coefficient: 2.0,
                   },
                   v);
        assert_eq!("x", v.name());
        assert_eq!(2.0, v.coefficient());
    }

    #[test]
    fn can_set_coefficient() {
        let abst_var_state: RefCell<AbstVar> = RefCell::new(new_var("x", 2.0));
        {
            let mut abst_var = abst_var_state.borrow_mut();
            abst_var.set_coefficient(3.0);
        }
        assert_eq!(3.0, abst_var_state.borrow().coefficient());
    }

    #[test]
    fn can_create_constants() {
        let c: AbstVar = new_const("barrels in stock", 450.0);
        assert_eq!(AbstVar::Constant {
                       name: "barrels in stock".to_string(),
                       value: 450.0,
                   },
                   c);
        assert_eq!("barrels in stock", c.name());
        assert_eq!(450.0, c.value());
    }

    #[test]
    fn can_set_value() {
        let abst_var_state: RefCell<AbstVar> = RefCell::new(new_const("days", 365.0));
        {
            let mut abst_var = abst_var_state.borrow_mut();
            abst_var.set_value(366.0);
        }
        assert_eq!(366.0, abst_var_state.borrow().value());
    }

    #[test]
    fn can_create_relationships() {
        let r: Relationship = Relationship::EQ;
        assert_eq!(Relationship::EQ, r);
        let r: Relationship = Relationship::LEQ;
        assert_eq!(Relationship::LEQ, r);
        let r: Relationship = Relationship::GEQ;
        assert_eq!(Relationship::GEQ, r);
    }

    #[test]
    fn can_create_expressions() {
        let e: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::EQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        assert_eq!("Z", e.lhs()[0].name());
        assert_eq!(1.0, e.lhs()[0].coefficient());
        assert_eq!(Relationship::EQ, *e.rel());
        assert_eq!("x", e.rhs()[0].name());
        assert_eq!(2.0, e.rhs()[0].coefficient());
        assert_eq!("y", e.rhs()[1].name());
        assert_eq!(3.0, e.rhs()[1].coefficient());
        assert_eq!("bonus", e.rhs()[2].name());
        assert_eq!(1000.0, e.rhs()[2].value());
    }

    #[test]
    fn can_mul_both_sides_of_expressions() {
        let mut e1: Expression =
            Expression::new(vec![new_var("Z", 1.0)],
                            Relationship::GEQ,
                            vec![new_var("x", 2.0), new_var("y", 3.0), new_const("bonus", 1000.0)]);
        e1.mul_both_sides(-1.0);
        assert_eq!("Z", e1.lhs()[0].name());
        assert_eq!(-1.0, e1.lhs()[0].coefficient());
        assert_eq!(Relationship::LEQ, *e1.rel());
        assert_eq!("x", e1.rhs()[0].name());
        assert_eq!(-2.0, e1.rhs()[0].coefficient());
        assert_eq!("y", e1.rhs()[1].name());
        assert_eq!(-3.0, e1.rhs()[1].coefficient());
        assert_eq!("bonus", e1.rhs()[2].name());
        assert_eq!(-1000.0, e1.rhs()[2].value());
    }
}
<|endoftext|>


<commit_before>use super::errors::*;
use cargo_metadata::Package;
use std::convert::TryInto;
use std::path::Path;

/// Takes a pkgid and attempts to find the path to it's `Cargo.toml`, using `cargo`'s metadata
pub fn manifest_from_pkgid(manifest_path: Option<&Path>, pkgid: &str) -> CargoResult<Package> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    let result = cmd.exec().with_context(|| "Invalid manifest")?;
    let packages = result.packages;
    let package = packages
        .into_iter()
        .find(|pkg| pkg.name == pkgid)
        .with_context(|| {
            "Found virtual manifest, but this command requires running against an \
             actual package in this workspace. Try adding `--workspace`."
        })?;
    Ok(package)
}

/// Lookup all members of the current workspace
pub fn workspace_members(manifest_path: Option<&Path>) -> CargoResult<Vec<Package>> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    let result = cmd.exec().with_context(|| "Invalid manifest")?;
    let workspace_members: std::collections::HashSet<_> =
        result.workspace_members.into_iter().collect();
    let workspace_members: Vec<_> = result
        .packages
        .into_iter()
        .filter(|p| workspace_members.contains(&p.id))
        .map(|mut p| {
            p.manifest_path = canonicalize_path(p.manifest_path);
            for dep in p.dependencies.iter_mut() {
                dep.path = dep.path.take().map(canonicalize_path);
            }
            p
        })
        .collect();
    Ok(workspace_members)
}

fn canonicalize_path(
    path: cargo_metadata::camino::Utf8PathBuf,
) -> cargo_metadata::camino::Utf8PathBuf {
    if let Ok(path) = dunce::canonicalize(&path) {
        if let Ok(path) = path.try_into() {
            return path;
        }
    }

    path
}
<commit_msg>fix(set-version): Ensure determinism when processing<commit_after>use super::errors::*;
use cargo_metadata::Package;
use std::convert::TryInto;
use std::path::Path;

/// Takes a pkgid and attempts to find the path to it's `Cargo.toml`, using `cargo`'s metadata
pub fn manifest_from_pkgid(manifest_path: Option<&Path>, pkgid: &str) -> CargoResult<Package> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    let result = cmd.exec().with_context(|| "Invalid manifest")?;
    let packages = result.packages;
    let package = packages
        .into_iter()
        .find(|pkg| pkg.name == pkgid)
        .with_context(|| {
            "Found virtual manifest, but this command requires running against an \
             actual package in this workspace. Try adding `--workspace`."
        })?;
    Ok(package)
}

/// Lookup all members of the current workspace
pub fn workspace_members(manifest_path: Option<&Path>) -> CargoResult<Vec<Package>> {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.no_deps();
    if let Some(manifest_path) = manifest_path {
        cmd.manifest_path(manifest_path);
    }
    let result = cmd.exec().with_context(|| "Invalid manifest")?;
    let workspace_members: std::collections::BTreeSet<_> =
        result.workspace_members.into_iter().collect();
    let workspace_members: Vec<_> = result
        .packages
        .into_iter()
        .filter(|p| workspace_members.contains(&p.id))
        .map(|mut p| {
            p.manifest_path = canonicalize_path(p.manifest_path);
            for dep in p.dependencies.iter_mut() {
                dep.path = dep.path.take().map(canonicalize_path);
            }
            p
        })
        .collect();
    Ok(workspace_members)
}

fn canonicalize_path(
    path: cargo_metadata::camino::Utf8PathBuf,
) -> cargo_metadata::camino::Utf8PathBuf {
    if let Ok(path) = dunce::canonicalize(&path) {
        if let Ok(path) = path.try_into() {
            return path;
        }
    }

    path
}
<|endoftext|>


<commit_before>#![allow(unused)]

use std;
use tokio_core::reactor::{Handle};
use futures;
use futures::future::Future;
use futures::sink::Sink;
use futures::stream::Stream;
use tokio_io::{self,AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;
use std::net::SocketAddr;

use std::rc::Rc;
use std::cell::RefCell;

use futures::Async::{Ready, NotReady};

use tokio_core::net::{TcpStream, TcpListener, UdpSocket};

use super::{Peer, io_other_error, brokenpipe, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, peer_err, peer_err_s, box_up_err};

/*
struct RcReadProxy<R>(Rc<R>) where for<'a> &'a R : AsyncRead;

impl<R> AsyncRead for RcReadProxy<R> where for<'a> &'a R : AsyncRead{}
impl<R> Read for RcReadProxy<R> where for<'a> &'a R : AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        (&*self.0).read(buf)
    }
}

struct RcWriteProxy<W>(Rc<W>) where for<'a> &'a W : AsyncWrite;

impl<W> AsyncWrite for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        (&*self.0).shutdown()
    }
}
impl<W> Write for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }
    fn flush(&mut self) -> IoResult<()> {
        (&*self.0).flush()
    }
}
*/

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyTcpStream(Rc<TcpStream>);

impl Read for MyTcpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyTcpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyTcpStream {}

impl AsyncWrite for MyTcpStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

pub fn tcp_connect_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        TcpStream::connect(&addr, handle).map(|x| {
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone()), MyTcpStream(x.clone()))
        }).map_err(box_up_err)
    ) as BoxedNewPeerFuture
}

pub fn tcp_listen_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerStream {
    let bound = match TcpListener::bind(&addr, handle) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    Box::new(
        bound
        .incoming()
        .map(|(x, _addr)| {
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone()), MyTcpStream(x.clone()))
        })
        .map_err(|e|box_up_err(e))
    ) as BoxedNewPeerStream
}

<commit_msg>Shutdown TCP read<commit_after>#![allow(unused)]

use std;
use tokio_core::reactor::{Handle};
use futures;
use futures::future::Future;
use futures::sink::Sink;
use futures::stream::Stream;
use tokio_io::{self,AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;
use std::net::SocketAddr;

use std::rc::Rc;
use std::cell::RefCell;

use futures::Async::{Ready, NotReady};

use tokio_core::net::{TcpStream, TcpListener, UdpSocket};

use super::{Peer, io_other_error, brokenpipe, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, peer_err, peer_err_s, box_up_err};

/*
struct RcReadProxy<R>(Rc<R>) where for<'a> &'a R : AsyncRead;

impl<R> AsyncRead for RcReadProxy<R> where for<'a> &'a R : AsyncRead{}
impl<R> Read for RcReadProxy<R> where for<'a> &'a R : AsyncRead {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        (&*self.0).read(buf)
    }
}

struct RcWriteProxy<W>(Rc<W>) where for<'a> &'a W : AsyncWrite;

impl<W> AsyncWrite for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        (&*self.0).shutdown()
    }
}
impl<W> Write for RcWriteProxy<W> where for<'a> &'a W : AsyncWrite {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }
    fn flush(&mut self) -> IoResult<()> {
        (&*self.0).flush()
    }
}
*/

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyTcpStream(Rc<TcpStream>, bool);

impl Read for MyTcpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyTcpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyTcpStream {}

impl AsyncWrite for MyTcpStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyTcpStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn tcp_connect_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerFuture {
    Box::new(
        TcpStream::connect(&addr, handle).map(|x| {
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
        }).map_err(box_up_err)
    ) as BoxedNewPeerFuture
}

pub fn tcp_listen_peer(handle: &Handle, addr: &SocketAddr) -> BoxedNewPeerStream {
    let bound = match TcpListener::bind(&addr, handle) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    Box::new(
        bound
        .incoming()
        .map(|(x, _addr)| {
            let x = Rc::new(x);
            Peer::new(MyTcpStream(x.clone(), true), MyTcpStream(x.clone(), false))
        })
        .map_err(|e|box_up_err(e))
    ) as BoxedNewPeerStream
}

<|endoftext|>


<commit_before>/* This file is part of Grust, GObject introspection bindings for Rust
 *
 * Copyright (C) 2013  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

extern mod grust (name="grust", vers="0.1");
extern mod gio (name="grust-Gio", vers="2.0");

extern mod std;

use core::result::{Result,Ok};
use core::comm::stream;
use core::task::TaskResult;
use core::util;
use std::timer::sleep;
// use std::timer::recv_timeout;
use std::uv_global_loop;
use grust::eventloop::EventLoop;

// We have to do this because of an rpath problem with crates linking to
// foreign libraries
extern mod grustna {
}

// Test timeout in milliseconds
static TEST_TIMEOUT: uint = 3000u;

fn tcase(test: ~fn()) {
    grust::init();

    let mut (port, _) = stream::<TaskResult>();
    task::task()
        .future_result(|p| {
            port = p;
        })
        .spawn(|| {
            test();
            debug!("test completed");
        });
    match Some(port.recv()) /* recv_timeout(&uv_global_loop::get(), TEST_TIMEOUT, &port) */ {
        Some(task::Success) => {}
        Some(task::Failure) => {
            fail!(~"test failed");
        }
        None => {
            error!("test timed out");
            unsafe { libc::abort(); }
        }
    }
}

fn tcase_result(test: ~fn() -> Result<(),()>) {
    do tcase {
        let result = test();
        assert!(result == Ok(()));
    }
}

#[test]
fn simple() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        let f = fobj.interface() as &gio::File;
        assert!(f.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn as_interface() {
    do tcase {
        gio::File::new_for_path("/dev/null").as_interface(|fobj| {
                let f = fobj as &gio::File;
                assert!(f.get_path().to_str() == ~"/dev/null");
            });
    }
}

#[test]
fn new_ref() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        let gobj = fobj.interface().new_ref();
        let g = gobj.interface() as &gio::File;
        assert!(g.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn clone() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        fobj.clone().as_interface(|gobj| {
                let g = gobj as &gio::File;
                assert!(g.get_path().to_str() == ~"/dev/null");
            });
    }
}

#[test]
fn off_stack() {
    do tcase_result {
        let f = ~gio::File::new_for_path("/dev/null");
        do task::try {
            let f = f.interface() as &gio::File;
            let p = f.get_path();
            assert!(p.to_str() == ~"/dev/null");
        }
    }
}

#[test]
fn off_stack_as_interface() {
    do tcase_result {
        let f = ~gio::File::new_for_path("/dev/null");
        do task::try {
            let f = f.interface() as &gio::File;
            let p = f.get_path();
            assert!(p.to_str() == ~"/dev/null");
        }
    }
}

#[test]
fn async() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        let f = fobj.interface() as &gio::File;
        let el = EventLoop::new();
        let elo = ~el.clone();
        f.read_async(0, None,
                |obj, res| {
                    let f: &gio::File = obj.cast::<gio::raw::GFile>()
                                        as &gio::File;
                    let in = f.read_finish(res);
                    util::ignore(in);
                    elo.quit();
                });
        el.run();
    }
}

#[test]
fn async_off_stack() {
    do tcase {
        let fobj = ~gio::File::new_for_path("/dev/null");
        let el = EventLoop::new();
        let elo = ~el.clone();
        task::spawn_sched(task::ThreadPerCore, || {
            let f = fobj.interface() as &gio::File;

            // Give the event loop time to start
            sleep(&uv_global_loop::get(), 100);

            let elo2 = ~elo.clone();
            f.read_async(0, None, |obj, res| {
                    let f: &gio::File = obj.cast::<gio::raw::GFile>()
                                        as &gio::File;
                    f.read_finish(res);
                    elo2.quit();
                });
        });
        el.run();
    }
}
<commit_msg>Various test suite improvements<commit_after>/* This file is part of Grust, GObject introspection bindings for Rust
 *
 * Copyright (C) 2013  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

extern mod grust (name="grust", vers="0.1");
extern mod gio (name="grust-Gio", vers="2.0");

extern mod std;

use core::result::{Result,Ok};
use core::comm::{Port,stream};
use core::task::TaskResult;
use core::util;
use std::timer::sleep;
// use std::timer::recv_timeout;
use std::uv_global_loop;
use grust::eventloop::EventLoop;

// We have to do this because of an rpath problem with crates linking to
// foreign libraries
extern mod grustna {
}

// Test timeout in milliseconds
static TEST_TIMEOUT: uint = 3000u;

fn spawn_with_future(func: ~fn()) -> Port<TaskResult> {
    let mut (port, _) = stream::<TaskResult>();
    task::task()
        .future_result(|p| {
            port = p;
        })
        .spawn(func);
    port
}

fn tcase(test: ~fn()) {
    grust::init();

    let port = spawn_with_future(test);

    match Some(port.recv()) /* recv_timeout(&uv_global_loop::get(), TEST_TIMEOUT, &port) */ {
        Some(task::Success) => {}
        Some(task::Failure) => {
            fail!(~"test failed");
        }
        None => {
            error!("test timed out");
            unsafe { libc::abort(); }
        }
    }
}

fn tcase_result(test: ~fn() -> Result<(),()>) {
    do tcase {
        let result = test();
        assert!(result == Ok(()));
    }
}

#[test]
fn simple() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        let f = fobj.interface() as &gio::File;
        assert!(f.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn as_interface() {
    do tcase {
        gio::File::new_for_path("/dev/null").as_interface(|fobj| {
                let f = fobj as &gio::File;
                assert!(f.get_path().to_str() == ~"/dev/null");
            });
    }
}

#[test]
fn new_ref() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        let gobj = fobj.interface().new_ref();
        let g = gobj.interface() as &gio::File;
        assert!(g.get_path().to_str() == ~"/dev/null");
    }
}

#[test]
fn clone() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        fobj.clone().as_interface(|gobj| {
                let g = gobj as &gio::File;
                assert!(g.get_path().to_str() == ~"/dev/null");
            });
    }
}

#[test]
fn off_task() {
    do tcase_result {
        let f = ~gio::File::new_for_path("/dev/null");
        do task::try {
            let f = f.interface() as &gio::File;
            let p = f.get_path();
            assert!(p.to_str() == ~"/dev/null");
        }
    }
}

#[test]
fn off_task_as_interface() {
    do tcase_result {
        let fobj = ~gio::File::new_for_path("/dev/null");
        do task::try {
            fobj.as_interface(|fifa| {
                    let f = fifa as &gio::File;
                    let p = f.get_path();
                    assert!(p.to_str() == ~"/dev/null");
                });
        }
    }
}

#[test]
fn async() {
    do tcase {
        let fobj = gio::File::new_for_path("/dev/null");
        let f = fobj.interface() as &gio::File;
        let el = EventLoop::new();
        let elo = ~el.clone();
        f.read_async(0, None,
                |obj, res| {
                    let f: &gio::File = obj.cast::<gio::raw::GFile>()
                                        as &gio::File;
                    let in = f.read_finish(res);
                    util::ignore(in);
                    elo.quit();
                });
        el.run();
    }
}

#[test]
fn async_off_stack() {
    do tcase {
        let fobj = ~gio::File::new_for_path("/dev/null");
        let el = EventLoop::new();
        let elo = ~el.clone();
        task::spawn_sched(task::ThreadPerCore, || {
            let f = fobj.interface() as &gio::File;

            // Give the event loop time to start
            sleep(&uv_global_loop::get(), 100);

            let elo2 = ~elo.clone();
            f.read_async(0, None, |obj, res| {
                    let f = obj.cast::<gio::raw::GFile>() as &gio::File;
                    f.read_finish(res);
                    elo2.quit();
                });
        });
        el.run();
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};
use conhash::Node;
use num::FromPrimitive;

use errors::BMemcachedError;

enum Type {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Command {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Success = 0x00,
        KeyNotFound = 0x01,
        KeyExists = 0x02,
        AuthError = 0x08,
        UnknownCommand = 0x81
    }
}

#[derive(Debug)]
pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

#[derive(Debug)]
pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Protocol, BMemcachedError> {
        Ok(Protocol{connection: try!(TcpStream::connect(addr))})
    }

    pub fn connection_info(&self) -> String {
        format!("{:?}", self.connection.peer_addr().unwrap())
    }

    fn build_request(command: Command, key_length: usize, value_length: usize, data_type: u8,
        extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Type::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0,
            body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: cas
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> Result<(), BMemcachedError> {
        let mut buf = &self.connection;
        try!(buf.write_u8(request.magic));
        try!(buf.write_u8(request.opcode));
        try!(buf.write_u16::<BigEndian>(request.key_length));
        try!(buf.write_u8(request.extras_length));
        try!(buf.write_u8(request.data_type));
        try!(buf.write_u16::<BigEndian>(request.reserved));
        try!(buf.write_u32::<BigEndian>(request.body_length));
        try!(buf.write_u32::<BigEndian>(request.opaque));
        try!(buf.write_u64::<BigEndian>(request.cas));
        try!(buf.write(final_payload));
        Ok(())
    }

    fn read_response(&mut self) -> Result<Response, BMemcachedError> {
        let mut buf = &self.connection;
        let magic: u8 = try!(buf.read_u8());
        if magic != Type::Response as u8 {
            // TODO Consume the stream, disconnect or something?
            debug!("Server sent an unknown magic code {:?}", magic);
            return Err(BMemcachedError::UnkownError("Server sent an unknown magic code"))
        }
        Ok(Response {
            magic: magic,
            opcode: try!(buf.read_u8()),
            key_length: try!(buf.read_u16::<BigEndian>()),
            extras_length: try!(buf.read_u8()),
            data_type: try!(buf.read_u8()),
            status: try!(buf.read_u16::<BigEndian>()),
            body_length: try!(buf.read_u32::<BigEndian>()),
            opaque: try!(buf.read_u32::<BigEndian>()),
            cas: try!(buf.read_u64::<BigEndian>())
        })
    }

    fn set_add_replace<K, V>(&mut self, command: Command, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        let key = key.as_ref();
        let value = value.as_ref();
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        try!(final_payload.write_u32::<BigEndian>(0));
        try!(final_payload.write_u32::<BigEndian>(time));
        // After flags key and value
        try!(final_payload.write(key));
        try!(final_payload.write(value));
        let size = try!(self.write_request(request, final_payload.as_slice()));
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(rest) => Err(BMemcachedError::Status(rest)),
            None => Err(BMemcachedError::UnkownError("Server returned an unknown status code"))
        }
    }

    pub fn set<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Set, key, value, time)
    }

    pub fn add<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Add, key, value, time)
    }

    pub fn replace<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Replace, key, value, time)
    }

    pub fn get<K>(&mut self, key: K) -> Result<String, BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => {},
            Some(status) => return Err(BMemcachedError::Status(status)),
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        };
        // Discard extras for now
        try!(self.connection.read_u32::<BigEndian>());
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        try!(self.connection.read_exact(&mut outbuf));
        Ok(try!(String::from_utf8(outbuf)))
    }

    pub fn delete<K>(&mut self, key: K) -> Result<(), BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Delete, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());

        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(Status::KeyNotFound) => Ok(()),
            Some(status) => return Err(BMemcachedError::Status(status)),
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        }
    }
}
#[cfg(test)]
mod tests {
    extern crate env_logger;
    use errors::BMemcachedError;
    use super::*;

    #[test]
    fn set_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        p.delete(key).unwrap();
    }

    #[test]
    fn add_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello Add";
        let value = "World";
        p.add(key, value, 10).unwrap();
        let result = p.add(key, value, 10);
        match result {
            Ok(()) => panic!("Add key should return error"),
            Err(BMemcachedError::Status(Status::KeyExists)) => {},
            Err(_) => panic!("Some strange error that should not happen")
        };
        p.delete(key).unwrap();
    }

    #[test]
    fn get_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        assert_eq!(p.get(key).unwrap(),  value);
        match p.get("not found".to_string()) {
            Ok(_) => panic!("This key should not exist"),
            Err(BMemcachedError::Status(Status::KeyNotFound)) => {},
            Err(_) => panic!("This should return KeyNotFound")
        };
        p.delete(key).unwrap();
    }

    #[test]
    fn delete_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        p.delete(key).unwrap();
        p.delete(key).unwrap();
    }
}
<commit_msg>Implement delete and consume body when errors happen<commit_after>use std::io::{Read, Write};
use std::mem::size_of;
use std::net::{
    TcpStream,
    ToSocketAddrs
};

use byteorder::{ReadBytesExt, BigEndian, WriteBytesExt};
use conhash::Node;
use num::FromPrimitive;

use errors::BMemcachedError;

enum Type {
    Request = 0x80,
    Response = 0x81
}

#[derive(Debug)]
enum Command {
    Get = 0x00,
    Set = 0x01,
    Add = 0x02,
    Replace = 0x03,
    Delete = 0x04,
    Increment = 0x05,
    Decrement = 0x06,
    Quit = 0x07,
    Flush = 0x08,
    GetQ = 0x09,
    NoOp = 0x0A,
    Version = 0x0B,
    GetK = 0x0C,
    GetKQ = 0x0D,
    Append = 0x0E,
    Prepend = 0x0F,
    Stat = 0x10,
    SetQ = 0x11,
    AddQ = 0x12,
    ReplaceQ = 0x13,
    DeleteQ = 0x14,
    IncrementQ = 0x15,
    DecrementQ = 0x16,
    QuitQ = 0x17,
    FlushQ = 0x18,
    AppendQ = 0x19,
    PrependQ = 0x1A
}

enum_from_primitive! {
    #[derive(Debug, PartialEq)]
    pub enum Status {
        Success = 0x00,
        KeyNotFound = 0x01,
        KeyExists = 0x02,
        AuthError = 0x08,
        UnknownCommand = 0x81
    }
}

#[derive(Debug)]
pub struct Request {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    reserved: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

#[derive(Debug)]
pub struct Response {
    magic: u8,
    opcode: u8,
    key_length: u16,
    extras_length: u8,
    data_type: u8,
    status: u16,
    body_length: u32,
    opaque: u32,
    cas: u64
}

pub struct SetAddReplace {
    flags: u32,
    expiration: u32
}

#[derive(Debug)]
pub struct Protocol {
    connection: TcpStream
}

impl Protocol {
    pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Protocol, BMemcachedError> {
        Ok(Protocol{connection: try!(TcpStream::connect(addr))})
    }

    pub fn connection_info(&self) -> String {
        format!("{:?}", self.connection.peer_addr().unwrap())
    }

    fn build_request(command: Command, key_length: usize, value_length: usize, data_type: u8,
        extras_length: usize, cas: u64) -> Request {
        Request {
            magic: Type::Request as u8, opcode: command as u8,
            key_length: key_length as u16,
            extras_length: extras_length as u8,
            data_type: data_type, reserved: 0,
            body_length: (key_length + value_length + extras_length) as u32,
            opaque: 0, cas: cas
        }
    }

    fn write_request(&self, request: Request, final_payload: &[u8]) -> Result<(), BMemcachedError> {
        let mut buf = &self.connection;
        try!(buf.write_u8(request.magic));
        try!(buf.write_u8(request.opcode));
        try!(buf.write_u16::<BigEndian>(request.key_length));
        try!(buf.write_u8(request.extras_length));
        try!(buf.write_u8(request.data_type));
        try!(buf.write_u16::<BigEndian>(request.reserved));
        try!(buf.write_u32::<BigEndian>(request.body_length));
        try!(buf.write_u32::<BigEndian>(request.opaque));
        try!(buf.write_u64::<BigEndian>(request.cas));
        try!(buf.write(final_payload));
        Ok(())
    }

    fn read_response(&mut self) -> Result<Response, BMemcachedError> {
        let mut buf = &self.connection;
        let magic: u8 = try!(buf.read_u8());
        if magic != Type::Response as u8 {
            // TODO Consume the stream, disconnect or something?
            debug!("Server sent an unknown magic code {:?}", magic);
            return Err(BMemcachedError::UnkownError("Server sent an unknown magic code"))
        }
        Ok(Response {
            magic: magic,
            opcode: try!(buf.read_u8()),
            key_length: try!(buf.read_u16::<BigEndian>()),
            extras_length: try!(buf.read_u8()),
            data_type: try!(buf.read_u8()),
            status: try!(buf.read_u16::<BigEndian>()),
            body_length: try!(buf.read_u32::<BigEndian>()),
            opaque: try!(buf.read_u32::<BigEndian>()),
            cas: try!(buf.read_u64::<BigEndian>())
        })
    }

    fn consume_body(&mut self, size: u32) {
        debug!("Consuming body");
        let mut buf: Vec<u8> = vec![0; size as usize];
        self.connection.read(&mut *buf);
        let str_buf = String::from_utf8(buf).unwrap();
        debug!("Consumed body {:?}", str_buf);
    }

    fn set_add_replace<K, V>(&mut self, command: Command, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        let key = key.as_ref();
        let value = value.as_ref();
        let extras_length = size_of::<SetAddReplace>();
        let request = Protocol::build_request(command, key.len(), value.len(), 0x00, extras_length, 0x00);
        let mut final_payload = vec![];
        // Flags
        try!(final_payload.write_u32::<BigEndian>(0));
        try!(final_payload.write_u32::<BigEndian>(time));
        // After flags key and value
        try!(final_payload.write(key));
        try!(final_payload.write(value));
        let size = try!(self.write_request(request, final_payload.as_slice()));
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(rest) => {
                self.consume_body(response.body_length);
                Err(BMemcachedError::Status(rest))
            },
            None => Err(BMemcachedError::UnkownError("Server returned an unknown status code"))
        }
    }

    pub fn set<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Set, key, value, time)
    }

    pub fn add<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Add, key, value, time)
    }

    pub fn replace<K, V>(&mut self, key: K, value: V, time: u32) -> Result<(), BMemcachedError>
        where K: AsRef<[u8]>, V: AsRef<[u8]> {
        self.set_add_replace(Command::Replace, key, value, time)
    }

    pub fn get<K>(&mut self, key: K) -> Result<String, BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Get, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());
        match Status::from_u16(response.status) {
            Some(Status::Success) => {},
            Some(status) => {
                self.consume_body(response.body_length);
                return Err(BMemcachedError::Status(status))
            },
            None => return Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        };
        // Discard extras for now
        try!(self.connection.read_u32::<BigEndian>());
        let mut outbuf = vec![0; (response.body_length - response.extras_length as u32) as usize];
        try!(self.connection.read_exact(&mut outbuf));
        Ok(try!(String::from_utf8(outbuf)))
    }

    pub fn delete<K>(&mut self, key: K) -> Result<(), BMemcachedError> where K: AsRef<[u8]> {
        let key = key.as_ref();
        let request = Protocol::build_request(Command::Delete, key.len(), 0 as usize, 0, 0, 0x00);
        self.write_request(request, key);
        let response = try!(self.read_response());

        match Status::from_u16(response.status) {
            Some(Status::Success) => Ok(()),
            Some(Status::KeyNotFound) => {
                self.consume_body(response.body_length);
                Ok(())
            },
            Some(status) => {
                self.consume_body(response.body_length);
                Err(BMemcachedError::Status(status))
            },
            None => Err(BMemcachedError::UnkownError("Server sent an unknown status code"))
        }
    }
}
#[cfg(test)]
mod tests {
    extern crate env_logger;
    use errors::BMemcachedError;
    use super::*;

    #[test]
    fn set_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        p.delete(key).unwrap();
    }

    #[test]
    fn add_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello Add";
        let value = "World";
        p.add(key, value, 10).unwrap();
        let result = p.add(key, value, 10);
        match result {
            Ok(()) => panic!("Add key should return error"),
            Err(BMemcachedError::Status(Status::KeyExists)) => {},
            Err(_) => panic!("Some strange error that should not happen")
        };
        p.delete(key);
    }

    #[test]
    fn get_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        assert_eq!(p.get(key).unwrap(),  value);
        match p.get("not found".to_string()) {
            Ok(_) => panic!("This key should not exist"),
            Err(BMemcachedError::Status(Status::KeyNotFound)) => {},
            Err(_) => panic!("This should return KeyNotFound")
        };
        p.delete(key).unwrap();
    }

    #[test]
    fn delete_key() {
        let _ = env_logger::init();
        let mut p = Protocol::connect("127.0.0.1:11211").unwrap();
        let key = "Hello";
        let value = "World";
        p.set(key, value, 100).unwrap();
        p.delete(key).unwrap();
        p.delete(key).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright(C) 2016 Chris Liebert
extern crate glium;
extern crate image;
extern crate nalgebra;

use std::collections::HashMap;
use std::io::Error;
use std::io::ErrorKind;

use common;
use common::{Camera, Mesh, Scene, Shader, Vertex8f32};
use loader::DBLoader;

use glium::backend::glutin_backend::GlutinFacade;
use glium::{Program, Surface, Version};

implement_vertex!(Vertex8f32, position, normal, texcoord);

pub struct Renderer {
	pub index_buffer: glium::index::NoIndices,
	pub scene: Scene,
	pub textures: HashMap<String, glium::texture::CompressedSrgbTexture2d>,
	pub vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>>,
}

impl Renderer {
	pub fn new(display: &GlutinFacade, scene: Scene) -> Renderer {

		let mut vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>> =
			Vec::with_capacity(scene.meshes.len());

		for i in 0..scene.meshes.len() {
			vertex_buffers.push(glium::vertex::VertexBuffer::new(display, &scene.meshes[i].vertices).unwrap());
		}

		let index_buffer: glium::index::NoIndices =
			glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

		let mut textures: HashMap<String, glium::texture::CompressedSrgbTexture2d> = HashMap::new();

		for i in 0..scene.images.len() {
			//TODO: determine image format by name extension if nessisary
			//let image = image::load_from_memory_with_format(&scene.images[i].image, image::PNG).unwrap().to_rgba();
			let image = image::load_from_memory(&scene.images[i].image).unwrap().to_rgba();

			let image_dimensions = image.dimensions();
			let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(),
			                                                               image_dimensions);
			let opengl_texture: glium::texture::CompressedSrgbTexture2d =
				glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
			textures.insert(scene.images[i].name.clone(), opengl_texture);
		}

		Renderer {
			index_buffer: index_buffer,
			scene: scene,
			textures: textures,
			vertex_buffers: vertex_buffers,
		}
	}

	pub fn get_mesh(&self, name: &str) -> Result<&Mesh, Error> {
		for i in 0..self.vertex_buffers.len() as usize {
			if self.scene.meshes[i].name.eq(name) {
				return Ok(&self.scene.meshes[i]);
			}
		}
		return Err(Error::new(ErrorKind::NotFound, "Unable to load mesh"));
	}

	#[allow(unused_assignments)]
	pub fn create_shader_program(&self, shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> glium::program::Program {
		let supported_glsl_version: Version = display.get_supported_glsl_version();
		let api: glium::Api = supported_glsl_version.0;
		let major_version : u8 = supported_glsl_version.1;
		let minor_version : u8 = supported_glsl_version.2;
		let mut glsl_version_string: String = major_version.to_string();
		glsl_version_string.push_str(&minor_version.to_string());
		glsl_version_string.push('0');
		let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

		match api {
				glium::Api::Gl => {
					use_gles = false;
				},
				glium::Api::GlEs => {
					use_gles = true;
					glsl_version_string.push_str(" es");
				},
		};

		let glsl_version_number: u32 = match glsl_version_string.parse() {
			Ok(s) => s,
			Err(e) =>  {
				// This is not likely to happen
				panic!("Unable to parse supported glsl version string: {}", e);
			},
		};

		println!("Using glsl version {}", &glsl_version_string);

		let shader: Shader = dbloader.load_shader(shader_name, &glsl_version_string);

		let program: Program;

		if use_gles {
			program = program!(display,
				glsl_version_number es => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		} else {
			program = program!(display,
				glsl_version_number => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		}

		// Shader compilation no longer required
		display.release_shader_compiler();
		return program;
	}

	pub fn create_shader_program_with_version(&self, shader_name: &str, dbloader: &DBLoader, glsl_version: &Version, display: &GlutinFacade) -> Result<glium::program::Program, Error> {
		if !display.is_glsl_version_supported(&glsl_version) {
			return Err(Error::new(ErrorKind::InvalidData, "Unsupported GLSL version"));
		}

		let api: glium::Api = glsl_version.0;
		let major_version : u8 = glsl_version.1;
		let minor_version : u8 = glsl_version.2;
		let mut glsl_version_string: String = major_version.to_string();
		glsl_version_string.push_str(&minor_version.to_string());
		glsl_version_string.push('0');
		let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

		match api {
				glium::Api::Gl => {
					use_gles = false;
				},
				glium::Api::GlEs => {
					use_gles = true;
					glsl_version_string.push_str(" es");
				},
		};

		let glsl_version_number: u32 = match glsl_version_string.parse() {
			Ok(s) => s,
			Err(e) =>  {
				// This is not likely to happen
				panic!("Unable to parse supported glsl version string: {}", e);
			},
		};

		println!("Using glsl version {}", &glsl_version_string);

		let shader: Shader = dbloader.load_shader(shader_name, &glsl_version_string);

		let program;

		if use_gles {
			program = program!(display,
				glsl_version_number es => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
		} else {
			program = program!(display,
				glsl_version_number => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
		}

		match program {
			Ok(p) => Ok(p),
			Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
		}
	}

	pub fn render(&self, display: &GlutinFacade, program: &glium::program::Program, camera: &Camera) {
		let mut target = display.draw();
		// TODO: generate this texture instead of loading from sqlite
		let default_blank_texture = &self.textures["DEFAULT_BLANK_TEXTURE.png"];
		target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
		for i in 0..self.vertex_buffers.len() as usize {
			let material_index: usize = self.scene.meshes[i].material_index.clone();
			let diffuse = self.scene.materials[material_index].diffuse.clone();
			let diffuse_texname: String =
				self.scene.materials[material_index].diffuse_texname.clone();
			let opengl_texture: &glium::texture::CompressedSrgbTexture2d;
			if diffuse_texname.len() == 0 {
				opengl_texture = &default_blank_texture;
			} else {
				match self.textures.get(&diffuse_texname) {
					Some(t) => {
						opengl_texture = &t;
					},
					None => {
						println!("Unable to load {}, using blank texture instead.", diffuse_texname);
						opengl_texture = &default_blank_texture;
					},
				}
			}
			let uniforms: glium::uniforms::UniformsStorage<_, _> = uniform! {
				projection: *camera.projection_matrix.borrow(),
				modelview: *camera.modelview_matrix.borrow(),
				light_position_worldspace: [2.0, 10.0, 1.0f32],
				diffuse: diffuse,
				diffuse_texture: opengl_texture,
				model: *(*self.scene.meshes[i].matrix.borrow()).as_ref(),
			};

			let params = glium::DrawParameters {
	            depth: glium::Depth {
	                test: glium::DepthTest::IfLess,
	                write: true,
	                .. Default::default()
	            },
	            .. Default::default()
	        };

			target.draw(&self.vertex_buffers[i],
				&self.index_buffer,
				program,
				&uniforms,
				&params)
				.unwrap();
		}
		target.finish().unwrap();
	}
}
<commit_msg>Fixed unused variable warning<commit_after>// Copyright(C) 2016 Chris Liebert
extern crate glium;
extern crate image;
extern crate nalgebra;

use std::collections::HashMap;
use std::io::Error;
use std::io::ErrorKind;

use common;
use common::{Camera, Mesh, Scene, Shader, Vertex8f32};
use loader::DBLoader;

use glium::backend::glutin_backend::GlutinFacade;
use glium::{Program, Surface, Version};

implement_vertex!(Vertex8f32, position, normal, texcoord);

pub struct Renderer {
	pub index_buffer: glium::index::NoIndices,
	pub scene: Scene,
	pub textures: HashMap<String, glium::texture::CompressedSrgbTexture2d>,
	pub vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>>,
}

impl Renderer {
	pub fn new(display: &GlutinFacade, scene: Scene) -> Renderer {

		let mut vertex_buffers: Vec<glium::vertex::VertexBuffer<common::Vertex8f32>> =
			Vec::with_capacity(scene.meshes.len());

		for i in 0..scene.meshes.len() {
			vertex_buffers.push(glium::vertex::VertexBuffer::new(display, &scene.meshes[i].vertices).unwrap());
		}

		let index_buffer: glium::index::NoIndices =
			glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

		let mut textures: HashMap<String, glium::texture::CompressedSrgbTexture2d> = HashMap::new();

		for i in 0..scene.images.len() {
			//TODO: determine image format by name extension if nessisary
			//let image = image::load_from_memory_with_format(&scene.images[i].image, image::PNG).unwrap().to_rgba();
			let image = image::load_from_memory(&scene.images[i].image).unwrap().to_rgba();

			let image_dimensions = image.dimensions();
			let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(),
			                                                               image_dimensions);
			let opengl_texture: glium::texture::CompressedSrgbTexture2d =
				glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
			textures.insert(scene.images[i].name.clone(), opengl_texture);
		}

		Renderer {
			index_buffer: index_buffer,
			scene: scene,
			textures: textures,
			vertex_buffers: vertex_buffers,
		}
	}

	pub fn get_mesh(&self, name: &str) -> Result<&Mesh, Error> {
		for i in 0..self.vertex_buffers.len() as usize {
			if self.scene.meshes[i].name.eq(name) {
				return Ok(&self.scene.meshes[i]);
			}
		}
		return Err(Error::new(ErrorKind::NotFound, "Unable to load mesh"));
	}

	#[allow(unused_assignments)]
	pub fn create_shader_program(&self, shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> glium::program::Program {
		let supported_glsl_version: Version = display.get_supported_glsl_version();
		let api: glium::Api = supported_glsl_version.0;
		let major_version : u8 = supported_glsl_version.1;
		let minor_version : u8 = supported_glsl_version.2;
		let mut glsl_version_string: String = major_version.to_string();
		glsl_version_string.push_str(&minor_version.to_string());
		glsl_version_string.push('0');
		let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

		match api {
				glium::Api::Gl => {
					use_gles = false;
				},
				glium::Api::GlEs => {
					use_gles = true;
					glsl_version_string.push_str(" es");
				},
		};

		let glsl_version_number: u32 = match glsl_version_string.parse() {
			Ok(s) => s,
			Err(e) =>  {
				// This is not likely to happen
				panic!("Unable to parse supported glsl version string: {}", e);
			},
		};

		println!("Using glsl version {}", &glsl_version_string);

		let shader: Shader = dbloader.load_shader(shader_name, &glsl_version_string);

		let program: Program;

		if use_gles {
			program = program!(display,
				glsl_version_number es => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		} else {
			program = program!(display,
				glsl_version_number => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
			.unwrap();
		}

		// Shader compilation no longer required
		display.release_shader_compiler();
		return program;
	}

	pub fn create_shader_program_with_version(&self, shader_name: &str, dbloader: &DBLoader, glsl_version: &Version, display: &GlutinFacade) -> Result<glium::program::Program, Error> {
		if !display.is_glsl_version_supported(&glsl_version) {
			return Err(Error::new(ErrorKind::InvalidData, "Unsupported GLSL version"));
		}

		let api: glium::Api = glsl_version.0;
		let major_version : u8 = glsl_version.1;
		let minor_version : u8 = glsl_version.2;
		let mut glsl_version_string: String = major_version.to_string();
		glsl_version_string.push_str(&minor_version.to_string());
		glsl_version_string.push('0');
		let mut _use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

		match api {
				glium::Api::Gl => {
					_use_gles = false;
				},
				glium::Api::GlEs => {
					_use_gles = true;
					glsl_version_string.push_str(" es");
				},
		};

		let glsl_version_number: u32 = match glsl_version_string.parse() {
			Ok(s) => s,
			Err(e) =>  {
				// This is not likely to happen
				panic!("Unable to parse supported glsl version string: {}", e);
			},
		};

		println!("Using glsl version {}", &glsl_version_string);

		let shader: Shader = dbloader.load_shader(shader_name, &glsl_version_string);

		let program;

		if _use_gles {
			program = program!(display,
				glsl_version_number es => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
		} else {
			program = program!(display,
				glsl_version_number => {
					vertex: &shader.vertex_source,
					fragment: &shader.fragment_source,
				},
			)
		}

		match program {
			Ok(p) => Ok(p),
			Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
		}
	}

	pub fn render(&self, display: &GlutinFacade, program: &glium::program::Program, camera: &Camera) {
		let mut target = display.draw();
		// TODO: generate this texture instead of loading from sqlite
		let default_blank_texture = &self.textures["DEFAULT_BLANK_TEXTURE.png"];
		target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
		for i in 0..self.vertex_buffers.len() as usize {
			let material_index: usize = self.scene.meshes[i].material_index.clone();
			let diffuse = self.scene.materials[material_index].diffuse.clone();
			let diffuse_texname: String =
				self.scene.materials[material_index].diffuse_texname.clone();
			let opengl_texture: &glium::texture::CompressedSrgbTexture2d;
			if diffuse_texname.len() == 0 {
				opengl_texture = &default_blank_texture;
			} else {
				match self.textures.get(&diffuse_texname) {
					Some(t) => {
						opengl_texture = &t;
					},
					None => {
						println!("Unable to load {}, using blank texture instead.", diffuse_texname);
						opengl_texture = &default_blank_texture;
					},
				}
			}
			let uniforms: glium::uniforms::UniformsStorage<_, _> = uniform! {
				projection: *camera.projection_matrix.borrow(),
				modelview: *camera.modelview_matrix.borrow(),
				light_position_worldspace: [2.0, 10.0, 1.0f32],
				diffuse: diffuse,
				diffuse_texture: opengl_texture,
				model: *(*self.scene.meshes[i].matrix.borrow()).as_ref(),
			};

			let params = glium::DrawParameters {
	            depth: glium::Depth {
	                test: glium::DepthTest::IfLess,
	                write: true,
	                .. Default::default()
	            },
	            .. Default::default()
	        };

			target.draw(&self.vertex_buffers[i],
				&self.index_buffer,
				program,
				&uniforms,
				&params)
				.unwrap();
		}
		target.finish().unwrap();
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// gpio_blinkled_signals.rs - Blinks an LED connected to a GPIO pin in a loop,
// while handling any incoming SIGINT (Ctrl-C) and SIGTERM signals so the
// pin's state can be reset before the application exits.
//
// Remember to add a resistor of an appropriate value in series, to prevent
// exceeding the maximum current rating of the GPIO pin and the LED.

use std::error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

// The simple-signal crate is used to handle incoming signals.
use simple_signal::{self, Signal};

use rppal::gpio::Gpio;

// Gpio uses BCM pin numbering. BCM GPIO 23 is tied to physical pin 16.
const GPIO_LED: u8 = 23;

fn main() -> Result<(), Box<dyn Error>> {
    // Retrieve the GPIO pin and configure it as an output.
    let mut pin = Gpio::new()?.get(GPIO_LED)?.into_output();

    // Clone running, so we can safely access it from within the signal handler.
    let running = Arc::new(AtomicBool::new(true));
    let r = running.clone();

    // When a SIGINT (Ctrl-C) or SIGTERM signal is caught, atomically set running to false.
    simple_signal::set_handler(&[Signal::Int, Signal::Term], move |_| {
        r.store(false, Ordering::SeqCst);
    });

    // Blink the LED until running is set to false.
    while running.load(Ordering::SeqCst) {
        pin.toggle();
        thread::sleep(Duration::from_millis(500));
    }

    // After we're done blinking, turn the LED off.
    pin.set_low();

    Ok(())

    // When the pin variable goes out of scope, the GPIO pin mode is automatically reset
    // to its original value, provided reset_on_drop is set to true (default).
}
<commit_msg>Group cloned data with closure definition<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// gpio_blinkled_signals.rs - Blinks an LED connected to a GPIO pin in a loop,
// while handling any incoming SIGINT (Ctrl-C) and SIGTERM signals so the
// pin's state can be reset before the application exits.
//
// Remember to add a resistor of an appropriate value in series, to prevent
// exceeding the maximum current rating of the GPIO pin and the LED.

use std::error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

// The simple-signal crate is used to handle incoming signals.
use simple_signal::{self, Signal};

use rppal::gpio::Gpio;

// Gpio uses BCM pin numbering. BCM GPIO 23 is tied to physical pin 16.
const GPIO_LED: u8 = 23;

fn main() -> Result<(), Box<dyn Error>> {
    // Retrieve the GPIO pin and configure it as an output.
    let mut pin = Gpio::new()?.get(GPIO_LED)?.into_output();

    let running = Arc::new(AtomicBool::new(true));

    // When a SIGINT (Ctrl-C) or SIGTERM signal is caught, atomically set running to false.
    simple_signal::set_handler(&[Signal::Int, Signal::Term], {
        let running = running.clone();
        move |_| {
            running.store(false, Ordering::SeqCst);
        }
    });

    // Blink the LED until running is set to false.
    while running.load(Ordering::SeqCst) {
        pin.toggle();
        thread::sleep(Duration::from_millis(500));
    }

    // After we're done blinking, turn the LED off.
    pin.set_low();

    Ok(())

    // When the pin variable goes out of scope, the GPIO pin mode is automatically reset
    // to its original value, provided reset_on_drop is set to true (default).
}
<|endoftext|>


<commit_before>use rustc_serialize::Decodable;

use rs_es::Client;
use rs_es::query::{Filter, Query};
use rs_es::operations::search::Sort;
use rs_es::operations::index::IndexResult;
use rs_es::operations::mapping::*;
use rs_es::error::EsError;

use params::*;

pub trait Resource : Decodable {
  fn search(mut es: &mut Client, default_index: &str, params: &Map) -> Vec<u32>;
  fn index(&self, mut es: &mut Client, index: &str) -> Result<IndexResult, EsError>;
  fn reset_index(mut es: &mut Client, index: &str) -> Result<MappingResult, EsError>;
  fn visibility_filters(epoch: &str, presented_talents: Vec<i32>) -> Vec<Filter>;
  fn search_filters(params: &Map, epoch: &str) -> Query;
  fn sorting_criteria() -> Sort;
}
<commit_msg>resource: require trait impls to implement Debug<commit_after>use rustc_serialize::Decodable;

use rs_es::Client;
use rs_es::query::{Filter, Query};
use rs_es::operations::search::Sort;
use rs_es::operations::index::IndexResult;
use rs_es::operations::mapping::*;
use rs_es::error::EsError;

use params::*;

use std::fmt::Debug;

pub trait Resource : Decodable + Debug {
  fn search(mut es: &mut Client, default_index: &str, params: &Map) -> Vec<u32>;
  fn index(&self, mut es: &mut Client, index: &str) -> Result<IndexResult, EsError>;
  fn reset_index(mut es: &mut Client, index: &str) -> Result<MappingResult, EsError>;
  fn visibility_filters(epoch: &str, presented_talents: Vec<i32>) -> Vec<Filter>;
  fn search_filters(params: &Map, epoch: &str) -> Query;
  fn sorting_criteria() -> Sort;
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;

#[cfg(not(windows))]
const CARGO_EXPAND_BIN: &str = "cargo-expand";

#[cfg(windows)]
const CARGO_EXPAND_BIN: &str = "cargo-expand.exe";

/// Scans paths in PATH env variable for a presence of `CARGO_EXPAND_BIN` file.
fn is_cargo_expand_present() -> bool {
    if let Ok(var) = env::var("PATH") {
        for path in var.split(":").map(PathBuf::from) {
            let cargo_expand_path = path.join(CARGO_EXPAND_BIN);
            if cargo_expand_path.exists() {
                return true;
            }
        }
    }

    false
}

pub fn main() {
    if is_cargo_expand_present() {
        println!("cargo:rustc-cfg=cargo_expand");
    }
}
<commit_msg>Rely on std::process::Command's path search<commit_after>use std::process::{Command, ExitStatus, Stdio};

#[cfg(not(windows))]
const CARGO_EXPAND: &str = "cargo-expand";

#[cfg(windows)]
const CARGO_EXPAND: &str = "cargo-expand.exe";

fn main() {
    if Command::new(CARGO_EXPAND)
        .arg("--version")
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status()
        .as_ref()
        .map(ExitStatus::success)
        .unwrap_or(false)
    {
        println!("cargo:rustc-cfg=cargo_expand");
    }
}
<|endoftext|>


<commit_before>use crate::{QCoreApplication, QString};
use std::iter::once;
use std::os::raw::{c_char, c_int};
use std::process;

/// A struct providing valid `argc` and `argv` values for Qt application
/// objects.
///
/// Constructors of `qt_core::core_application::CoreApplication`,
/// `qt_gui::gui_application::GuiApplication` and `qt_widgets::application::Application`
/// require `argc` and `argv` values that are available in C++'s `main` function but
/// not available in Rust. More importantly, `argc` and `argv` must be valid for the entire
/// life of the application. This struct stores list of arguments in a format compatible with
/// `argc` and `argv`, and can be used to initialize Qt application objects.
/// `CoreApplicationArgs` must live longer than the application object.
///
/// `CoreApplication::init` convenience function
/// and similar functions in the other application types
/// can be used instead of `CoreApplicationArgs`.
pub struct QCoreApplicationArgs {
    _values: Vec<Vec<u8>>,
    argc: Box<c_int>,
    argv: Vec<*mut c_char>,
}

impl QCoreApplicationArgs {
    /// Creates an object containing `args`.
    pub fn new() -> QCoreApplicationArgs {
        // Qt uses `QString::fromLocal8Bit()` to decode `argv`,
        // so we use `QString::toLocal8Bit()` to encode it.
        let mut args = std::env::args()
            .map(|arg| unsafe {
                QString::from_std_str(&arg)
                    .to_local8_bit()
                    .as_slice()
                    .iter()
                    .map(|&c| c as u8)
                    .chain(once(0))
                    .collect::<Vec<_>>()
            })
            .collect::<Vec<_>>();

        QCoreApplicationArgs {
            argc: Box::new(args.len() as c_int),
            argv: args
                .iter_mut()
                .map(|x| x.as_mut_ptr() as *mut c_char)
                .collect(),
            _values: args,
        }
    }

    /// Returns `(argc, argv)` values in the form accepted by the application objects'
    /// constructors.
    pub fn get(&mut self) -> (*mut c_int, *mut *mut c_char) {
        (self.argc.as_mut(), self.argv.as_mut_ptr())
    }
}

impl QCoreApplication {
    /// A convenience function for performing proper initialization and de-initialization of
    /// a Qt application.
    ///
    /// This function creates `CoreApplication` with valid `argc` and `argv`, calls the passed
    /// closure `f(app)` with the application object and exist the process with the exit code
    /// returned by the closure. The closure should perform the initialization of the application
    /// and either return immediately or call `CoreApplication::exec()` and return its return value:
    /// ```no_run
    /// use qt_core::QCoreApplication;
    ///
    /// fn main() {
    ///     QCoreApplication::init(|app| {
    ///         unsafe {
    ///             // initialization goes here
    ///             QCoreApplication::exec()
    ///         }
    ///     })
    /// }
    /// ```
    pub fn init<F: FnOnce(::cpp_core::Ptr<QCoreApplication>) -> i32>(f: F) -> ! {
        let exit_code = {
            unsafe {
                let mut args = QCoreApplicationArgs::new();
                let (argc, argv) = args.get();
                let app = QCoreApplication::new_2a(argc, argv);
                f(app.as_ptr())
            }
        }; // drop `app` and `args`
        process::exit(exit_code)
    }
}
<commit_msg>use boxed slice instead of Vec in QCoreApplicationArgs<commit_after>use crate::{QCoreApplication, QString};
use std::iter::once;
use std::os::raw::{c_char, c_int};
use std::process;

/// A struct providing valid `argc` and `argv` values for Qt application
/// objects.
///
/// Constructors of `qt_core::core_application::CoreApplication`,
/// `qt_gui::gui_application::GuiApplication` and `qt_widgets::application::Application`
/// require `argc` and `argv` values that are available in C++'s `main` function but
/// not available in Rust. More importantly, `argc` and `argv` must be valid for the entire
/// life of the application. This struct stores list of arguments in a format compatible with
/// `argc` and `argv`, and can be used to initialize Qt application objects.
/// `CoreApplicationArgs` must live longer than the application object.
///
/// `CoreApplication::init` convenience function
/// and similar functions in the other application types
/// can be used instead of `CoreApplicationArgs`.
pub struct QCoreApplicationArgs {
    _values: Vec<Vec<u8>>,
    argc: Box<c_int>,
    argv: Box<[*mut c_char]>,
}

impl QCoreApplicationArgs {
    /// Creates an object containing `args`.
    pub fn new() -> QCoreApplicationArgs {
        // Qt uses `QString::fromLocal8Bit()` to decode `argv`,
        // so we use `QString::toLocal8Bit()` to encode it.
        let mut args = std::env::args()
            .map(|arg| unsafe {
                QString::from_std_str(&arg)
                    .to_local8_bit()
                    .as_slice()
                    .iter()
                    .map(|&c| c as u8)
                    .chain(once(0))
                    .collect::<Vec<_>>()
            })
            .collect::<Vec<_>>();

        QCoreApplicationArgs {
            argc: Box::new(args.len() as c_int),
            argv: args
                .iter_mut()
                .map(|x| x.as_mut_ptr() as *mut c_char)
                .collect::<Vec<_>>()
                .into_boxed_slice(),
            _values: args,
        }
    }

    /// Returns `(argc, argv)` values in the form accepted by the application objects'
    /// constructors.
    pub fn get(&mut self) -> (*mut c_int, *mut *mut c_char) {
        (self.argc.as_mut(), self.argv.as_mut_ptr())
    }
}

impl QCoreApplication {
    /// A convenience function for performing proper initialization and de-initialization of
    /// a Qt application.
    ///
    /// This function creates `CoreApplication` with valid `argc` and `argv`, calls the passed
    /// closure `f(app)` with the application object and exist the process with the exit code
    /// returned by the closure. The closure should perform the initialization of the application
    /// and either return immediately or call `CoreApplication::exec()` and return its return value:
    /// ```no_run
    /// use qt_core::QCoreApplication;
    ///
    /// fn main() {
    ///     QCoreApplication::init(|app| {
    ///         unsafe {
    ///             // initialization goes here
    ///             QCoreApplication::exec()
    ///         }
    ///     })
    /// }
    /// ```
    pub fn init<F: FnOnce(::cpp_core::Ptr<QCoreApplication>) -> i32>(f: F) -> ! {
        let exit_code = {
            unsafe {
                let mut args = QCoreApplicationArgs::new();
                let (argc, argv) = args.get();
                let app = QCoreApplication::new_2a(argc, argv);
                f(app.as_ptr())
            }
        }; // drop `app` and `args`
        process::exit(exit_code)
    }
}
<|endoftext|>


<commit_before>//~ GLOBAL-ERROR-REGEX linking with `(.+)ptx-linker` failed: exit code: 1

//~ GLOBAL-NOTE-REGEX ptx-linker(.+)-o(.+)example.ptx
//~ GLOBAL-NOTE-REGEX Unable to link modules
//~ GLOBAL-NOTE-REGEX Undefined references: \["bar"\]

#![deny(warnings)]
#![feature(abi_ptx)]
#![no_std]

extern "C" {
    fn bar();
}

#[no_mangle]
pub unsafe extern "ptx-kernel" fn kernel() {
    bar()
}

#[panic_handler]
fn panic(_info: &::core::panic::PanicInfo) -> ! {
    loop {}
}
<commit_msg>Add syscalls test case<commit_after>//~ GLOBAL-ERROR-REGEX linking with `(.+)ptx-linker` failed: exit code: 1

//~ GLOBAL-NOTE-REGEX ptx-linker(.+)-o(.+)example.ptx
//~ GLOBAL-NOTE-REGEX Unable to link modules
//~ GLOBAL-NOTE-REGEX Undefined references: \["bar"\]

#![deny(warnings)]
#![feature(abi_ptx)]
#![no_std]

// Actual "undefined reference"
extern "C" {
    fn bar();
}

// Syscalls that are allowed
extern "C" {
    pub fn vprintf(format: *const u8, valist: *const u8) -> i32;
    pub fn malloc(size: u64) -> *mut u8;
    pub fn free(ptr: *mut u8);
}

#[no_mangle]
pub unsafe extern "ptx-kernel" fn kernel() {
    bar();

    vprintf("allocating memory".as_ptr(), [].as_ptr());
    let ptr = malloc(32);

    vprintf("writing into the memory".as_ptr(), [].as_ptr());
    *ptr.offset(0) = 128;

    vprintf("releasing memory".as_ptr(), [].as_ptr());
    free(ptr);
}

#[panic_handler]
fn panic(_info: &::core::panic::PanicInfo) -> ! {
    loop {}
}
<|endoftext|>