<commit_before>use std::fmt;
use std::fmt::{Show,Formatter};
use std::io::{UserDir};
use std::io::fs::{mkdir_recursive,rmdir_recursive};
use serialize::{Encodable,Encoder};
use url::Url;

use util::{CargoResult, ChainError, ProcessBuilder, process, human};

#[deriving(PartialEq,Clone,Encodable)]
pub enum GitReference {
    Master,
    Other(String)
}

#[deriving(PartialEq,Clone,Encodable)]
pub struct GitRevision(String);

impl GitReference {
    pub fn for_str<S: Str>(string: S) -> GitReference {
        if string.as_slice() == "master" {
            Master
        } else {
            Other(string.as_slice().to_string())
        }
    }
}

impl Str for GitReference {
    fn as_slice(&self) -> &str {
        match *self {
            Master => "master",
            Other(ref string) => string.as_slice()
        }
    }
}

impl Show for GitReference {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl Str for GitRevision {
    fn as_slice(&self) -> &str {
        let GitRevision(ref me) = *self;
        me.as_slice()
    }
}

impl Show for GitRevision {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

macro_rules! git(
    ($config:expr, $($arg:expr),+) => (
        try!(git_inherit(&$config, process("git")$(.arg($arg))*))
    )
)

macro_rules! git_output(
    ($config:expr, $($arg:expr),*) => ({
        try!(git_output(&$config, process("git")$(.arg($arg))*))
    })
)

macro_rules! errln(
    ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*))
)

/// GitRemote represents a remote repository. It gets cloned into a local
/// GitDatabase.
#[deriving(PartialEq,Clone,Show)]
pub struct GitRemote {
    url: Url,
}

#[deriving(PartialEq,Clone,Encodable)]
struct EncodableGitRemote {
    url: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitRemote {
            url: self.url.to_string()
        }.encode(s)
    }
}

/// GitDatabase is a local clone of a remote repository's database. Multiple
/// GitCheckouts can be cloned from this GitDatabase.
#[deriving(PartialEq,Clone)]
pub struct GitDatabase {
    remote: GitRemote,
    path: Path,
}

#[deriving(Encodable)]
pub struct EncodableGitDatabase {
    remote: GitRemote,
    path: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitDatabase {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitDatabase {
            remote: self.remote.clone(),
            path: self.path.display().to_string()
        }.encode(s)
    }
}

/// GitCheckout is a local checkout of a particular revision. Calling
/// `clone_into` with a reference will resolve the reference into a revision,
/// and return a CargoError if no revision for that reference was found.
pub struct GitCheckout {
    database: GitDatabase,
    location: Path,
    revision: GitRevision,
}

#[deriving(Encodable)]
pub struct EncodableGitCheckout {
    database: GitDatabase,
    location: String,
    revision: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitCheckout {
            database: self.database.clone(),
            location: self.location.display().to_string(),
            revision: self.revision.to_string()
        }.encode(s)
    }
}

// Implementations

impl GitRemote {
    pub fn new(url: &Url) -> GitRemote {
        GitRemote { url: url.clone() }
    }

    pub fn get_url(&self) -> &Url {
        &self.url
    }

    pub fn rev_for<S: Str>(&self, path: &Path, reference: S)
                           -> CargoResult<GitRevision> {
        // We simultaneously want to transform the reference into a resolved
        // revision as well as verify that the reference itself is inside the
        // repository. Sadly for a 40-character SHA1 the call to `rev-parse`
        // will *always* return the same string with a 0 exit status, regardless
        // of whether it's present in the database.
        //
        // Later versions of git introduced a syntax for this query via
        // `$sha1^{object}`, but older versions of git do not support this. To
        // get around this limitation, we chop 40-character sha revisions to 39
        // characters to get an error'd exit status if the revision is indeed
        // not present.
        let mut reference = reference.as_slice();
        if reference.len() == 40 {
            reference = reference.slice_to(39);
        }
        Ok(GitRevision(git_output!(*path, "rev-parse", reference)))
    }

    pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
        if into.exists() {
            try!(self.fetch_into(into));
        } else {
            try!(self.clone_into(into));
        }

        Ok(GitDatabase { remote: self.clone(), path: into.clone() })
    }

    pub fn db_at(&self, db_path: &Path) -> GitDatabase {
        GitDatabase { remote: self.clone(), path: db_path.clone() }
    }

    fn fetch_into(&self, path: &Path) -> CargoResult<()> {
        Ok(git!(*path, "fetch", "--force", "--quiet", "--tags",
                self.url.to_string(), "refs/heads/*:refs/heads/*"))
    }

    fn clone_into(&self, path: &Path) -> CargoResult<()> {
        let dirname = Path::new(path.dirname());

        try!(mkdir_recursive(path, UserDir));

        Ok(git!(dirname, "clone", self.url.to_string(), path, "--bare",
                "--no-hardlinks", "--quiet"))
    }
}

impl GitDatabase {
    fn get_path<'a>(&'a self) -> &'a Path {
        &self.path
    }

    pub fn copy_to(&self, rev: GitRevision, dest: &Path)
                   -> CargoResult<GitCheckout> {

        if dest.exists() {
            match self.remote.rev_for(dest, "HEAD") {
                Ok(ref head) if rev == *head => {
                    return Ok(GitCheckout::new(dest, self.clone(), rev.clone()));
                }
                _ => {}
            }
        }

        GitCheckout::clone_into(dest, self.clone(), rev.clone())
    }

    pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<GitRevision> {
        self.remote.rev_for(&self.path, reference)
    }

    pub fn has_ref<S: Str>(&self, reference: S) -> CargoResult<()> {
        git_output!(self.path, "rev-parse", "--verify", reference.as_slice());
        Ok(())
    }
}

impl GitCheckout {
    fn new(path: &Path, database: GitDatabase, revision: GitRevision)
           -> GitCheckout
    {
        GitCheckout {
            location: path.clone(),
            database: database,
            revision: revision,
        }
    }

    fn clone_into(into: &Path, database: GitDatabase,
                  revision: GitRevision)
                  -> CargoResult<GitCheckout>
    {
        let checkout = GitCheckout::new(into, database, revision);

        try!(checkout.clone_repo());
        try!(checkout.update_submodules());

        Ok(checkout)
    }

    fn get_source(&self) -> &Path {
        self.database.get_path()
    }

    pub fn get_rev(&self) -> &str {
        self.revision.as_slice()
    }

    fn clone_repo(&self) -> CargoResult<()> {
        let dirname = Path::new(self.location.dirname());

        try!(mkdir_recursive(&dirname, UserDir).chain_error(|| {
            human(format!("Couldn't mkdir {}",
                          Path::new(self.location.dirname()).display()))
        }));

        if self.location.exists() {
            try!(rmdir_recursive(&self.location).chain_error(|| {
                human(format!("Couldn't rmdir {}",
                              Path::new(&self.location).display()))
            }));
        }

        git!(dirname, "clone", "--no-checkout", "--quiet",
             self.get_source(), &self.location);
        try!(self.reset());

        Ok(())
    }

    fn reset(&self) -> CargoResult<()> {
        Ok(git!(self.location, "reset", "-q", "--hard",
                self.revision.as_slice()))
    }

    fn update_submodules(&self) -> CargoResult<()> {
        git!(self.location, "submodule", "sync", "--quiet");
        Ok(git!(self.location, "submodule", "update", "--init",
                "--recursive", "--quiet"))
    }
}

fn git(path: &Path, cmd: ProcessBuilder) -> ProcessBuilder {
    debug!("Executing {} @ {}", cmd, path.display());

    cmd.cwd(path.clone())
}

fn git_inherit(path: &Path, cmd: ProcessBuilder) -> CargoResult<()> {
    let cmd = git(path, cmd);
    cmd.exec().chain_error(|| {
        human(format!("Executing {} failed", cmd))
    })
}

fn git_output(path: &Path, cmd: ProcessBuilder) -> CargoResult<String> {
    let cmd = git(path, cmd);
    let output = try!(cmd.exec_with_output().chain_error(||
        human(format!("Executing {} failed", cmd))));

    Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_string())
}

fn to_str(vec: &[u8]) -> String {
    String::from_utf8_lossy(vec).into_string()
}

<commit_msg>Fix some flaky tests on the buildbots<commit_after>use std::fmt;
use std::fmt::{Show,Formatter};
use std::io::{UserDir};
use std::io::fs::{mkdir_recursive,rmdir_recursive};
use serialize::{Encodable,Encoder};
use url::Url;

use util::{CargoResult, ChainError, ProcessBuilder, process, human};

#[deriving(PartialEq,Clone,Encodable)]
pub enum GitReference {
    Master,
    Other(String)
}

#[deriving(PartialEq,Clone,Encodable)]
pub struct GitRevision(String);

impl GitReference {
    pub fn for_str<S: Str>(string: S) -> GitReference {
        if string.as_slice() == "master" {
            Master
        } else {
            Other(string.as_slice().to_string())
        }
    }
}

impl Str for GitReference {
    fn as_slice(&self) -> &str {
        match *self {
            Master => "master",
            Other(ref string) => string.as_slice()
        }
    }
}

impl Show for GitReference {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl Str for GitRevision {
    fn as_slice(&self) -> &str {
        let GitRevision(ref me) = *self;
        me.as_slice()
    }
}

impl Show for GitRevision {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

macro_rules! git(
    ($config:expr, $($arg:expr),+) => (
        try!(git_inherit(&$config, process("git")$(.arg($arg))*))
    )
)

macro_rules! git_output(
    ($config:expr, $($arg:expr),*) => ({
        try!(git_output(&$config, process("git")$(.arg($arg))*))
    })
)

macro_rules! errln(
    ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*))
)

/// GitRemote represents a remote repository. It gets cloned into a local
/// GitDatabase.
#[deriving(PartialEq,Clone,Show)]
pub struct GitRemote {
    url: Url,
}

#[deriving(PartialEq,Clone,Encodable)]
struct EncodableGitRemote {
    url: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitRemote {
            url: self.url.to_string()
        }.encode(s)
    }
}

/// GitDatabase is a local clone of a remote repository's database. Multiple
/// GitCheckouts can be cloned from this GitDatabase.
#[deriving(PartialEq,Clone)]
pub struct GitDatabase {
    remote: GitRemote,
    path: Path,
}

#[deriving(Encodable)]
pub struct EncodableGitDatabase {
    remote: GitRemote,
    path: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitDatabase {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitDatabase {
            remote: self.remote.clone(),
            path: self.path.display().to_string()
        }.encode(s)
    }
}

/// GitCheckout is a local checkout of a particular revision. Calling
/// `clone_into` with a reference will resolve the reference into a revision,
/// and return a CargoError if no revision for that reference was found.
pub struct GitCheckout {
    database: GitDatabase,
    location: Path,
    revision: GitRevision,
}

#[deriving(Encodable)]
pub struct EncodableGitCheckout {
    database: GitDatabase,
    location: String,
    revision: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitCheckout {
            database: self.database.clone(),
            location: self.location.display().to_string(),
            revision: self.revision.to_string()
        }.encode(s)
    }
}

// Implementations

impl GitRemote {
    pub fn new(url: &Url) -> GitRemote {
        GitRemote { url: url.clone() }
    }

    pub fn get_url(&self) -> &Url {
        &self.url
    }

    pub fn rev_for<S: Str>(&self, path: &Path, reference: S)
                           -> CargoResult<GitRevision> {
        // We simultaneously want to transform the reference into a resolved
        // revision as well as verify that the reference itself is inside the
        // repository. Sadly for a 40-character SHA1 the call to `rev-parse`
        // will *always* return the same string with a 0 exit status, regardless
        // of whether it's present in the database.
        //
        // Later versions of git introduced a syntax for this query via
        // `$sha1^{object}`, but older versions of git do not support this. To
        // get around this limitation, we chop 40-character sha revisions to 39
        // characters to get an error'd exit status if the revision is indeed
        // not present.
        let mut reference = reference.as_slice();
        if reference.len() == 40 {
            reference = reference.slice_to(39);
        }
        Ok(GitRevision(git_output!(*path, "rev-parse", reference)))
    }

    pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
        if into.exists() {
            try!(self.fetch_into(into));
        } else {
            try!(self.clone_into(into));
        }

        Ok(GitDatabase { remote: self.clone(), path: into.clone() })
    }

    pub fn db_at(&self, db_path: &Path) -> GitDatabase {
        GitDatabase { remote: self.clone(), path: db_path.clone() }
    }

    fn fetch_into(&self, path: &Path) -> CargoResult<()> {
        Ok(git!(*path, "fetch", "--force", "--quiet", "--tags",
                self.url.to_string(), "refs/heads/*:refs/heads/*"))
    }

    fn clone_into(&self, path: &Path) -> CargoResult<()> {
        let dirname = Path::new(path.dirname());

        try!(mkdir_recursive(path, UserDir));

        Ok(git!(dirname, "clone", self.url.to_string(), path, "--bare",
                "--no-hardlinks", "--quiet"))
    }
}

impl GitDatabase {
    fn get_path<'a>(&'a self) -> &'a Path {
        &self.path
    }

    pub fn copy_to(&self, rev: GitRevision, dest: &Path)
                   -> CargoResult<GitCheckout> {

        if dest.exists() {
            match self.remote.rev_for(dest, "HEAD") {
                Ok(ref head) if rev == *head => {
                    return Ok(GitCheckout::new(dest, self.clone(), rev.clone()));
                }
                _ => {}
            }
        }

        GitCheckout::clone_into(dest, self.clone(), rev.clone())
    }

    pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<GitRevision> {
        self.remote.rev_for(&self.path, reference)
    }

    pub fn has_ref<S: Str>(&self, reference: S) -> CargoResult<()> {
        git_output!(self.path, "rev-parse", "--verify", reference.as_slice());
        Ok(())
    }
}

impl GitCheckout {
    fn new(path: &Path, database: GitDatabase, revision: GitRevision)
           -> GitCheckout
    {
        GitCheckout {
            location: path.clone(),
            database: database,
            revision: revision,
        }
    }

    fn clone_into(into: &Path, database: GitDatabase,
                  revision: GitRevision)
                  -> CargoResult<GitCheckout>
    {
        let checkout = GitCheckout::new(into, database, revision);

        try!(checkout.clone_repo());
        try!(checkout.update_submodules());

        Ok(checkout)
    }

    fn get_source(&self) -> &Path {
        self.database.get_path()
    }

    pub fn get_rev(&self) -> &str {
        self.revision.as_slice()
    }

    fn clone_repo(&self) -> CargoResult<()> {
        let dirname = Path::new(self.location.dirname());

        try!(mkdir_recursive(&dirname, UserDir).chain_error(|| {
            human(format!("Couldn't mkdir {}",
                          Path::new(self.location.dirname()).display()))
        }));

        if self.location.exists() {
            try!(rmdir_recursive(&self.location).chain_error(|| {
                human(format!("Couldn't rmdir {}",
                              Path::new(&self.location).display()))
            }));
        }

        git!(dirname, "clone", "--no-checkout", "--quiet",
             self.get_source(), &self.location);
        try!(self.reset());

        Ok(())
    }

    fn reset(&self) -> CargoResult<()> {
        Ok(git!(self.location, "reset", "-q", "--hard",
                self.revision.as_slice()))
    }

    fn update_submodules(&self) -> CargoResult<()> {
        git!(self.location, "submodule", "sync", "--quiet");
        // Sadly older versions of git don't actually respect --quiet for *all*
        // operations and still print some thing here and there.
        git_output!(self.location, "submodule", "update", "--init",
                    "--recursive", "--quiet");
        Ok(())
    }
}

fn git(path: &Path, cmd: ProcessBuilder) -> ProcessBuilder {
    debug!("Executing {} @ {}", cmd, path.display());

    cmd.cwd(path.clone())
}

fn git_inherit(path: &Path, cmd: ProcessBuilder) -> CargoResult<()> {
    let cmd = git(path, cmd);
    cmd.exec().chain_error(|| {
        human(format!("Executing {} failed", cmd))
    })
}

fn git_output(path: &Path, cmd: ProcessBuilder) -> CargoResult<String> {
    let cmd = git(path, cmd);
    let output = try!(cmd.exec_with_output().chain_error(||
        human(format!("Executing {} failed", cmd))));

    Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_string())
}

fn to_str(vec: &[u8]) -> String {
    String::from_utf8_lossy(vec).into_string()
}

<|endoftext|>


<commit_before>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>group text<commit_after>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ----- text -----

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>use crate::inode_error::InodeError;
use bootstrap_components::bs_table;
use futures::Future;
use iml_environment::influx_root;
use seed::{
    class, div,
    dom_types::Attrs,
    fetch::{FetchObject, RequestController},
    h4, i,
    prelude::*,
    style, tbody, td, th, thead, tr,
};

#[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Clone)]
pub struct INodeCount {
    uid: String,
    count: u32,
}

#[derive(Default, Debug)]
pub struct Model {
    inodes: Vec<INodeCount>,
    destroyed: bool,
    cancel: Option<futures::sync::oneshot::Sender<()>>,
    request_controller: Option<RequestController>,
}

#[derive(Clone, Debug)]
pub enum Msg {
    FetchInodes,
    InodesFetched(FetchObject<InfluxResults>),
    OnFetchError(InodeError),
    Destroy,
    Noop,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct InfluxSeries {
    #[serde(skip)]
    name: String,
    #[serde(skip)]
    columns: Vec<String>,
    values: Vec<(String, String, u32)>,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct InfluxResult {
    #[serde(skip)]
    statement_id: u16,
    series: Option<Vec<InfluxSeries>>,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct InfluxResults {
    results: Vec<InfluxResult>,
}

pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
    if model.destroyed {
        return;
    }

    match msg {
        Msg::FetchInodes => {
            model.cancel = None;

            let (fut, request_controller) = fetch_inodes();
            model.request_controller = request_controller;
            orders.skip().perform_cmd(fut);
        }
        Msg::InodesFetched(fetch_object) => {
            model.request_controller = None;

            match fetch_object.response() {
                Ok(response) => {
                    let mut data: InfluxResults = response.data;
                    model.inodes = data
                        .results
                        .drain(..)
                        .take(1)
                        .filter_map(|result| result.series)
                        .flatten()
                        .take(1)
                        .map(|v| v.values)
                        .flatten()
                        .map(|(_, uid, count)| INodeCount { uid, count })
                        .collect();
                }
                Err(fail_reason) => {
                    orders.send_msg(Msg::OnFetchError(fail_reason.into()));
                }
            }

            let sleep = iml_sleep::Sleep::new(60000)
                .map(move |_| Msg::FetchInodes)
                .map_err(|_| unreachable!());

            let (p, c) = futures::sync::oneshot::channel::<()>();

            model.cancel = Some(p);

            let c = c.map(move |_| Msg::Noop).map_err(move |_| {
                log::info!("Inodes poll timeout dropped");

                Msg::Noop
            });

            // Fetch the inodes after 60 seconds unless the producer is dropped before
            // it has an opportunity to fetch.
            let fut = sleep
                .select2(c)
                .map(futures::future::Either::split)
                .map(|(x, _)| x)
                .map_err(futures::future::Either::split)
                .map_err(|(x, _)| x);
            orders.perform_cmd(fut);
        }
        Msg::OnFetchError(e) => {
            log::error!("Fetch Error: {}", e);
            orders.skip();
        }
        Msg::Noop => {
            orders.skip();
        }
        Msg::Destroy => {
            model.cancel = None;

            if let Some(c) = model.request_controller.take() {
                c.abort()
            }

            model.destroyed = true;
            model.inodes = vec![];
        }
    }
}

pub fn fetch_inodes() -> (
    impl Future<Item = Msg, Error = Msg>,
    Option<seed::fetch::RequestController>,
) {
    let mut request_controller = None;
    let url:String = format!("{}db=iml_stratagem_scans&q=SELECT%20counter_name,%20count%20FROM%20stratagem_scan%20WHERE%20group_name=%27user_distribution%27", influx_root());
    let fut = seed::fetch::Request::new(url)
        .controller(|controller| request_controller = Some(controller))
        .fetch_json(Msg::InodesFetched);

    (fut, request_controller)
}

fn get_inode_elements<T>(inodes: &Vec<INodeCount>) -> Vec<Node<T>> {
    inodes
        .into_iter()
        .map(|x| tr![td![x.uid], td![x.count.to_string()]])
        .collect()
}

fn detail_panel<T>(children: Vec<Node<T>>) -> Node<T> {
    div!(children)
        .add_style("display", "grid")
        .add_style("grid-template-columns", "50% 50%")
        .add_style("grid-row-gap", px(20))
}

/// View
pub fn view(model: &Model) -> Node<Msg> {
    if model.destroyed {
        seed::empty()
    } else {
        let entries = get_inode_elements(&model.inodes);

        div![
            h4![class!["section-header"], "Top inode Users"],
            if !entries.is_empty() {
                bs_table::table(
                    Attrs::empty(),
                    vec![thead![tr![th!["Name"], th!["Count"]]], tbody![entries]],
                )
            } else {
                div![detail_panel(vec![i![
                    class!["fa fa-circle-notch fa-spin".into()],
                    style! {
                        "grid-column" => "2",
                        "grid-row" => "1",
                        "width" => "40px",
                        "height" => "40px",
                        "margin-left" => "-20px",
                        "font-size" => "40px"
                    }
                ]])]
            }
        ]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::sync::{oneshot, oneshot::Sender};
    use iml_utils::Children;
    use seed::fetch::{Request, ResponseWithDataResult, Status, StatusCategory};
    use std::sync::{Arc, Mutex};
    use wasm_bindgen_test::wasm_bindgen_test_configure;

    wasm_bindgen_test_configure!(run_in_browser);

    use wasm_bindgen_test::*;

    #[derive(Debug)]
    pub struct TestModel {
        model: Model,
        p: Arc<Mutex<Option<Sender<Node<Msg>>>>>,
    }

    fn destroy_after_delay() -> impl Future<Item = Msg, Error = Msg> {
        iml_sleep::Sleep::new(1000)
            .map(move |_| Msg::Destroy)
            .map_err(|_| unreachable!())
    }

    pub fn test_view(TestModel { p, model }: &TestModel) -> Node<Msg> {
        let el = view(&model);

        if let Some(_) = &model.cancel {
            p.lock().unwrap().take().map(|p| p.send(el.clone()));
        }

        el
    }

    pub fn test_update(msg: Msg, model: &mut TestModel, orders: &mut impl Orders<Msg>) {
        update(msg.clone(), &mut model.model, orders);
        orders.perform_cmd(destroy_after_delay());
    }

    #[wasm_bindgen_test(async)]
    pub fn test_inodes_with_data() -> impl Future<Item = (), Error = JsValue> {
        pub fn render() -> impl Future<Item = (), Error = JsValue> {
            let (p, c) = oneshot::channel::<Node<Msg>>();

            let app = seed::App::build(
                |_, _| TestModel {
                    p: Arc::new(Mutex::new(Some(p))),
                    model: Model::default(),
                },
                test_update,
                test_view,
            )
            .mount(seed::body())
            .finish()
            .run();

            let results = r#"{
            "results": [
              {
                "statement_id": 0,
                "series": [
                  {
                    "name": "stratagem_scan",
                    "columns": [
                      "time",
                      "counter_name",
                      "count"
                    ],
                    "values": [
                      [
                        "2019-07-12T06:16:51.700191592Z",
                        "uid_0",
                        26
                      ],
                      [
                        "2019-07-12T06:16:51.700191592Z",
                        "uid_1",
                        13
                      ]
                    ]
                  }
                ]
              }
            ]
          }"#;

            let raw = web_sys::Response::new_with_opt_str(Some(results)).unwrap();
            let data: InfluxResults = serde_json::from_str(results).unwrap();

            let fetch_object: FetchObject<InfluxResults> = FetchObject {
                request: Request::new("/influx?db=iml_stratagem_scans&q=SELECT counter_name, count FROM stratagem_scan WHERE group_name='user_distribution'"),
                result: Ok(ResponseWithDataResult {
                    raw,
                    status: Status {code: 200, text: "OK".into(), category: StatusCategory::Success},
                    data: Ok(data)
                })
            };

            app.update(Msg::InodesFetched(fetch_object));

            c.map(|el| {
                let children = el.get_children().unwrap();

                let tr1 = &children[0];
                let th1 = tr1.get_children().unwrap()[0].get_text();
                let th2 = tr1.get_children().unwrap()[1].get_children().unwrap()[0].get_text();

                let tr2 = &children[1];
                let td21 = tr2.get_children().unwrap()[0].get_children().unwrap()[0].get_text();
                let td22 = tr2.get_children().unwrap()[1].get_children().unwrap()[0].get_text();
                let tr3 = &children[2];
                let td31 = tr3.get_children().unwrap()[0].get_children().unwrap()[0].get_text();
                let td32 = tr3.get_children().unwrap()[1].get_children().unwrap()[0].get_text();

                assert_eq!(th1, "Uid".to_string());
                assert_eq!(th2, "Count".to_string());
                assert_eq!(td21, "uid_0".to_string());
                assert_eq!(td22, "26".to_string());
                assert_eq!(td31, "uid_1".to_string());
                assert_eq!(td32, "13".to_string());
            })
            .map_err(|_| unreachable!())
        }

        render()
    }

    #[wasm_bindgen_test(async)]
    pub fn test_inodes_with_empty_results() -> impl Future<Item = (), Error = JsValue> {
        pub fn render() -> impl Future<Item = (), Error = JsValue> {
            let (p, c) = oneshot::channel::<Node<Msg>>();

            let app = seed::App::build(
                |_, _| TestModel {
                    p: Arc::new(Mutex::new(Some(p))),
                    model: Model::default(),
                },
                test_update,
                test_view,
            )
            .mount(seed::body())
            .finish()
            .run();

            let results = r#"{
                "results": []
            }"#;

            let raw = web_sys::Response::new_with_opt_str(Some(results)).unwrap();
            let data: InfluxResults = serde_json::from_str(results).unwrap();

            let fetch_object: FetchObject<InfluxResults> = FetchObject {
                request: Request::new("/influx?db=iml_stratagem_scans&q=SELECT counter_name, count FROM stratagem_scan WHERE group_name='user_distribution'"),
                result: Ok(ResponseWithDataResult {
                    raw,
                    status: Status {code: 200, text: "OK".into(), category: StatusCategory::Success},
                    data: Ok(data)
                })
            };

            app.update(Msg::InodesFetched(fetch_object));

            c.map(|el| {
                assert_eq!(el.get_children().unwrap().len(), 0);
            })
            .map_err(|_| unreachable!())
        }

        render()
    }
}
<commit_msg>Top inode users table should be truncated after n users (#1138)<commit_after>use crate::inode_error::InodeError;
use bootstrap_components::bs_table;
use futures::Future;
use iml_environment::influx_root;
use seed::{
    class, div,
    dom_types::Attrs,
    fetch::{FetchObject, RequestController},
    h4, p,
    prelude::*,
    tbody, td, th, thead, tr,
};

pub static MAX_INODE_ENTRIES: u32 = 20;

#[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq, Clone)]
pub struct INodeCount {
    uid: String,
    count: u32,
}

#[derive(Default, Debug)]
pub struct Model {
    inodes: Vec<INodeCount>,
    destroyed: bool,
    cancel: Option<futures::sync::oneshot::Sender<()>>,
    request_controller: Option<RequestController>,
}

#[derive(Clone, Debug)]
pub enum Msg {
    FetchInodes,
    InodesFetched(FetchObject<InfluxResults>),
    OnFetchError(InodeError),
    Destroy,
    Noop,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct InfluxSeries {
    #[serde(skip)]
    name: String,
    #[serde(skip)]
    columns: Vec<String>,
    values: Vec<(String, String, u32)>,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct InfluxResult {
    #[serde(skip)]
    statement_id: u16,
    series: Option<Vec<InfluxSeries>>,
}

#[derive(serde::Deserialize, Clone, Debug)]
pub struct InfluxResults {
    results: Vec<InfluxResult>,
}

pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
    if model.destroyed {
        return;
    }

    match msg {
        Msg::FetchInodes => {
            model.cancel = None;

            let (fut, request_controller) = fetch_inodes();
            model.request_controller = request_controller;
            orders.skip().perform_cmd(fut);
        }
        Msg::InodesFetched(fetch_object) => {
            model.request_controller = None;

            match fetch_object.response() {
                Ok(response) => {
                    let mut data: InfluxResults = response.data;
                    model.inodes = data
                        .results
                        .drain(..)
                        .take(1)
                        .filter_map(|result| result.series)
                        .flatten()
                        .take(1)
                        .map(|v| v.values)
                        .flatten()
                        .map(|(_, uid, count)| INodeCount { uid, count })
                        .collect();
                }
                Err(fail_reason) => {
                    orders.send_msg(Msg::OnFetchError(fail_reason.into()));
                }
            }

            let sleep = iml_sleep::Sleep::new(60000)
                .map(move |_| Msg::FetchInodes)
                .map_err(|_| unreachable!());

            let (p, c) = futures::sync::oneshot::channel::<()>();

            model.cancel = Some(p);

            let c = c.map(move |_| Msg::Noop).map_err(move |_| {
                log::info!("Inodes poll timeout dropped");

                Msg::Noop
            });

            // Fetch the inodes after 60 seconds unless the producer is dropped before
            // it has an opportunity to fetch.
            let fut = sleep
                .select2(c)
                .map(futures::future::Either::split)
                .map(|(x, _)| x)
                .map_err(futures::future::Either::split)
                .map_err(|(x, _)| x);
            orders.perform_cmd(fut);
        }
        Msg::OnFetchError(e) => {
            log::error!("Fetch Error: {}", e);
            orders.skip();
        }
        Msg::Noop => {
            orders.skip();
        }
        Msg::Destroy => {
            model.cancel = None;

            if let Some(c) = model.request_controller.take() {
                c.abort()
            }

            model.destroyed = true;
            model.inodes = vec![];
        }
    }
}

pub fn fetch_inodes() -> (
    impl Future<Item = Msg, Error = Msg>,
    Option<seed::fetch::RequestController>,
) {
    let mut request_controller = None;
    let url:String = format!("{}db=iml_stratagem_scans&q=SELECT%20counter_name,%20count%20FROM%20stratagem_scan%20WHERE%20group_name=%27user_distribution%27%20limit%20{}", influx_root(), MAX_INODE_ENTRIES);
    let fut = seed::fetch::Request::new(url)
        .controller(|controller| request_controller = Some(controller))
        .fetch_json(Msg::InodesFetched);

    (fut, request_controller)
}

fn get_inode_elements<T>(inodes: &Vec<INodeCount>) -> Vec<Node<T>> {
    inodes
        .into_iter()
        .map(|x| tr![td![x.uid], td![x.count.to_string()]])
        .collect()
}

fn detail_panel<T>(children: Vec<Node<T>>) -> Node<T> {
    div!(children)
        .add_style("display", "grid")
        .add_style("grid-template-columns", "50% 50%")
        .add_style("grid-row-gap", px(20))
}

/// View
pub fn view(model: &Model) -> Node<Msg> {
    if model.destroyed {
        seed::empty()
    } else {
        let entries = get_inode_elements(&model.inodes);

        div![
            h4![class!["section-header"], "Top inode Users"],
            if !entries.is_empty() {
                bs_table::table(
                    Attrs::empty(),
                    vec![thead![tr![th!["Name"], th!["Count"]]], tbody![entries]],
                )
            } else {
                div![detail_panel(vec![p!["No Data"]])]
            }
        ]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::sync::{oneshot, oneshot::Sender};
    use iml_utils::Children;
    use seed::fetch::{Request, ResponseWithDataResult, Status, StatusCategory};
    use std::sync::{Arc, Mutex};
    use wasm_bindgen_test::wasm_bindgen_test_configure;

    wasm_bindgen_test_configure!(run_in_browser);

    use wasm_bindgen_test::*;

    #[derive(Debug)]
    pub struct TestModel {
        model: Model,
        p: Arc<Mutex<Option<Sender<Node<Msg>>>>>,
    }

    fn destroy_after_delay() -> impl Future<Item = Msg, Error = Msg> {
        iml_sleep::Sleep::new(1000)
            .map(move |_| Msg::Destroy)
            .map_err(|_| unreachable!())
    }

    pub fn test_view(TestModel { p, model }: &TestModel) -> Node<Msg> {
        let el = view(&model);

        if let Some(_) = &model.cancel {
            p.lock().unwrap().take().map(|p| p.send(el.clone()));
        }

        el
    }

    pub fn test_update(msg: Msg, model: &mut TestModel, orders: &mut impl Orders<Msg>) {
        update(msg.clone(), &mut model.model, orders);
        orders.perform_cmd(destroy_after_delay());
    }

    #[wasm_bindgen_test(async)]
    pub fn test_inodes_with_data() -> impl Future<Item = (), Error = JsValue> {
        pub fn render() -> impl Future<Item = (), Error = JsValue> {
            let (p, c) = oneshot::channel::<Node<Msg>>();

            let app = seed::App::build(
                |_, _| TestModel {
                    p: Arc::new(Mutex::new(Some(p))),
                    model: Model::default(),
                },
                test_update,
                test_view,
            )
            .mount(seed::body())
            .finish()
            .run();

            let results = r#"{
            "results": [
              {
                "statement_id": 0,
                "series": [
                  {
                    "name": "stratagem_scan",
                    "columns": [
                      "time",
                      "counter_name",
                      "count"
                    ],
                    "values": [
                      [
                        "2019-07-12T06:16:51.700191592Z",
                        "uid_0",
                        26
                      ],
                      [
                        "2019-07-12T06:16:51.700191592Z",
                        "uid_1",
                        13
                      ]
                    ]
                  }
                ]
              }
            ]
          }"#;

            let raw = web_sys::Response::new_with_opt_str(Some(results)).unwrap();
            let data: InfluxResults = serde_json::from_str(results).unwrap();

            let fetch_object: FetchObject<InfluxResults> = FetchObject {
                request: Request::new("/influx?db=iml_stratagem_scans&q=SELECT counter_name, count FROM stratagem_scan WHERE group_name='user_distribution'"),
                result: Ok(ResponseWithDataResult {
                    raw,
                    status: Status {code: 200, text: "OK".into(), category: StatusCategory::Success},
                    data: Ok(data)
                })
            };

            app.update(Msg::InodesFetched(fetch_object));

            c.map(|el| {
                let children = el.get_children().unwrap();

                let tr1 = &children[0];
                let th1 = tr1.get_children().unwrap()[0].get_text();
                let th2 = tr1.get_children().unwrap()[1].get_children().unwrap()[0].get_text();

                let tr2 = &children[1];
                let td21 = tr2.get_children().unwrap()[0].get_children().unwrap()[0].get_text();
                let td22 = tr2.get_children().unwrap()[1].get_children().unwrap()[0].get_text();
                let tr3 = &children[2];
                let td31 = tr3.get_children().unwrap()[0].get_children().unwrap()[0].get_text();
                let td32 = tr3.get_children().unwrap()[1].get_children().unwrap()[0].get_text();

                assert_eq!(th1, "Uid".to_string());
                assert_eq!(th2, "Count".to_string());
                assert_eq!(td21, "uid_0".to_string());
                assert_eq!(td22, "26".to_string());
                assert_eq!(td31, "uid_1".to_string());
                assert_eq!(td32, "13".to_string());
            })
            .map_err(|_| unreachable!())
        }

        render()
    }

    #[wasm_bindgen_test(async)]
    pub fn test_inodes_with_empty_results() -> impl Future<Item = (), Error = JsValue> {
        pub fn render() -> impl Future<Item = (), Error = JsValue> {
            let (p, c) = oneshot::channel::<Node<Msg>>();

            let app = seed::App::build(
                |_, _| TestModel {
                    p: Arc::new(Mutex::new(Some(p))),
                    model: Model::default(),
                },
                test_update,
                test_view,
            )
            .mount(seed::body())
            .finish()
            .run();

            let results = r#"{
                "results": []
            }"#;

            let raw = web_sys::Response::new_with_opt_str(Some(results)).unwrap();
            let data: InfluxResults = serde_json::from_str(results).unwrap();

            let fetch_object: FetchObject<InfluxResults> = FetchObject {
                request: Request::new("/influx?db=iml_stratagem_scans&q=SELECT counter_name, count FROM stratagem_scan WHERE group_name='user_distribution'"),
                result: Ok(ResponseWithDataResult {
                    raw,
                    status: Status {code: 200, text: "OK".into(), category: StatusCategory::Success},
                    data: Ok(data)
                })
            };

            app.update(Msg::InodesFetched(fetch_object));

            c.map(|el| {
                assert_eq!(el.get_children().unwrap().len(), 0);
            })
            .map_err(|_| unreachable!())
        }

        render()
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Ana Hobden (@hoverbear) <operator@hoverbear.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

use proc_macro2::TokenStream;
use proc_macro_error::abort_call_site;
use quote::quote;
use syn::Ident;
use syn::Variant;
use syn::{
    self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields,
    Generics,
};

use crate::derives::{args, into_app, subcommand};
use crate::dummies;
use crate::item::Item;
use crate::item::Name;

pub fn derive_parser(input: &DeriveInput) -> TokenStream {
    let ident = &input.ident;

    match input.data {
        Data::Struct(DataStruct {
            fields: Fields::Named(ref fields),
            ..
        }) => {
            dummies::parser_struct(ident);

            let name = Name::Assigned(quote!(std::env::var("CARGO_PKG_NAME")
                .ok()
                .unwrap_or_default()));
            let item = Item::from_args_struct(input, name);
            let fields = fields
                .named
                .iter()
                .map(|field| {
                    let item = Item::from_args_field(field, item.casing(), item.env_casing());
                    (field, item)
                })
                .collect::<Vec<_>>();
            gen_for_struct(&item, ident, &input.generics, &fields)
        }
        Data::Struct(DataStruct {
            fields: Fields::Unit,
            ..
        }) => {
            dummies::parser_struct(ident);

            let name = Name::Assigned(quote!(std::env::var("CARGO_PKG_NAME")
                .ok()
                .unwrap_or_default()));
            let item = Item::from_args_struct(input, name);
            let fields = Punctuated::<Field, Comma>::new();
            let fields = fields
                .iter()
                .map(|field| {
                    let item = Item::from_args_field(field, item.casing(), item.env_casing());
                    (field, item)
                })
                .collect::<Vec<_>>();
            gen_for_struct(&item, ident, &input.generics, &fields)
        }
        Data::Enum(ref e) => {
            dummies::parser_enum(ident);

            let name = Name::Assigned(quote!(std::env::var("CARGO_PKG_NAME")
                .ok()
                .unwrap_or_default()));
            let item = Item::from_subcommand_enum(input, name);
            let variants = e
                .variants
                .iter()
                .map(|variant| {
                    let item =
                        Item::from_subcommand_variant(variant, item.casing(), item.env_casing());
                    (variant, item)
                })
                .collect::<Vec<_>>();
            gen_for_enum(&item, ident, &input.generics, &variants)
        }
        _ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"),
    }
}

fn gen_for_struct(
    item: &Item,
    item_name: &Ident,
    generics: &Generics,
    fields: &[(&Field, Item)],
) -> TokenStream {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let into_app = into_app::gen_for_struct(item, item_name, generics);
    let args = args::gen_for_struct(item, item_name, generics, fields);

    quote! {
        impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}

        #into_app
        #args
    }
}

fn gen_for_enum(
    item: &Item,
    item_name: &Ident,
    generics: &Generics,
    variants: &[(&Variant, Item)],
) -> TokenStream {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let into_app = into_app::gen_for_enum(item, item_name, generics);
    let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants);

    quote! {
        impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}

        #into_app
        #subcommand
    }
}
<commit_msg>fix(derive): Read CARGO_PKG_NAME at runtime<commit_after>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Ana Hobden (@hoverbear) <operator@hoverbear.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.

use proc_macro2::TokenStream;
use proc_macro_error::abort_call_site;
use quote::quote;
use syn::Ident;
use syn::Variant;
use syn::{
    self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields,
    Generics,
};

use crate::derives::{args, into_app, subcommand};
use crate::dummies;
use crate::item::Item;
use crate::item::Name;

pub fn derive_parser(input: &DeriveInput) -> TokenStream {
    let ident = &input.ident;
    let pkg_name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();

    match input.data {
        Data::Struct(DataStruct {
            fields: Fields::Named(ref fields),
            ..
        }) => {
            dummies::parser_struct(ident);

            let name = Name::Assigned(quote!(#pkg_name));
            let item = Item::from_args_struct(input, name);
            let fields = fields
                .named
                .iter()
                .map(|field| {
                    let item = Item::from_args_field(field, item.casing(), item.env_casing());
                    (field, item)
                })
                .collect::<Vec<_>>();
            gen_for_struct(&item, ident, &input.generics, &fields)
        }
        Data::Struct(DataStruct {
            fields: Fields::Unit,
            ..
        }) => {
            dummies::parser_struct(ident);

            let name = Name::Assigned(quote!(#pkg_name));
            let item = Item::from_args_struct(input, name);
            let fields = Punctuated::<Field, Comma>::new();
            let fields = fields
                .iter()
                .map(|field| {
                    let item = Item::from_args_field(field, item.casing(), item.env_casing());
                    (field, item)
                })
                .collect::<Vec<_>>();
            gen_for_struct(&item, ident, &input.generics, &fields)
        }
        Data::Enum(ref e) => {
            dummies::parser_enum(ident);

            let name = Name::Assigned(quote!(#pkg_name));
            let item = Item::from_subcommand_enum(input, name);
            let variants = e
                .variants
                .iter()
                .map(|variant| {
                    let item =
                        Item::from_subcommand_variant(variant, item.casing(), item.env_casing());
                    (variant, item)
                })
                .collect::<Vec<_>>();
            gen_for_enum(&item, ident, &input.generics, &variants)
        }
        _ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"),
    }
}

fn gen_for_struct(
    item: &Item,
    item_name: &Ident,
    generics: &Generics,
    fields: &[(&Field, Item)],
) -> TokenStream {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let into_app = into_app::gen_for_struct(item, item_name, generics);
    let args = args::gen_for_struct(item, item_name, generics, fields);

    quote! {
        impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}

        #into_app
        #args
    }
}

fn gen_for_enum(
    item: &Item,
    item_name: &Ident,
    generics: &Generics,
    variants: &[(&Variant, Item)],
) -> TokenStream {
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let into_app = into_app::gen_for_enum(item, item_name, generics);
    let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants);

    quote! {
        impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {}

        #into_app
        #subcommand
    }
}
<|endoftext|>


<commit_before>/*!
`crypto_secretbox_xsalsa20poly1305`, a particular
combination of Salsa20 and Poly1305 specified in
[Cryptography in NaCl](http://nacl.cr.yp.to/valid.html).

This function is conjectured to meet the standard notions of privacy and
authenticity.
*/
use libc::{c_ulonglong, c_int};
use std::intrinsics::volatile_set_memory;
use utils::marshal;
use randombytes::randombytes_into;

#[link(name = "sodium")]
extern {
    fn crypto_secretbox_xsalsa20poly1305(c: *mut u8,
                                         m: *const u8,
                                         mlen: c_ulonglong,
                                         n: *const u8,
                                         k: *const u8) -> c_int;
    fn crypto_secretbox_xsalsa20poly1305_open(m: *mut u8,
                                              c: *const u8,
                                              clen: c_ulonglong,
                                              n: *const u8,
                                              k: *const u8) -> c_int;
}

pub const KEYBYTES: uint = 32;
pub const NONCEBYTES: uint = 24;

/**
 * `Key` for symmetric authenticated encryption
 *
 * When a `Key` goes out of scope its contents
 * will be zeroed out
 */
pub struct Key(pub [u8, ..KEYBYTES]);

newtype_drop!(Key)
newtype_clone!(Key)

/**
 * `Nonce` for symmetric authenticated encryption
 */
pub struct Nonce(pub [u8, ..NONCEBYTES]);

newtype_clone!(Nonce)

pub static ZEROBYTES: uint = 32;
pub static BOXZEROBYTES: uint = 16;

/**
 * `gen_key()` randomly generates a secret key
 *
 * THREAD SAFETY: `gen_key()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_key() -> Key {
    let mut key = [0, ..KEYBYTES];
    randombytes_into(key);
    Key(key)
}

/**
 * `gen_nonce()` randomly generates a nonce
 *
 * THREAD SAFETY: `gen_key()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_nonce() -> Nonce {
    let mut nonce = [0, ..NONCEBYTES];
    randombytes_into(nonce);
    Nonce(nonce)
}

/**
 * `seal()` encrypts and authenticates a message `m` using a secret key `k` and a
 * nonce `n`.  It returns a ciphertext `c`.
 */
pub fn seal(m: &[u8],
            &Nonce(n): &Nonce,
            &Key(k): &Key) -> Vec<u8> {
    let (c, _) = marshal(m, ZEROBYTES, BOXZEROBYTES, |dst, src, len| {
        unsafe {
            crypto_secretbox_xsalsa20poly1305(dst, src, len, n.as_ptr(), k.as_ptr())
        }
    });
    c
}

/**
 * `open()` verifies and decrypts a ciphertext `c` using a secret key `k` and a nonce `n`.
 * It returns a plaintext `Some(m)`.
 * If the ciphertext fails verification, `open()` returns `None`.
 */
pub fn open(c: &[u8],
            &Nonce(n): &Nonce,
            &Key(k): &Key) -> Option<Vec<u8>> {
    if c.len() < BOXZEROBYTES {
        return None
    }
    let (m, ret) = marshal(c, BOXZEROBYTES, ZEROBYTES, |dst, src, len| {
        unsafe {
            crypto_secretbox_xsalsa20poly1305_open(dst,
                                                   src,
                                                   len,
                                                   n.as_ptr(),
                                                   k.as_ptr())
        }
    });
    if ret == 0 {
        Some(m)
    } else {
        None
    }
}

#[test]
fn test_seal_open() {
    use randombytes::randombytes;
    for i in range(0, 256u) {
        let k = gen_key();
        let m = randombytes(i);
        let n = gen_nonce();
        let c = seal(m.as_slice(), &n, &k);
        let opened = open(c.as_slice(), &n, &k);
        assert!(Some(m) == opened);
    }
}

#[test]
fn test_seal_open_tamper() {
    use randombytes::randombytes;
    for i in range(0, 32u) {
        let k = gen_key();
        let m = randombytes(i);
        let n = gen_nonce();
        let mut cv = seal(m.as_slice(), &n, &k);
        let c = cv.as_mut_slice();
        for i in range(0, c.len()) {
            c[i] ^= 0x20;
            assert!(None == open(c, &n, &k));
            c[i] ^= 0x20;
        }
    }
}

#[test]
fn test_vector_1() {
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let m = vec![0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
             ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
             ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
             ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
             ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
             ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
             ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
             ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
             ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
             ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
             ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
             ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
             ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
             ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
             ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
             ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
             ,0x5e,0x07,0x05];

    let c_expected = vec![0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
                      ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
                      ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
                      ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
                      ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
                      ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
                      ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
                      ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
                      ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
                      ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
                      ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
                      ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
                      ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
                      ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
                      ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
                      ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
                      ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
                      ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
                      ,0xe3,0x55,0xa5];
    let c = seal(m.as_slice(), &nonce, &firstkey);
    assert!(c == c_expected);
    let m2 = open(c.as_slice(), &nonce, &firstkey);
    assert!(Some(m) == m2);
}
<commit_msg>make ZEROBYTES and BOXZEROBYTES const and hidden<commit_after>/*!
`crypto_secretbox_xsalsa20poly1305`, a particular
combination of Salsa20 and Poly1305 specified in
[Cryptography in NaCl](http://nacl.cr.yp.to/valid.html).

This function is conjectured to meet the standard notions of privacy and
authenticity.
*/
use libc::{c_ulonglong, c_int};
use std::intrinsics::volatile_set_memory;
use utils::marshal;
use randombytes::randombytes_into;

#[link(name = "sodium")]
extern {
    fn crypto_secretbox_xsalsa20poly1305(c: *mut u8,
                                         m: *const u8,
                                         mlen: c_ulonglong,
                                         n: *const u8,
                                         k: *const u8) -> c_int;
    fn crypto_secretbox_xsalsa20poly1305_open(m: *mut u8,
                                              c: *const u8,
                                              clen: c_ulonglong,
                                              n: *const u8,
                                              k: *const u8) -> c_int;
}

pub const KEYBYTES: uint = 32;
pub const NONCEBYTES: uint = 24;

/**
 * `Key` for symmetric authenticated encryption
 *
 * When a `Key` goes out of scope its contents
 * will be zeroed out
 */
pub struct Key(pub [u8, ..KEYBYTES]);

newtype_drop!(Key)
newtype_clone!(Key)

/**
 * `Nonce` for symmetric authenticated encryption
 */
pub struct Nonce(pub [u8, ..NONCEBYTES]);

newtype_clone!(Nonce)

const ZEROBYTES: uint = 32;
const BOXZEROBYTES: uint = 16;

/**
 * `gen_key()` randomly generates a secret key
 *
 * THREAD SAFETY: `gen_key()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_key() -> Key {
    let mut key = [0, ..KEYBYTES];
    randombytes_into(key);
    Key(key)
}

/**
 * `gen_nonce()` randomly generates a nonce
 *
 * THREAD SAFETY: `gen_key()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_nonce() -> Nonce {
    let mut nonce = [0, ..NONCEBYTES];
    randombytes_into(nonce);
    Nonce(nonce)
}

/**
 * `seal()` encrypts and authenticates a message `m` using a secret key `k` and a
 * nonce `n`.  It returns a ciphertext `c`.
 */
pub fn seal(m: &[u8],
            &Nonce(n): &Nonce,
            &Key(k): &Key) -> Vec<u8> {
    let (c, _) = marshal(m, ZEROBYTES, BOXZEROBYTES, |dst, src, len| {
        unsafe {
            crypto_secretbox_xsalsa20poly1305(dst, src, len, n.as_ptr(), k.as_ptr())
        }
    });
    c
}

/**
 * `open()` verifies and decrypts a ciphertext `c` using a secret key `k` and a nonce `n`.
 * It returns a plaintext `Some(m)`.
 * If the ciphertext fails verification, `open()` returns `None`.
 */
pub fn open(c: &[u8],
            &Nonce(n): &Nonce,
            &Key(k): &Key) -> Option<Vec<u8>> {
    if c.len() < BOXZEROBYTES {
        return None
    }
    let (m, ret) = marshal(c, BOXZEROBYTES, ZEROBYTES, |dst, src, len| {
        unsafe {
            crypto_secretbox_xsalsa20poly1305_open(dst,
                                                   src,
                                                   len,
                                                   n.as_ptr(),
                                                   k.as_ptr())
        }
    });
    if ret == 0 {
        Some(m)
    } else {
        None
    }
}

#[test]
fn test_seal_open() {
    use randombytes::randombytes;
    for i in range(0, 256u) {
        let k = gen_key();
        let m = randombytes(i);
        let n = gen_nonce();
        let c = seal(m.as_slice(), &n, &k);
        let opened = open(c.as_slice(), &n, &k);
        assert!(Some(m) == opened);
    }
}

#[test]
fn test_seal_open_tamper() {
    use randombytes::randombytes;
    for i in range(0, 32u) {
        let k = gen_key();
        let m = randombytes(i);
        let n = gen_nonce();
        let mut cv = seal(m.as_slice(), &n, &k);
        let c = cv.as_mut_slice();
        for i in range(0, c.len()) {
            c[i] ^= 0x20;
            assert!(None == open(c, &n, &k));
            c[i] ^= 0x20;
        }
    }
}

#[test]
fn test_vector_1() {
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let m = vec![0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
             ,0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
             ,0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
             ,0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
             ,0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
             ,0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
             ,0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
             ,0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
             ,0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
             ,0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
             ,0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
             ,0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
             ,0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
             ,0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
             ,0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
             ,0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
             ,0x5e,0x07,0x05];

    let c_expected = vec![0xf3,0xff,0xc7,0x70,0x3f,0x94,0x00,0xe5
                      ,0x2a,0x7d,0xfb,0x4b,0x3d,0x33,0x05,0xd9
                      ,0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
                      ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
                      ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
                      ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
                      ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
                      ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
                      ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
                      ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
                      ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
                      ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
                      ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
                      ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
                      ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
                      ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
                      ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
                      ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
                      ,0xe3,0x55,0xa5];
    let c = seal(m.as_slice(), &nonce, &firstkey);
    assert!(c == c_expected);
    let m2 = open(c.as_slice(), &nonce, &firstkey);
    assert!(Some(m) == m2);
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::Rectangle;
use util::units::{Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_frame.location() + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[self.map_view.y as usize .. self.map_view.y as usize + height].iter().enumerate() {
            for (x, cell) in line[self.map_view.x as usize .. self.map_view.x as usize + width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map_frame.width() < game.world.map.width()
    }

    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map_frame.height() < game.world.map.height()
    }

}
<commit_msg>Rename render_map -> draw_map in GameScreen<commit_after>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::Rectangle;
use util::units::{Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.draw_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_frame.location() + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn draw_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[self.map_view.y as usize .. self.map_view.y as usize + height].iter().enumerate() {
            for (x, cell) in line[self.map_view.x as usize .. self.map_view.x as usize + width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

    fn view_can_move_right(&self, game: &Game) -> bool {
        self.map_view.x + self.map_frame.width() < game.world.map.width()
    }

    fn view_can_move_down(&self, game: &Game) -> bool {
        self.map_view.y + self.map_frame.height() < game.world.map.height()
    }

}
<|endoftext|>


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

use clone::Clone;
use cmp;
use collections::Collection;
use comm::{Sender, Receiver};
use io;
use option::{None, Option, Some};
use result::{Ok, Err};
use slice::{bytes, CloneableVector};
use super::{Reader, Writer, IoResult};
use vec::Vec;

/// Allows reading from a rx.
///
/// # Example
///
/// ```
/// use std::io::ChanReader;
///
/// let (tx, rx) = channel();
/// # drop(tx);
/// let mut reader = ChanReader::new(rx);
///
/// let mut buf = [0u8, ..100];
/// match reader.read(buf) {
///     Ok(nread) => println!("Read {} bytes", nread),
///     Err(e) => println!("read error: {}", e),
/// }
/// ```
pub struct ChanReader {
    buf: Option<Vec<u8>>,  // A buffer of bytes received but not consumed.
    pos: uint,             // How many of the buffered bytes have already be consumed.
    rx: Receiver<Vec<u8>>, // The Receiver to pull data from.
    closed: bool,          // Whether the channel this Receiver connects to has been closed.
}

impl ChanReader {
    /// Wraps a `Port` in a `ChanReader` structure
    pub fn new(rx: Receiver<Vec<u8>>) -> ChanReader {
        ChanReader {
            buf: None,
            pos: 0,
            rx: rx,
            closed: false,
        }
    }
}

impl Reader for ChanReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let mut num_read = 0;
        loop {
            match self.buf {
                Some(ref prev) => {
                    let dst = buf[mut num_read..];
                    let src = prev[self.pos..];
                    let count = cmp::min(dst.len(), src.len());
                    bytes::copy_memory(dst, src[..count]);
                    num_read += count;
                    self.pos += count;
                },
                None => (),
            };
            if num_read == buf.len() || self.closed {
                break;
            }
            self.pos = 0;
            self.buf = self.rx.recv_opt().ok();
            self.closed = self.buf.is_none();
        }
        if self.closed && num_read == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(num_read)
        }
    }
}

/// Allows writing to a tx.
///
/// # Example
///
/// ```
/// # #![allow(unused_must_use)]
/// use std::io::ChanWriter;
///
/// let (tx, rx) = channel();
/// # drop(rx);
/// let mut writer = ChanWriter::new(tx);
/// writer.write("hello, world".as_bytes());
/// ```
pub struct ChanWriter {
    tx: Sender<Vec<u8>>,
}

impl ChanWriter {
    /// Wraps a channel in a `ChanWriter` structure
    pub fn new(tx: Sender<Vec<u8>>) -> ChanWriter {
        ChanWriter { tx: tx }
    }
}

impl Clone for ChanWriter {
    fn clone(&self) -> ChanWriter {
        ChanWriter { tx: self.tx.clone() }
    }
}

impl Writer for ChanWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.tx.send_opt(buf.to_vec()).map_err(|_| {
            io::IoError {
                kind: io::BrokenPipe,
                desc: "Pipe closed",
                detail: None
            }
        })
    }
}

#[cfg(test)]
mod test {
    use prelude::*;
    use super::*;
    use io;
    use task;

    #[test]
    fn test_rx_reader() {
        let (tx, rx) = channel();
        task::spawn(proc() {
          tx.send(vec![1u8, 2u8]);
          tx.send(vec![]);
          tx.send(vec![3u8, 4u8]);
          tx.send(vec![5u8, 6u8]);
          tx.send(vec![7u8, 8u8]);
        });

        let mut reader = ChanReader::new(rx);
        let mut buf = [0u8, ..3];

        assert_eq!(Ok(0), reader.read([]));

        assert_eq!(Ok(3), reader.read(buf));
        let a: &[u8] = &[1,2,3];
        assert_eq!(a, buf.as_slice());

        assert_eq!(Ok(3), reader.read(buf));
        let a: &[u8] = &[4,5,6];
        assert_eq!(a, buf.as_slice());

        assert_eq!(Ok(2), reader.read(buf));
        let a: &[u8] = &[7,8,6];
        assert_eq!(a, buf.as_slice());

        match reader.read(buf.as_mut_slice()) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::EndOfFile),
        }
        assert_eq!(a, buf.as_slice());

        // Ensure it continues to fail in the same way.
        match reader.read(buf.as_mut_slice()) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::EndOfFile),
        }
        assert_eq!(a, buf.as_slice());
    }

    #[test]
    fn test_chan_writer() {
        let (tx, rx) = channel();
        let mut writer = ChanWriter::new(tx);
        writer.write_be_u32(42).unwrap();

        let wanted = vec![0u8, 0u8, 0u8, 42u8];
        let got = match task::try(proc() { rx.recv() }) {
            Ok(got) => got,
            Err(_) => fail!(),
        };
        assert_eq!(wanted, got);

        match writer.write_u8(1) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::BrokenPipe),
        }
    }
}
<commit_msg>impl Buffer for ChanReader<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use clone::Clone;
use cmp;
use collections::Collection;
use comm::{Sender, Receiver};
use io;
use option::{None, Some};
use result::{Ok, Err};
use slice::{bytes, CloneableVector};
use super::{Buffer, Reader, Writer, IoResult};
use vec::Vec;

/// Allows reading from a rx.
///
/// # Example
///
/// ```
/// use std::io::ChanReader;
///
/// let (tx, rx) = channel();
/// # drop(tx);
/// let mut reader = ChanReader::new(rx);
///
/// let mut buf = [0u8, ..100];
/// match reader.read(buf) {
///     Ok(nread) => println!("Read {} bytes", nread),
///     Err(e) => println!("read error: {}", e),
/// }
/// ```
pub struct ChanReader {
    buf: Vec<u8>,          // A buffer of bytes received but not consumed.
    pos: uint,             // How many of the buffered bytes have already be consumed.
    rx: Receiver<Vec<u8>>, // The Receiver to pull data from.
    closed: bool,          // Whether the channel this Receiver connects to has been closed.
}

impl ChanReader {
    /// Wraps a `Port` in a `ChanReader` structure
    pub fn new(rx: Receiver<Vec<u8>>) -> ChanReader {
        ChanReader {
            buf: Vec::new(),
            pos: 0,
            rx: rx,
            closed: false,
        }
    }
}

impl Buffer for ChanReader {
    fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> {
        if self.pos >= self.buf.len() {
            self.pos = 0;
            match self.rx.recv_opt() {
                Ok(bytes) => {
                    self.buf = bytes;
                },
                Err(()) => {
                    self.closed = true;
                    self.buf = Vec::new();
                }
            }
        }
        if self.closed {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(self.buf.slice_from(self.pos))
        }
    }

    fn consume(&mut self, amt: uint) {
        self.pos += amt;
        assert!(self.pos <= self.buf.len());
    }
}

impl Reader for ChanReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let mut num_read = 0;
        loop {
            let count = match self.fill_buf().ok() {
                Some(src) => {
                    let dst = buf[mut num_read..];
                    let count = cmp::min(src.len(), dst.len());
                    bytes::copy_memory(dst, src[..count]);
                    count
                },
                None => 0,
            };
            self.consume(count);
            num_read += count;
            if num_read == buf.len() || self.closed {
                break;
            }
        }
        if self.closed && num_read == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(num_read)
        }
    }
}

/// Allows writing to a tx.
///
/// # Example
///
/// ```
/// # #![allow(unused_must_use)]
/// use std::io::ChanWriter;
///
/// let (tx, rx) = channel();
/// # drop(rx);
/// let mut writer = ChanWriter::new(tx);
/// writer.write("hello, world".as_bytes());
/// ```
pub struct ChanWriter {
    tx: Sender<Vec<u8>>,
}

impl ChanWriter {
    /// Wraps a channel in a `ChanWriter` structure
    pub fn new(tx: Sender<Vec<u8>>) -> ChanWriter {
        ChanWriter { tx: tx }
    }
}

impl Clone for ChanWriter {
    fn clone(&self) -> ChanWriter {
        ChanWriter { tx: self.tx.clone() }
    }
}

impl Writer for ChanWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.tx.send_opt(buf.to_vec()).map_err(|_| {
            io::IoError {
                kind: io::BrokenPipe,
                desc: "Pipe closed",
                detail: None
            }
        })
    }
}

#[cfg(test)]
mod test {
    use prelude::*;
    use super::*;
    use io;
    use task;

    #[test]
    fn test_rx_reader() {
        let (tx, rx) = channel();
        task::spawn(proc() {
          tx.send(vec![1u8, 2u8]);
          tx.send(vec![]);
          tx.send(vec![3u8, 4u8]);
          tx.send(vec![5u8, 6u8]);
          tx.send(vec![7u8, 8u8]);
        });

        let mut reader = ChanReader::new(rx);
        let mut buf = [0u8, ..3];

        assert_eq!(Ok(0), reader.read([]));

        assert_eq!(Ok(3), reader.read(buf));
        let a: &[u8] = &[1,2,3];
        assert_eq!(a, buf.as_slice());

        assert_eq!(Ok(3), reader.read(buf));
        let a: &[u8] = &[4,5,6];
        assert_eq!(a, buf.as_slice());

        assert_eq!(Ok(2), reader.read(buf));
        let a: &[u8] = &[7,8,6];
        assert_eq!(a, buf.as_slice());

        match reader.read(buf.as_mut_slice()) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::EndOfFile),
        }
        assert_eq!(a, buf.as_slice());

        // Ensure it continues to fail in the same way.
        match reader.read(buf.as_mut_slice()) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::EndOfFile),
        }
        assert_eq!(a, buf.as_slice());
    }

    #[test]
    fn test_rx_buffer() {
        let (tx, rx) = channel();
        task::spawn(proc() {
          tx.send(b"he".to_vec());
          tx.send(b"llo wo".to_vec());
          tx.send(b"".to_vec());
          tx.send(b"rld\nhow ".to_vec());
          tx.send(b"are you?".to_vec());
          tx.send(b"".to_vec());
        });

        let mut reader = ChanReader::new(rx);

        assert_eq!(Ok("hello world\n".to_string()), reader.read_line());
        assert_eq!(Ok("how are you?".to_string()), reader.read_line());
        match reader.read_line() {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::EndOfFile),
        }
    }

    #[test]
    fn test_chan_writer() {
        let (tx, rx) = channel();
        let mut writer = ChanWriter::new(tx);
        writer.write_be_u32(42).unwrap();

        let wanted = vec![0u8, 0u8, 0u8, 42u8];
        let got = match task::try(proc() { rx.recv() }) {
            Ok(got) => got,
            Err(_) => fail!(),
        };
        assert_eq!(wanted, got);

        match writer.write_u8(1) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, io::BrokenPipe),
        }
    }
}
<|endoftext|>