<commit_before>
use std::io::{Result, Write};

use html5ever;
use html5ever::serialize::{SerializeOpts, TraversalScope};

pub use self::document::{DocumentSerializer, DocumentDoctypeSerializer};
pub use self::empty_attrs::EmptyAttrs;
pub use self::node::NodeSerializer;
use self::serializer::Serializer;

mod document;
mod empty_attrs;
mod node;
mod serializer;

pub trait SerializeDocument {
    fn serialize_document<W: Write>(&self, DocumentSerializer<W>);
}

pub trait SerializeNode {
    fn serialize_node<W: Write>(self, &mut NodeSerializer<W>);
}

impl<I: SerializeNode, T: Iterator<Item = I>> SerializeNode for T {
    fn serialize_node<W: Write>(self, s: &mut NodeSerializer<W>) {
        for node in self.into_iter() {
            node.serialize_node(s);
        }
    }
}

struct Serializable<'a, T: 'a + SerializeDocument>(&'a T);

impl<'a, T: SerializeDocument> html5ever::serialize::Serializable for Serializable<'a, T> {
    fn serialize<'w, W: Write>(&self,
                               serializer: &mut html5ever::serialize::Serializer<'w, W>,
                               _: TraversalScope)
                               -> Result<()> {
        let mut serializer = Serializer::new(serializer);

        {
            let doc_ser = document::new_doc_ser(&mut serializer);
            self.0.serialize_document(doc_ser);
        }

        serializer.error()
    }
}

pub fn serialize<'w, W, T>(writer: &mut W, document: &T) -> Result<()>
    where W: 'w + Write,
          T: SerializeDocument
{
    html5ever::serialize::serialize(writer, &Serializable(document), SerializeOpts::default())
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;
    use std::io::Write;

    #[test]
    fn test_empty_document() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, _: DocumentSerializer<W>) {}
        }

        assert_eq!(ser(&Doc), "");
    }

    #[test]
    fn test_basic_document() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
            }
        }

        assert_eq!(ser(&Doc), "<!DOCTYPE html>");
    }

    #[test]
    fn test_nodes() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                let mut html = s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
                {
                    let mut head = html.element_normal(qualname!(html, "head"), EmptyAttrs::new());
                    {
                        let mut title = head.element_normal(qualname!(html, "title"), EmptyAttrs::new());
                        title.text("test");
                    }
                }
                {
                    let mut body = html.element_normal(qualname!(html, "body"), EmptyAttrs::new());
                    body.text("more tests!");
                }
            }
        }

        assert_eq!(ser(&Doc),
                   "<!DOCTYPE html><title>test</title>more \
                    tests!");
    }

    #[test]
    fn test_nodes_ser() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                let mut html = s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
                let mut body = html.element_normal(qualname!(html, "body"), EmptyAttrs::new());
                Node(0).serialize_node(&mut body);

                vec![Node(1), Node(2)].iter().serialize_node(&mut body);
                (3..5).map(Node).serialize_node(&mut body);
            }
        }

        struct Node(i32);

        impl SerializeNode for Node {
            fn serialize_node<W: Write>(self, s: &mut NodeSerializer<W>) {
                (&self).serialize_node(s);
            }
        }

        impl<'a> SerializeNode for &'a Node {
            fn serialize_node<W: Write>(self, s: &mut NodeSerializer<W>) {
                let mut p = s.element_normal(qualname!(html, "p"), EmptyAttrs::new());
                p.text(&format!("{}", self.0));
            }
        }

        assert_eq!(ser(&Doc),
                   "<!DOCTYPE \
                    html>
0

1

2

3

4
");
    }

    #[bench]
    fn bench_serialize_document(b: &mut Bencher) {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                let mut html = s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
                {
                    let mut head = html.element_normal(qualname!(html, "head"), EmptyAttrs::new());
                    {
                        let mut title = head.element_normal(qualname!(html, "title"), EmptyAttrs::new());
                        title.text("test");
                    }
                }
                {
                    let mut body = html.element_normal(qualname!(html, "body"), EmptyAttrs::new());
                    body.text("more tests!");
                }
            }
        }

        b.iter(|| {
            let mut writer = Vec::new();
            serialize(&mut writer, &Doc).unwrap();
            writer
        });
    }

    fn ser<T: SerializeDocument>(document: &T) -> String {
        let mut writer = Vec::new();
        serialize(&mut writer, document).unwrap();
        String::from_utf8(writer).unwrap()
    }
}
<commit_msg>Fixed tests for stable/beta.<commit_after>
use std::io::{Result, Write};

use html5ever;
use html5ever::serialize::{SerializeOpts, TraversalScope};

pub use self::document::{DocumentSerializer, DocumentDoctypeSerializer};
pub use self::empty_attrs::EmptyAttrs;
pub use self::node::NodeSerializer;
use self::serializer::Serializer;

mod document;
mod empty_attrs;
mod node;
mod serializer;

pub trait SerializeDocument {
    fn serialize_document<W: Write>(&self, DocumentSerializer<W>);
}

pub trait SerializeNode {
    fn serialize_node<W: Write>(self, &mut NodeSerializer<W>);
}

impl<I: SerializeNode, T: Iterator<Item = I>> SerializeNode for T {
    fn serialize_node<W: Write>(self, s: &mut NodeSerializer<W>) {
        for node in self.into_iter() {
            node.serialize_node(s);
        }
    }
}

struct Serializable<'a, T: 'a + SerializeDocument>(&'a T);

impl<'a, T: SerializeDocument> html5ever::serialize::Serializable for Serializable<'a, T> {
    fn serialize<'w, W: Write>(&self,
                               serializer: &mut html5ever::serialize::Serializer<'w, W>,
                               _: TraversalScope)
                               -> Result<()> {
        let mut serializer = Serializer::new(serializer);

        {
            let doc_ser = document::new_doc_ser(&mut serializer);
            self.0.serialize_document(doc_ser);
        }

        serializer.error()
    }
}

pub fn serialize<'w, W, T>(writer: &mut W, document: &T) -> Result<()>
    where W: 'w + Write,
          T: SerializeDocument
{
    html5ever::serialize::serialize(writer, &Serializable(document), SerializeOpts::default())
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature = "nightly")]
    use test::Bencher;
    use std::io::Write;

    #[test]
    fn test_empty_document() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, _: DocumentSerializer<W>) {}
        }

        assert_eq!(ser(&Doc), "");
    }

    #[test]
    fn test_basic_document() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
            }
        }

        assert_eq!(ser(&Doc), "<!DOCTYPE html>");
    }

    #[test]
    fn test_nodes() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                let mut html = s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
                {
                    let mut head = html.element_normal(qualname!(html, "head"), EmptyAttrs::new());
                    {
                        let mut title = head.element_normal(qualname!(html, "title"), EmptyAttrs::new());
                        title.text("test"); } } {
                    let mut body = html.element_normal(qualname!(html, "body"), EmptyAttrs::new());
                    body.text("more tests!");
                }
            }
        }

        assert_eq!(ser(&Doc),
                   "<!DOCTYPE html><title>test</title>more \
                    tests!");
    }

    #[test]
    fn test_nodes_ser() {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                let mut html = s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
                let mut body = html.element_normal(qualname!(html, "body"), EmptyAttrs::new());
                Node(0).serialize_node(&mut body);

                vec![Node(1), Node(2)].iter().serialize_node(&mut body);
                (3..5).map(Node).serialize_node(&mut body);
            }
        }

        struct Node(i32);

        impl SerializeNode for Node {
            fn serialize_node<W: Write>(self, s: &mut NodeSerializer<W>) {
                (&self).serialize_node(s);
            }
        }

        impl<'a> SerializeNode for &'a Node {
            fn serialize_node<W: Write>(self, s: &mut NodeSerializer<W>) {
                let mut p = s.element_normal(qualname!(html, "p"), EmptyAttrs::new());
                p.text(&format!("{}", self.0));
            }
        }

        assert_eq!(ser(&Doc),
                   "<!DOCTYPE \
                    html>
0

1

2

3

4
");
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn bench_serialize_document(b: &mut Bencher) {
        struct Doc;

        impl SerializeDocument for Doc {
            fn serialize_document<W: Write>(&self, s: DocumentSerializer<W>) {
                let mut html = s.doctype("html").node(qualname!(html, "html"), EmptyAttrs::new());
                {
                    let mut head = html.element_normal(qualname!(html, "head"), EmptyAttrs::new());
                    {
                        let mut title = head.element_normal(qualname!(html, "title"), EmptyAttrs::new());
                        title.text("test");
                    }
                }
                {
                    let mut body = html.element_normal(qualname!(html, "body"), EmptyAttrs::new());
                    body.text("more tests!");
                }
            }
        }

        b.iter(|| {
            let mut writer = Vec::new();
            serialize(&mut writer, &Doc).unwrap();
            writer
        });
    }

    fn ser<T: SerializeDocument>(document: &T) -> String {
        let mut writer = Vec::new();
        serialize(&mut writer, document).unwrap();
        String::from_utf8(writer).unwrap()
    }
}
<|endoftext|>


<commit_before>use crate::{Lint, LintExtractor};
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::process::Command;

/// Descriptions of rustc lint groups.
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
    ("unused", "Lints that detect things being declared but not used, or excess syntax"),
    ("rustdoc", "Rustdoc-specific lints"),
    ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
    ("nonstandard-style", "Violation of standard naming conventions"),
    ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
    ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
];

type LintGroups = BTreeMap<String, BTreeSet<String>>;

impl<'a> LintExtractor<'a> {
    /// Updates the documentation of lint groups.
    pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
        let groups = self.collect_groups()?;
        let groups_path = self.out_path.join("groups.md");
        let contents = fs::read_to_string(&groups_path)
            .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
        let new_contents =
            contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
        // Delete the output because rustbuild uses hard links in its copies.
        let _ = fs::remove_file(&groups_path);
        fs::write(&groups_path, new_contents)
            .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
        Ok(())
    }

    /// Collects the group names from rustc.
    fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> {
        let mut result = BTreeMap::new();
        let mut cmd = Command::new(self.rustc_path);
        cmd.arg("-Whelp");
        let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
        if !output.status.success() {
            return Err(format!(
                "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
                output.status,
                std::str::from_utf8(&output.stderr).unwrap(),
                std::str::from_utf8(&output.stdout).unwrap(),
            )
            .into());
        }
        let stdout = std::str::from_utf8(&output.stdout).unwrap();
        let lines = stdout.lines();
        let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
        let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
        for line in table_start {
            if line.is_empty() {
                break;
            }
            let mut parts = line.trim().splitn(2, ' ');
            let name = parts.next().expect("name in group");
            if name == "warnings" {
                // This is special.
                continue;
            }
            let lints = parts
                .next()
                .ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
            let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
            assert!(result.insert(name.to_string(), lints).is_none());
        }
        if result.is_empty() {
            return Err(
                format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
            );
        }
        Ok(result)
    }

    fn make_groups_table(
        &self,
        lints: &[Lint],
        groups: &LintGroups,
    ) -> Result<String, Box<dyn Error>> {
        let mut result = String::new();
        let mut to_link = Vec::new();
        result.push_str("| Group | Description | Lints |\n");
        result.push_str("|-------|-------------|-------|\n");
        result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
        for (group_name, group_lints) in groups {
            let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) {
                Some((_, desc)) => desc,
                None if self.validate => {
                    return Err(format!(
                        "lint group `{}` does not have a description, \
                         please update the GROUP_DESCRIPTIONS list in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    )
                    .into());
                }
                None => {
                    eprintln!(
                        "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\
                         If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    );
                    continue;
                }
            };
            to_link.extend(group_lints);
            let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
            write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
                .unwrap();
        }
        result.push('\n');
        result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
        for lint_name in to_link {
            let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) {
                Some(def) => def,
                None => {
                    let msg = format!(
                        "`rustc -W help` defined lint `{}` but that lint does not \
                        appear to exist\n\
                        Check that the lint definition includes the appropriate doc comments.",
                        lint_name
                    );
                    if self.validate {
                        return Err(msg.into());
                    } else {
                        eprintln!("warning: {}", msg);
                        continue;
                    }
                }
            };
            write!(
                result,
                "[{}]: listing/{}#{}\n",
                lint_name,
                lint_def.level.doc_filename(),
                lint_name
            )
            .unwrap();
        }
        Ok(result)
    }
}
<commit_msg>Add 2021 compatibility lint description<commit_after>use crate::{Lint, LintExtractor};
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::process::Command;

/// Descriptions of rustc lint groups.
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
    ("unused", "Lints that detect things being declared but not used, or excess syntax"),
    ("rustdoc", "Rustdoc-specific lints"),
    ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
    ("nonstandard-style", "Violation of standard naming conventions"),
    ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
    ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
    ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"),
];

type LintGroups = BTreeMap<String, BTreeSet<String>>;

impl<'a> LintExtractor<'a> {
    /// Updates the documentation of lint groups.
    pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
        let groups = self.collect_groups()?;
        let groups_path = self.out_path.join("groups.md");
        let contents = fs::read_to_string(&groups_path)
            .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
        let new_contents =
            contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
        // Delete the output because rustbuild uses hard links in its copies.
        let _ = fs::remove_file(&groups_path);
        fs::write(&groups_path, new_contents)
            .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
        Ok(())
    }

    /// Collects the group names from rustc.
    fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> {
        let mut result = BTreeMap::new();
        let mut cmd = Command::new(self.rustc_path);
        cmd.arg("-Whelp");
        let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
        if !output.status.success() {
            return Err(format!(
                "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
                output.status,
                std::str::from_utf8(&output.stderr).unwrap(),
                std::str::from_utf8(&output.stdout).unwrap(),
            )
            .into());
        }
        let stdout = std::str::from_utf8(&output.stdout).unwrap();
        let lines = stdout.lines();
        let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
        let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
        for line in table_start {
            if line.is_empty() {
                break;
            }
            let mut parts = line.trim().splitn(2, ' ');
            let name = parts.next().expect("name in group");
            if name == "warnings" {
                // This is special.
                continue;
            }
            let lints = parts
                .next()
                .ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
            let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
            assert!(result.insert(name.to_string(), lints).is_none());
        }
        if result.is_empty() {
            return Err(
                format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
            );
        }
        Ok(result)
    }

    fn make_groups_table(
        &self,
        lints: &[Lint],
        groups: &LintGroups,
    ) -> Result<String, Box<dyn Error>> {
        let mut result = String::new();
        let mut to_link = Vec::new();
        result.push_str("| Group | Description | Lints |\n");
        result.push_str("|-------|-------------|-------|\n");
        result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
        for (group_name, group_lints) in groups {
            let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) {
                Some((_, desc)) => desc,
                None if self.validate => {
                    return Err(format!(
                        "lint group `{}` does not have a description, \
                         please update the GROUP_DESCRIPTIONS list in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    )
                    .into());
                }
                None => {
                    eprintln!(
                        "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\
                         If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
                         src/tools/lint-docs/src/groups.rs",
                        group_name
                    );
                    continue;
                }
            };
            to_link.extend(group_lints);
            let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
            write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
                .unwrap();
        }
        result.push('\n');
        result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
        for lint_name in to_link {
            let lint_def = match lints.iter().find(|l| l.name == lint_name.replace("-", "_")) {
                Some(def) => def,
                None => {
                    let msg = format!(
                        "`rustc -W help` defined lint `{}` but that lint does not \
                        appear to exist\n\
                        Check that the lint definition includes the appropriate doc comments.",
                        lint_name
                    );
                    if self.validate {
                        return Err(msg.into());
                    } else {
                        eprintln!("warning: {}", msg);
                        continue;
                    }
                }
            };
            write!(
                result,
                "[{}]: listing/{}#{}\n",
                lint_name,
                lint_def.level.doc_filename(),
                lint_name
            )
            .unwrap();
        }
        Ok(result)
    }
}
<|endoftext|>


<commit_before>//! TODO documentation

use wlroots_sys::{wlr_output_cursor, wlr_output_cursor_create, wlr_output_cursor_destroy,
                  wlr_output_cursor_move, wlr_output_cursor_set_image,
                  wlr_output_cursor_set_surface};

use {Image, Output, OutputHandle, Surface, UpgradeHandleErr};

#[derive(Debug, Eq, PartialEq)]
pub struct OutputCursor {
    cursor: *mut wlr_output_cursor,
    output_handle: OutputHandle
}

impl OutputCursor {
    /// Creates a new `OutputCursor` that's bound to the given `Output`.
    ///
    /// When the `Output` is destroyed, this can no longer be used.
    ///
    /// # Ergonomics
    /// TODO Put in module documentation
    ///
    /// To make this easier for you, I would suggest putting the `OutputCursor` in your
    /// `OutputHandler` implementor's state so that when the `Output` is removed you
    /// just don't have to think about it and it will clean itself up by itself.
    pub fn new<'output>(output: &'output mut Output) -> Option<OutputCursor> {
        unsafe {
            let output_handle = output.weak_reference();
            let cursor = wlr_output_cursor_create(output.as_ptr());
            if cursor.is_null() {
                None
            } else {
                Some(OutputCursor { cursor,
                                    output_handle })
            }
        }
    }

    /// Sets the hardware cursor's image.
    pub fn set_image(&mut self, image: &Image) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_image(cursor,
                                                                             image.pixels.as_ptr(),
                                                                             image.stride,
                                                                             image.width,
                                                                             image.height,
                                                                             image.hotspot_x,
                                                                             image.hotspot_y)
                                             });
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Sets the hardware cursor's surface.
    pub fn set_surface(&mut self, surface: Surface, hotspot_x: i32, hotspot_y: i32) {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_surface(cursor,
                                                                               surface.as_ptr(),
                                                                               hotspot_x,
                                                                               hotspot_y)
                                             });
            match res {
                Ok(_) | Err(UpgradeHandleErr::AlreadyDropped) => {}
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Moves the hardware cursor to the desired location
    pub fn move_to(&mut self, x: f64, y: f64) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| wlr_output_cursor_move(cursor, x, y));
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Get the coordinates of the cursor.
    ///
    /// Returned value is in (x, y) format.
    pub fn coords(&self) -> (f64, f64) {
        unsafe { ((*self.cursor).x, (*self.cursor).y) }
    }

    /// Determines if the hardware cursor is enabled or not.
    pub fn enabled(&self) -> bool {
        unsafe { (*self.cursor).enabled }
    }

    /// Determines if the hardware cursor is visible or not.
    pub fn visible(&self) -> bool {
        unsafe { (*self.cursor).visible }
    }

    /// Gets the width and height of the hardware cursor.
    ///
    /// Returned value is in (width, height) format.
    pub fn size(&self) -> (u32, u32) {
        unsafe { ((*self.cursor).width, (*self.cursor).height) }
    }

    /// Gets the hotspot coordinates of the hardware cursor.
    ///
    /// Returned value is in (x, y) coordinates.
    pub fn hotspots(&self) -> (i32, i32) {
        unsafe { ((*self.cursor).hotspot_x, (*self.cursor).hotspot_y) }
    }
}

impl Drop for OutputCursor {
    fn drop(&mut self) {
        unsafe { wlr_output_cursor_destroy(self.cursor) }
    }
}
<commit_msg>set_surface can be NULL, removed lifetime on new<commit_after>//! TODO documentation

use wlroots_sys::{wlr_output_cursor, wlr_output_cursor_create, wlr_output_cursor_destroy,
                  wlr_output_cursor_move, wlr_output_cursor_set_image,
                  wlr_output_cursor_set_surface};

use {Image, Output, OutputHandle, Surface, UpgradeHandleErr};

#[derive(Debug, Eq, PartialEq)]
pub struct OutputCursor {
    cursor: *mut wlr_output_cursor,
    output_handle: OutputHandle
}

impl OutputCursor {
    /// Creates a new `OutputCursor` that's bound to the given `Output`.
    ///
    /// When the `Output` is destroyed, this can no longer be used.
    ///
    /// # Ergonomics
    ///
    /// To make this easier for you, I would suggest putting the `OutputCursor` in your
    /// `OutputHandler` implementor's state so that when the `Output` is removed you
    /// just don't have to think about it and it will clean itself up by itself.
    pub fn new(output: &mut Output) -> Option<OutputCursor> {
        unsafe {
            let output_handle = output.weak_reference();
            let cursor = wlr_output_cursor_create(output.as_ptr());
            if cursor.is_null() {
                None
            } else {
                Some(OutputCursor { cursor,
                                    output_handle })
            }
        }
    }

    /// Sets the hardware cursor's image.
    pub fn set_image(&mut self, image: &Image) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_image(cursor,
                                                                             image.pixels.as_ptr(),
                                                                             image.stride,
                                                                             image.width,
                                                                             image.height,
                                                                             image.hotspot_x,
                                                                             image.hotspot_y)
                                             });
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Sets the hardware cursor's surface.
    pub fn set_surface(&mut self, surface: Option<Surface>, hotspot_x: i32, hotspot_y: i32) {
        unsafe {
            let surface_ptr = surface.map(|surface| surface.as_ptr())
                                     .unwrap_or_else(|| ptr::null_mut());
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_surface(cursor,
                                                                               surface_ptr,
                                                                               hotspot_x,
                                                                               hotspot_y)
                                             });
            match res {
                Ok(_) | Err(UpgradeHandleErr::AlreadyDropped) => {}
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Moves the hardware cursor to the desired location
    pub fn move_to(&mut self, x: f64, y: f64) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| wlr_output_cursor_move(cursor, x, y));
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Get the coordinates of the cursor.
    ///
    /// Returned value is in (x, y) format.
    pub fn coords(&self) -> (f64, f64) {
        unsafe { ((*self.cursor).x, (*self.cursor).y) }
    }

    /// Determines if the hardware cursor is enabled or not.
    pub fn enabled(&self) -> bool {
        unsafe { (*self.cursor).enabled }
    }

    /// Determines if the hardware cursor is visible or not.
    pub fn visible(&self) -> bool {
        unsafe { (*self.cursor).visible }
    }

    /// Gets the width and height of the hardware cursor.
    ///
    /// Returned value is in (width, height) format.
    pub fn size(&self) -> (u32, u32) {
        unsafe { ((*self.cursor).width, (*self.cursor).height) }
    }

    /// Gets the hotspot coordinates of the hardware cursor.
    ///
    /// Returned value is in (x, y) coordinates.
    pub fn hotspots(&self) -> (i32, i32) {
        unsafe { ((*self.cursor).hotspot_x, (*self.cursor).hotspot_y) }
    }
}

impl Drop for OutputCursor {
    fn drop(&mut self) {
        unsafe { wlr_output_cursor_destroy(self.cursor) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Andre-Philippe Paquet
// Modifications copyright 2021 Robert Swinford
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file has been modified for use in the uutils' coreutils subproject, sort.

use rayon::prelude::*;
use std::{
    cmp::Ordering,
    collections::VecDeque,
    fs::{File, OpenOptions},
    io::{BufReader, BufWriter, Error, Read, Seek, SeekFrom, Write},
    path::{Path, PathBuf},
};

/// Exposes external sorting (i.e. on disk sorting) capability on arbitrarily
/// sized iterator, even if the generated content of the iterator doesn't fit in
/// memory.
///
/// It uses an in-memory buffer sorted and flushed to disk in segment files when
/// full. Once sorted, it returns a new sorted iterator with all items. In order
/// to remain efficient for all implementations, the crate doesn't handle
/// serialization, but leaves that to the user.
pub struct ExternalSorter {
    segment_size: usize,
    sort_dir: Option<PathBuf>,
    parallel: bool,
}

impl ExternalSorter {
    pub fn new() -> ExternalSorter {
        ExternalSorter {
            segment_size: 16000000000,
            sort_dir: None,
            parallel: false,
        }
    }

    /// Sets the maximum size of each segment in number of sorted items.
    ///
    /// This number of items needs to fit in memory. While sorting, a
    /// in-memory buffer is used to collect the items to be sorted. Once
    /// it reaches the maximum size, it is sorted and then written to disk.
    ///
    /// Using a higher segment size makes sorting faster by leveraging
    /// faster in-memory operations.
    pub fn with_segment_size(mut self, size: usize) -> Self {
        self.segment_size = size;
        self
    }

    /// Sets directory in which sorted segments will be written (if it doesn't
    /// fit in memory).
    pub fn with_sort_dir(mut self, path: PathBuf) -> Self {
        self.sort_dir = Some(path);
        self
    }

    /// Uses Rayon to sort the in-memory buffer.
    ///
    /// This may not be needed if the buffer isn't big enough for parallelism to
    /// be gainful over the overhead of multithreading.
    pub fn with_parallel_sort(mut self) -> Self {
        self.parallel = true;
        self
    }

    /// Sorts a given iterator, returning a new iterator with items
    pub fn sort<T, I>(
        &self,
        iterator: I,
    ) -> Result<SortedIterator<T, impl Fn(&T, &T) -> Ordering + Send + Sync>, Error>
    where
        T: Sortable + Ord,
        I: Iterator<Item = T>,
    {
        self.sort_by(iterator, |a, b| a.cmp(b))
    }

    /// Sorts a given iterator with a comparator function, returning a new iterator with items
    pub fn sort_by<T, I, F>(&self, iterator: I, cmp: F) -> Result<SortedIterator<T, F>, Error>
    where
        T: Sortable,
        I: Iterator<Item = T>,
        F: Fn(&T, &T) -> Ordering + Send + Sync,
    {
        let mut tempdir: Option<tempfile::TempDir> = None;
        let mut sort_dir: Option<PathBuf> = None;

        let mut count = 0;
        let mut segments_file: Vec<File> = Vec::new();
        let size_of_items = std::mem::size_of::<T>();
        let mut buffer: Vec<T> = Vec::with_capacity(self.segment_size / size_of_items);
        for next_item in iterator {
            count += 1;
            buffer.push(next_item);
            if buffer.len() > self.segment_size {
                let sort_dir = self.lazy_create_dir(&mut tempdir, &mut sort_dir)?;
                self.sort_and_write_segment(sort_dir, &mut segments_file, &mut buffer, &cmp)?;
            }
        }

        // Write any items left in buffer, but only if we had at least 1 segment
        // written. Otherwise we use the buffer itself to iterate from memory
        let pass_through_queue = if !buffer.is_empty() && !segments_file.is_empty() {
            let sort_dir = self.lazy_create_dir(&mut tempdir, &mut sort_dir)?;
            self.sort_and_write_segment(sort_dir, &mut segments_file, &mut buffer, &cmp)?;
            None
        } else {
            buffer.sort_by(&cmp);
            Some(VecDeque::from(buffer))
        };

        SortedIterator::new(tempdir, pass_through_queue, segments_file, count, cmp)
    }

    /// We only want to create directory if it's needed (i.e. if the dataset
    /// doesn't fit in memory) to prevent filesystem latency
    fn lazy_create_dir<'a>(
        &self,
        tempdir: &mut Option<tempfile::TempDir>,
        sort_dir: &'a mut Option<PathBuf>,
    ) -> Result<&'a Path, Error> {
        if let Some(sort_dir) = sort_dir {
            return Ok(sort_dir);
        }

        *sort_dir = if let Some(ref sort_dir) = self.sort_dir {
            Some(sort_dir.to_path_buf())
        } else {
            *tempdir = Some(tempfile::TempDir::new()?);
            Some(tempdir.as_ref().unwrap().path().to_path_buf())
        };

        Ok(sort_dir.as_ref().unwrap())
    }

    fn sort_and_write_segment<T, F>(
        &self,
        sort_dir: &Path,
        segments: &mut Vec<File>,
        buffer: &mut Vec<T>,
        cmp: F,
    ) -> Result<(), Error>
    where
        T: Sortable,
        F: Fn(&T, &T) -> Ordering + Send + Sync,
    {
        if self.parallel {
            buffer.par_sort_by(|a, b| cmp(a, b));
        } else {
            buffer.sort_by(|a, b| cmp(a, b));
        }

        let segment_path = sort_dir.join(format!("{}", segments.len()));
        let segment_file = OpenOptions::new()
            .create(true)
            .truncate(true)
            .read(true)
            .write(true)
            .open(&segment_path)?;
        let mut buf_writer = BufWriter::new(segment_file);

        for item in buffer.drain(0..) {
            item.encode(&mut buf_writer);
        }

        let file = buf_writer.into_inner()?;
        segments.push(file);

        Ok(())
    }
}

impl Default for ExternalSorter {
    fn default() -> Self {
        ExternalSorter::new()
    }
}

pub trait Sortable: Sized + Send {
    fn encode<W: Write>(&self, writer: &mut W);
    fn decode<R: Read>(reader: &mut R) -> Option<Self>;
}

pub struct SortedIterator<T: Sortable, F> {
    _tempdir: Option<tempfile::TempDir>,
    pass_through_queue: Option<VecDeque<T>>,
    segments_file: Vec<BufReader<File>>,
    next_values: Vec<Option<T>>,
    count: u64,
    cmp: F,
}

impl<T: Sortable, F: Fn(&T, &T) -> Ordering + Send + Sync> SortedIterator<T, F> {
    fn new(
        tempdir: Option<tempfile::TempDir>,
        pass_through_queue: Option<VecDeque<T>>,
        mut segments_file: Vec<File>,
        count: u64,
        cmp: F,
    ) -> Result<SortedIterator<T, F>, Error> {
        for segment in &mut segments_file {
            segment.seek(SeekFrom::Start(0))?;
        }

        let next_values = segments_file
            .iter_mut()
            .map(|file| T::decode(file))
            .collect();

        let segments_file_buffered = segments_file.into_iter().map(BufReader::new).collect();

        Ok(SortedIterator {
            _tempdir: tempdir,
            pass_through_queue,
            segments_file: segments_file_buffered,
            next_values,
            count,
            cmp,
        })
    }
}

impl<T: Sortable, F: Fn(&T, &T) -> Ordering> Iterator for SortedIterator<T, F> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        // if we have a pass through, we dequeue from it directly
        if let Some(ptb) = self.pass_through_queue.as_mut() {
            return ptb.pop_front();
        }

        // otherwise, we iter from segments on disk
        let mut smallest_idx: Option<usize> = None;
        {
            let mut smallest: Option<&T> = None;
            for idx in 0..self.segments_file.len() {
                let next_value = self.next_values[idx].as_ref();
                if next_value.is_none() {
                    continue;
                }

                if smallest.is_none()
                    || (self.cmp)(next_value.unwrap(), smallest.unwrap()) == Ordering::Less
                {
                    smallest = Some(next_value.unwrap());
                    smallest_idx = Some(idx);
                }
            }
        }

        smallest_idx.map(|idx| {
            let file = &mut self.segments_file[idx];
            let value = self.next_values[idx].take().unwrap();
            self.next_values[idx] = T::decode(file);
            value
        })
    }
}
<commit_msg>Remove unsed code<commit_after>// Copyright 2018 Andre-Philippe Paquet
// Modifications copyright 2021 Robert Swinford
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file has been modified for use in the uutils' coreutils subproject, sort.

use rayon::prelude::*;
use std::{
    cmp::Ordering,
    collections::VecDeque,
    fs::{File, OpenOptions},
    io::{BufReader, BufWriter, Error, Read, Seek, SeekFrom, Write},
    path::{Path, PathBuf},
};

/// Exposes external sorting (i.e. on disk sorting) capability on arbitrarily
/// sized iterator, even if the generated content of the iterator doesn't fit in
/// memory.
///
/// It uses an in-memory buffer sorted and flushed to disk in segment files when
/// full. Once sorted, it returns a new sorted iterator with all items. In order
/// to remain efficient for all implementations, the crate doesn't handle
/// serialization, but leaves that to the user.
pub struct ExternalSorter {
    segment_size: usize,
    sort_dir: Option<PathBuf>,
    parallel: bool,
}

impl ExternalSorter {
    pub fn new() -> ExternalSorter {
        ExternalSorter {
            segment_size: 16000000000,
            sort_dir: None,
            parallel: false,
        }
    }

    /// Sets the maximum size of each segment in number of sorted items.
    ///
    /// This number of items needs to fit in memory. While sorting, a
    /// in-memory buffer is used to collect the items to be sorted. Once
    /// it reaches the maximum size, it is sorted and then written to disk.
    ///
    /// Using a higher segment size makes sorting faster by leveraging
    /// faster in-memory operations.
    pub fn with_segment_size(mut self, size: usize) -> Self {
        self.segment_size = size;
        self
    }

    /// Sets directory in which sorted segments will be written (if it doesn't
    /// fit in memory).
    pub fn with_sort_dir(mut self, path: PathBuf) -> Self {
        self.sort_dir = Some(path);
        self
    }

    /// Uses Rayon to sort the in-memory buffer.
    ///
    /// This may not be needed if the buffer isn't big enough for parallelism to
    /// be gainful over the overhead of multithreading.
    pub fn with_parallel_sort(mut self) -> Self {
        self.parallel = true;
        self
    }

    /// Sorts a given iterator with a comparator function, returning a new iterator with items
    pub fn sort_by<T, I, F>(&self, iterator: I, cmp: F) -> Result<SortedIterator<T, F>, Error>
    where
        T: Sortable,
        I: Iterator<Item = T>,
        F: Fn(&T, &T) -> Ordering + Send + Sync,
    {
        let mut tempdir: Option<tempfile::TempDir> = None;
        let mut sort_dir: Option<PathBuf> = None;

        let mut segments_file: Vec<File> = Vec::new();
        let size_of_items = std::mem::size_of::<T>();
        let mut buffer: Vec<T> = Vec::with_capacity(self.segment_size / size_of_items);
        for next_item in iterator {
            buffer.push(next_item);
            if buffer.len() > self.segment_size {
                let sort_dir = self.lazy_create_dir(&mut tempdir, &mut sort_dir)?;
                self.sort_and_write_segment(sort_dir, &mut segments_file, &mut buffer, &cmp)?;
            }
        }

        // Write any items left in buffer, but only if we had at least 1 segment
        // written. Otherwise we use the buffer itself to iterate from memory
        let pass_through_queue = if !buffer.is_empty() && !segments_file.is_empty() {
            let sort_dir = self.lazy_create_dir(&mut tempdir, &mut sort_dir)?;
            self.sort_and_write_segment(sort_dir, &mut segments_file, &mut buffer, &cmp)?;
            None
        } else {
            buffer.sort_by(&cmp);
            Some(VecDeque::from(buffer))
        };

        SortedIterator::new(tempdir, pass_through_queue, segments_file, cmp)
    }

    /// We only want to create directory if it's needed (i.e. if the dataset
    /// doesn't fit in memory) to prevent filesystem latency
    fn lazy_create_dir<'a>(
        &self,
        tempdir: &mut Option<tempfile::TempDir>,
        sort_dir: &'a mut Option<PathBuf>,
    ) -> Result<&'a Path, Error> {
        if let Some(sort_dir) = sort_dir {
            return Ok(sort_dir);
        }

        *sort_dir = if let Some(ref sort_dir) = self.sort_dir {
            Some(sort_dir.to_path_buf())
        } else {
            *tempdir = Some(tempfile::TempDir::new()?);
            Some(tempdir.as_ref().unwrap().path().to_path_buf())
        };

        Ok(sort_dir.as_ref().unwrap())
    }

    fn sort_and_write_segment<T, F>(
        &self,
        sort_dir: &Path,
        segments: &mut Vec<File>,
        buffer: &mut Vec<T>,
        cmp: F,
    ) -> Result<(), Error>
    where
        T: Sortable,
        F: Fn(&T, &T) -> Ordering + Send + Sync,
    {
        if self.parallel {
            buffer.par_sort_by(|a, b| cmp(a, b));
        } else {
            buffer.sort_by(|a, b| cmp(a, b));
        }

        let segment_path = sort_dir.join(format!("{}", segments.len()));
        let segment_file = OpenOptions::new()
            .create(true)
            .truncate(true)
            .read(true)
            .write(true)
            .open(&segment_path)?;
        let mut buf_writer = BufWriter::new(segment_file);

        for item in buffer.drain(0..) {
            item.encode(&mut buf_writer);
        }

        let file = buf_writer.into_inner()?;
        segments.push(file);

        Ok(())
    }
}

impl Default for ExternalSorter {
    fn default() -> Self {
        ExternalSorter::new()
    }
}

pub trait Sortable: Sized + Send {
    fn encode<W: Write>(&self, writer: &mut W);
    fn decode<R: Read>(reader: &mut R) -> Option<Self>;
}

pub struct SortedIterator<T: Sortable, F> {
    _tempdir: Option<tempfile::TempDir>,
    pass_through_queue: Option<VecDeque<T>>,
    segments_file: Vec<BufReader<File>>,
    next_values: Vec<Option<T>>,
    cmp: F,
}

impl<T: Sortable, F: Fn(&T, &T) -> Ordering + Send + Sync> SortedIterator<T, F> {
    fn new(
        tempdir: Option<tempfile::TempDir>,
        pass_through_queue: Option<VecDeque<T>>,
        mut segments_file: Vec<File>,
        cmp: F,
    ) -> Result<SortedIterator<T, F>, Error> {
        for segment in &mut segments_file {
            segment.seek(SeekFrom::Start(0))?;
        }

        let next_values = segments_file
            .iter_mut()
            .map(|file| T::decode(file))
            .collect();

        let segments_file_buffered = segments_file.into_iter().map(BufReader::new).collect();

        Ok(SortedIterator {
            _tempdir: tempdir,
            pass_through_queue,
            segments_file: segments_file_buffered,
            next_values,
            cmp,
        })
    }
}

impl<T: Sortable, F: Fn(&T, &T) -> Ordering> Iterator for SortedIterator<T, F> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        // if we have a pass through, we dequeue from it directly
        if let Some(ptb) = self.pass_through_queue.as_mut() {
            return ptb.pop_front();
        }

        // otherwise, we iter from segments on disk
        let mut smallest_idx: Option<usize> = None;
        {
            let mut smallest: Option<&T> = None;
            for idx in 0..self.segments_file.len() {
                let next_value = self.next_values[idx].as_ref();
                if next_value.is_none() {
                    continue;
                }

                if smallest.is_none()
                    || (self.cmp)(next_value.unwrap(), smallest.unwrap()) == Ordering::Less
                {
                    smallest = Some(next_value.unwrap());
                    smallest_idx = Some(idx);
                }
            }
        }

        smallest_idx.map(|idx| {
            let file = &mut self.segments_file[idx];
            let value = self.next_values[idx].take().unwrap();
            self.next_values[idx] = T::decode(file);
            value
        })
    }
}
<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16, be_u32,
  IResult,
  ErrorKind,
};

use attribute_info::*;
use attribute_info::types::StackMapFrame::*;

pub fn attribute_parser(input: &[u8]) -> IResult<&[u8], AttributeInfo> {
    do_parse!(input,
        attribute_name_index: be_u16 >>
        attribute_length: be_u32 >>
        info: take!(attribute_length)>>
        (AttributeInfo {
            attribute_name_index: attribute_name_index,
            attribute_length: attribute_length,
            info: info.to_owned(),
        })
    )
}

pub fn exception_entry_parser(input: &[u8]) -> IResult<&[u8], ExceptionEntry> {
    do_parse!(input,
        start_pc: be_u16 >>
        end_pc: be_u16 >>
        handler_pc: be_u16 >>
        catch_type: be_u16>>
        (ExceptionEntry {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    )
}

pub fn code_attribute_parser(input: &[u8]) -> IResult<&[u8], CodeAttribute> {
    do_parse!(input,
        max_stack: be_u16 >>
        max_locals: be_u16 >>
        code_length: be_u32 >>
        code: take!(code_length) >>
        exception_table_length: be_u16 >>
        exception_table: count!(exception_entry_parser, exception_table_length as usize) >>
        attributes_count: be_u16 >>
        attributes: count!(attribute_parser, attributes_count as usize) >>
        (CodeAttribute {
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code.to_owned(),
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    )
}

fn same_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    value!(input, SameFrame { frame_type })
}

fn verification_type(v: &u8) -> Option<VerificationTypeInfo> {
    use self::VerificationTypeInfo::*;
    match *v {
        0 => Some(Top),
        1 => Some(Integer),
        2 => Some(Float),
        3 => Some(Double),
        4 => Some(Long),
        5 => Some(Null),
        6 => Some(UninitializedThis),
        7 => Some(Object),
        8 => Some(Uninitialized),
        _ => None,
    }
}

fn verification_type_parser(input: &[u8]) -> IResult<&[u8], VerificationTypeInfo> {
    do_parse!(input,
        v: be_u8 >>
        (verification_type(&v).unwrap()) // TODO rewrite .unwrap() call
    )
}

fn same_locals_1_stack_item_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        stack: verification_type_parser >>
        (SameLocals1StackItemFrame { frame_type, stack })
    )
}

fn same_locals_1_stack_item_frame_extended_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        stack: verification_type_parser >>
        (SameLocals1StackItemFrameExtended { frame_type, offset_delta, stack })
    )
}

fn chop_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        (ChopFrame { frame_type, offset_delta })
    )
}

fn same_frame_extended_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        (SameFrameExtended { frame_type, offset_delta })
    )
}

fn append_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        locals: count!(verification_type_parser, (frame_type - 251) as usize) >>
        (AppendFrame { frame_type, offset_delta, locals })
    )
}

fn full_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        number_of_locals: be_u16 >>
        locals: count!(verification_type_parser, number_of_locals as usize) >>
        number_of_stack_items: be_u16 >>
        stack: count!(verification_type_parser, number_of_stack_items as usize) >>
        (FullFrame {
            frame_type,
            offset_delta,
            number_of_locals,
            locals,
            number_of_stack_items,
            stack,
        })
    )
}

fn stack_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    match frame_type {
          0... 63 => same_frame_parser(input, frame_type),
         64...127 => same_locals_1_stack_item_frame_parser(input, frame_type),
        247       => same_locals_1_stack_item_frame_extended_parser(input, frame_type),
        248...250 => chop_frame_parser(input, frame_type),
        251       => same_frame_extended_parser(input, frame_type),
        252...254 => append_frame_parser(input, frame_type),
        255       => full_frame_parser(input, frame_type),
        _ => IResult::Error(error_position!(ErrorKind::Alt, input)),
    }
}

fn stack_map_frame_entry_parser(input: &[u8]) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        frame_type: be_u8 >>
        stack_frame: apply!(stack_frame_parser, frame_type) >>
        (stack_frame)
    )
}

pub fn stack_map_table_attribute_parser(input: &[u8]) -> IResult<&[u8], StackMapTableAttribute> {
    do_parse!(input,
        number_of_entries: be_u16 >>
        entries: count!(stack_map_frame_entry_parser, number_of_entries as usize) >>
        (StackMapTableAttribute {
            number_of_entries,
            entries,
        })
    )
}

pub fn exceptions_attribute_parser(input: &[u8]) -> IResult<&[u8], ExceptionsAttribute> {
    do_parse!(input,
        exception_table_length: be_u16 >>
        exception_table: count!(be_u16, exception_table_length as usize) >>
        (ExceptionsAttribute {
        exception_table_length: exception_table_length,
        exception_table: exception_table,
        })
    )
}

pub fn constant_value_attribute_parser(input: &[u8]) -> IResult<&[u8], ConstantValueAttribute> {
    do_parse!(input,
        constant_value_index: be_u16 >>
        (ConstantValueAttribute {
            constant_value_index: constant_value_index,
        })
    )
}
<commit_msg>Get rid of .unwrap() call<commit_after>use nom::{
  be_u8, be_u16, be_u32,
  IResult,
  ErrorKind,
};

use attribute_info::*;
use attribute_info::types::StackMapFrame::*;

pub fn attribute_parser(input: &[u8]) -> IResult<&[u8], AttributeInfo> {
    do_parse!(input,
        attribute_name_index: be_u16 >>
        attribute_length: be_u32 >>
        info: take!(attribute_length)>>
        (AttributeInfo {
            attribute_name_index: attribute_name_index,
            attribute_length: attribute_length,
            info: info.to_owned(),
        })
    )
}

pub fn exception_entry_parser(input: &[u8]) -> IResult<&[u8], ExceptionEntry> {
    do_parse!(input,
        start_pc: be_u16 >>
        end_pc: be_u16 >>
        handler_pc: be_u16 >>
        catch_type: be_u16>>
        (ExceptionEntry {
            start_pc: start_pc,
            end_pc: end_pc,
            handler_pc: handler_pc,
            catch_type: catch_type,
        })
    )
}

pub fn code_attribute_parser(input: &[u8]) -> IResult<&[u8], CodeAttribute> {
    do_parse!(input,
        max_stack: be_u16 >>
        max_locals: be_u16 >>
        code_length: be_u32 >>
        code: take!(code_length) >>
        exception_table_length: be_u16 >>
        exception_table: count!(exception_entry_parser, exception_table_length as usize) >>
        attributes_count: be_u16 >>
        attributes: count!(attribute_parser, attributes_count as usize) >>
        (CodeAttribute {
            max_stack: max_stack,
            max_locals: max_locals,
            code_length: code_length,
            code: code.to_owned(),
            exception_table_length: exception_table_length,
            exception_table: exception_table,
            attributes_count: attributes_count,
            attributes: attributes,
        })
    )
}

fn same_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    value!(input, SameFrame { frame_type })
}

fn verification_type(v: &u8) -> Option<VerificationTypeInfo> {
    use self::VerificationTypeInfo::*;
    match *v {
        0 => Some(Top),
        1 => Some(Integer),
        2 => Some(Float),
        3 => Some(Double),
        4 => Some(Long),
        5 => Some(Null),
        6 => Some(UninitializedThis),
        7 => Some(Object),
        8 => Some(Uninitialized),
        _ => None,
    }
}

fn verification_type_parser(input: &[u8]) -> IResult<&[u8], VerificationTypeInfo> {
    match verification_type(&input[0]) {
        Some(x) => IResult::Done(&input[1..], x),
        _ => IResult::Error(error_position!(ErrorKind::Alt, input)),
    }
}

fn same_locals_1_stack_item_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        stack: verification_type_parser >>
        (SameLocals1StackItemFrame { frame_type, stack })
    )
}

fn same_locals_1_stack_item_frame_extended_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        stack: verification_type_parser >>
        (SameLocals1StackItemFrameExtended { frame_type, offset_delta, stack })
    )
}

fn chop_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        (ChopFrame { frame_type, offset_delta })
    )
}

fn same_frame_extended_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        (SameFrameExtended { frame_type, offset_delta })
    )
}

fn append_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        locals: count!(verification_type_parser, (frame_type - 251) as usize) >>
        (AppendFrame { frame_type, offset_delta, locals })
    )
}

fn full_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        offset_delta: be_u16 >>
        number_of_locals: be_u16 >>
        locals: count!(verification_type_parser, number_of_locals as usize) >>
        number_of_stack_items: be_u16 >>
        stack: count!(verification_type_parser, number_of_stack_items as usize) >>
        (FullFrame {
            frame_type,
            offset_delta,
            number_of_locals,
            locals,
            number_of_stack_items,
            stack,
        })
    )
}

fn stack_frame_parser(input: &[u8], frame_type: u8) -> IResult<&[u8], StackMapFrame> {
    match frame_type {
          0... 63 => same_frame_parser(input, frame_type),
         64...127 => same_locals_1_stack_item_frame_parser(input, frame_type),
        247       => same_locals_1_stack_item_frame_extended_parser(input, frame_type),
        248...250 => chop_frame_parser(input, frame_type),
        251       => same_frame_extended_parser(input, frame_type),
        252...254 => append_frame_parser(input, frame_type),
        255       => full_frame_parser(input, frame_type),
        _ => IResult::Error(error_position!(ErrorKind::Alt, input)),
    }
}

fn stack_map_frame_entry_parser(input: &[u8]) -> IResult<&[u8], StackMapFrame> {
    do_parse!(input,
        frame_type: be_u8 >>
        stack_frame: apply!(stack_frame_parser, frame_type) >>
        (stack_frame)
    )
}

pub fn stack_map_table_attribute_parser(input: &[u8]) -> IResult<&[u8], StackMapTableAttribute> {
    do_parse!(input,
        number_of_entries: be_u16 >>
        entries: count!(stack_map_frame_entry_parser, number_of_entries as usize) >>
        (StackMapTableAttribute {
            number_of_entries,
            entries,
        })
    )
}

pub fn exceptions_attribute_parser(input: &[u8]) -> IResult<&[u8], ExceptionsAttribute> {
    do_parse!(input,
        exception_table_length: be_u16 >>
        exception_table: count!(be_u16, exception_table_length as usize) >>
        (ExceptionsAttribute {
        exception_table_length: exception_table_length,
        exception_table: exception_table,
        })
    )
}

pub fn constant_value_attribute_parser(input: &[u8]) -> IResult<&[u8], ConstantValueAttribute> {
    do_parse!(input,
        constant_value_index: be_u16 >>
        (ConstantValueAttribute {
            constant_value_index: constant_value_index,
        })
    )
}
<|endoftext|>


<commit_before><commit_msg>Update for language changes<commit_after><|endoftext|>


<commit_before>use std::path;

use support::{project, execs};
use support::{COMPILING, RUNNING};
use hamcrest::{assert_that};

fn setup() {
}

test!(custom_build_compiled {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("build.rs", r#"
        	invalid rust file, should trigger a build error
        "#);

    assert_that(p.cargo_process("build"),
                execs().with_status(101));
})

/*
test!(custom_build_script_failed {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("build.rs", r#"
            fn main() {
                std::os::set_exit_status(101);
            }
        "#);
    assert_that(p.cargo_process("build"),
                execs().with_status(101)
                       .with_stderr(format!("\
Failed to run custom build command for `foo v0.5.0 (file://{})`
Process didn't exit successfully: `{}` (status=101)",  // TODO: TEST FAILS BECAUSE OF WRONG PATH
p.root().display(), p.bin("build-script-build").display())));
})
*/

test!(custom_build_env_vars {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]

            [features]
            bar_feat = ["bar/foo"]

            [dependencies.bar]
            path = "bar"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("bar/Cargo.toml", r#"
            [project]

            name = "bar"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"

            [features]
            foo = []
        "#)
        .file("bar/src/lib.rs", r#"
            pub fn hello() {}
        "#);

    let file_content = format!(r#"
            use std::os;
            use std::io::fs::PathExtensions;
            fn main() {{
                let _target = os::getenv("TARGET").unwrap();

                let _ncpus = os::getenv("NUM_JOBS").unwrap();

                let out = os::getenv("CARGO_MANIFEST_DIR").unwrap();
                let p1 = Path::new(out);
                let p2 = os::make_absolute(&Path::new(file!()).dir_path().dir_path());
                assert!(p1 == p2, "{{}} != {{}}", p1.display(), p2.display());

                let opt = os::getenv("OPT_LEVEL").unwrap();
                assert_eq!(opt.as_slice(), "0");

                let opt = os::getenv("PROFILE").unwrap();
                assert_eq!(opt.as_slice(), "compile");

                let debug = os::getenv("DEBUG").unwrap();
                assert_eq!(debug.as_slice(), "true");

                let out = os::getenv("OUT_DIR").unwrap();
                assert!(out.as_slice().starts_with(r"{0}"));
                assert!(Path::new(out).is_dir());

                let _feat = os::getenv("CARGO_FEATURE_FOO").unwrap();
            }}
        "#,
        p.root().join("target").join("native").display());

    let p = p.file("bar/build.rs", file_content);

    assert_that(p.cargo_process("build").arg("--features").arg("bar_feat"),
                execs().with_status(0));
})

test!(custom_build_script_wrong_rustc_flags {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("build.rs", r#"
            fn main() {
                println!("cargo:rustc-flags=-aaa -bbb");
            }
        "#);

    assert_that(p.cargo_process("build"),
                execs().with_status(101)
                       .with_stderr(format!("\
Only `-l` and `-L` flags are allowed in build script of `foo v0.5.0 (file://{})`:
`-aaa -bbb
`",
p.root().display())));
})

/*
test!(custom_build_script_rustc_flags {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "bar"
            version = "0.5.0"
            authors = ["wycats@example.com"]

            [dependencies.foo]
            path = "foo"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("foo/Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("foo/src/lib.rs", r#"
        "#)
        .file("foo/build.rs", r#"
            fn main() {
                println!("cargo:rustc-flags=-l nonexistinglib -L /dummy/path1 -L /dummy/path2");
            }
        "#);

    // TODO: TEST FAILS BECAUSE OF WRONG STDOUT (but otherwise, the build works)
    assert_that(p.cargo_process("build").arg("--verbose"),
                execs().with_status(101)
                       .with_stdout(format!("\
{compiling} bar v0.5.0 ({url})
{running} `rustc {dir}{sep}src{sep}lib.rs --crate-name test --crate-type lib -g \
        -C metadata=[..] \
        -C extra-filename=-[..] \
        --out-dir {dir}{sep}target \
        --dep-info [..] \
        -L {dir}{sep}target \
        -L {dir}{sep}target{sep}deps`
",
running = RUNNING, compiling = COMPILING, sep = path::SEP,
dir = p.root().display(),
url = p.url(),
)));
})
*/
<commit_msg>Tweak tests that check whether the build script is being run<commit_after>use std::path;

use support::{project, execs};
use support::{COMPILING, RUNNING};
use hamcrest::{assert_that};

fn setup() {
}

test!(custom_build_script_failed {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("build.rs", r#"
            fn main() {
                std::os::set_exit_status(101);
            }
        "#);
    assert_that(p.cargo_process("build").arg("-v"),
                execs().with_status(101)
                       .with_stdout(format!("\
{compiling} foo v0.5.0 ({url})
{running} `rustc build.rs --crate-name build-script-build --crate-type bin [..]`
",
url = p.url(), compiling = COMPILING, running = RUNNING))
                       .with_stderr(format!("\
Failed to run custom build command for `foo v0.5.0 ({})`
Process didn't exit successfully: `[..]build[..]build-script-build` (status=101)",
p.url())));
})

test!(custom_build_env_vars {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]

            [features]
            bar_feat = ["bar/foo"]

            [dependencies.bar]
            path = "bar"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("bar/Cargo.toml", r#"
            [project]

            name = "bar"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"

            [features]
            foo = []
        "#)
        .file("bar/src/lib.rs", r#"
            pub fn hello() {}
        "#);

    let file_content = format!(r#"
            use std::os;
            use std::io::fs::PathExtensions;
            fn main() {{
                let _target = os::getenv("TARGET").unwrap();

                let _ncpus = os::getenv("NUM_JOBS").unwrap();

                let out = os::getenv("CARGO_MANIFEST_DIR").unwrap();
                let p1 = Path::new(out);
                let p2 = os::make_absolute(&Path::new(file!()).dir_path().dir_path());
                assert!(p1 == p2, "{{}} != {{}}", p1.display(), p2.display());

                let opt = os::getenv("OPT_LEVEL").unwrap();
                assert_eq!(opt.as_slice(), "0");

                let opt = os::getenv("PROFILE").unwrap();
                assert_eq!(opt.as_slice(), "compile");

                let debug = os::getenv("DEBUG").unwrap();
                assert_eq!(debug.as_slice(), "true");

                let out = os::getenv("OUT_DIR").unwrap();
                assert!(out.as_slice().starts_with(r"{0}"));
                assert!(Path::new(out).is_dir());

                let _feat = os::getenv("CARGO_FEATURE_FOO").unwrap();
            }}
        "#,
        p.root().join("target").join("native").display());

    let p = p.file("bar/build.rs", file_content);

    assert_that(p.cargo_process("build").arg("--features").arg("bar_feat"),
                execs().with_status(0));
})

test!(custom_build_script_wrong_rustc_flags {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("build.rs", r#"
            fn main() {
                println!("cargo:rustc-flags=-aaa -bbb");
            }
        "#);

    assert_that(p.cargo_process("build"),
                execs().with_status(101)
                       .with_stderr(format!("\
Only `-l` and `-L` flags are allowed in build script of `foo v0.5.0 ({})`:
`-aaa -bbb
`",
p.url())));
})

/*
test!(custom_build_script_rustc_flags {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]

            name = "bar"
            version = "0.5.0"
            authors = ["wycats@example.com"]

            [dependencies.foo]
            path = "foo"
        "#)
        .file("src/main.rs", r#"
            fn main() {}
        "#)
        .file("foo/Cargo.toml", r#"
            [project]

            name = "foo"
            version = "0.5.0"
            authors = ["wycats@example.com"]
            build = "build.rs"
        "#)
        .file("foo/src/lib.rs", r#"
        "#)
        .file("foo/build.rs", r#"
            fn main() {
                println!("cargo:rustc-flags=-l nonexistinglib -L /dummy/path1 -L /dummy/path2");
            }
        "#);

    // TODO: TEST FAILS BECAUSE OF WRONG STDOUT (but otherwise, the build works)
    assert_that(p.cargo_process("build").arg("--verbose"),
                execs().with_status(101)
                       .with_stdout(format!("\
{compiling} bar v0.5.0 ({url})
{running} `rustc {dir}{sep}src{sep}lib.rs --crate-name test --crate-type lib -g \
        -C metadata=[..] \
        -C extra-filename=-[..] \
        --out-dir {dir}{sep}target \
        --dep-info [..] \
        -L {dir}{sep}target \
        -L {dir}{sep}target{sep}deps`
",
running = RUNNING, compiling = COMPILING, sep = path::SEP,
dir = p.root().display(),
url = p.url(),
)));
})
*/
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Result};

#[derive(Clone, Copy, Debug)]
pub enum Orientation {
  Right = 0,
  UpRight = 1,
  Up = 2,
  UpLeft = 3,
  Left = 4,
  DownLeft = 5,
  Down = 6,
  DownRight = 7,
}

impl Display for Orientation {
  fn fmt(&self, f: &mut Formatter) -> Result {
    match *self {
      Right => write!(f, "0"),
      UpRight => write!(f, "1"),
      Up => write!(f, "2"),
      UpLeft => write!(f, "3"),
      Left => write!(f, "4"),
      DownLeft => write!(f, "5"),
      Down => write!(f, "6"),
      DownRight => write!(f, "7"),
    }
  }
}
<commit_msg>Fix Orientation Debug display<commit_after>use std::fmt::{Display, Formatter, Result};

#[derive(Clone, Copy, Debug)]
pub enum Orientation {
  Right = 0,
  UpRight = 1,
  Up = 2,
  UpLeft = 3,
  Left = 4,
  DownLeft = 5,
  Down = 6,
  DownRight = 7,
}

impl Display for Orientation {
  fn fmt(&self, f: &mut Formatter) -> Result {
    match *self {
      Orientation::Right => write!(f, "0"),
      Orientation::UpRight => write!(f, "1"),
      Orientation::Up => write!(f, "2"),
      Orientation::UpLeft => write!(f, "3"),
      Orientation::Left => write!(f, "4"),
      Orientation::DownLeft => write!(f, "5"),
      Orientation::Down => write!(f, "6"),
      Orientation::DownRight => write!(f, "7"),
    }
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,FlatMapper,Mapper,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
tag!(lsb       "[".as_bytes());
tag!(rsb       "]".as_bytes());
tag!(equal     "=".as_bytes());

take_until_and_leave!(category_bytes "]".as_bytes());
fn category_name(input: &[u8]) -> IResult<&[u8], &str> {
  category_bytes(input).map_res(str::from_utf8)
}

take_until!(not_equal      "=".as_bytes());
take_until_either_and_leave!(value_bytes "\n;".as_bytes());

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  value_bytes(input).map_res(str::from_utf8)
/*  for idx in 0..input.len() {
    if input[idx] == '\n' as u8 || input[idx] == ';' as u8 {
      return Done(&input[idx..], &input[0..idx]).map_res(str::from_utf8)
    }
  }
  Done("".as_bytes(), input).map_res(str::from_utf8)
*/
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

fn keys_and_values<'a,'b>(input: &'a[u8], mut z: HashMap<&'a str, &'a str>) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  fold0_impl!(<&[u8], HashMap<&str, &str> >, | mut h:HashMap<&'a str, &'a str>, (k, v)| {
    h.insert(k,v);
    h
  }, key_value, input, z);
}

fn keys_and_values_wrapper<'a,'b>(input:&'a[u8]) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(input, h);
  //println!("{:?}", res);
  res
}

o!(comment_body     <&[u8], &[u8]>       semicolon ~ [ not_line_ending]);
o!(comment          <&[u8], ()>          comment_body ~ line_ending ~ [ empty_result ]);
opt!(opt_comment    <&[u8], &[u8]>       comment_body);
o!(category         <&[u8], &str>        lsb ~ [ category_name ] ~ rsb ~ opt_multispace);
opt!(opt_multispace <&[u8], &[u8]>       multispace);
opt!(opt_space      <&[u8], &[u8]>       space);
o!(value            <&[u8],&str>         opt_space ~ equal ~ opt_space ~ [ value_parser ] ~ opt_space ~ opt_comment ~ opt_multispace);
chain!(key_value    <&[u8],(&str,&str)>, ||{(key, val)},
    key: parameter_parser,
    val: value,
);
chain!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,move ||{(category, keys)},
    category: category,
    keys: keys_and_values_wrapper,
);

fn categories<'a>(input: &'a[u8]) -> IResult<&'a[u8], HashMap<&'a str, HashMap<&'a str, &'a str> > > {
  let z: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  fold0_impl!(<&[u8], HashMap<&str, HashMap<&str, &str> > >, |mut h:HashMap<&'a str, HashMap<&'a str, &'a str> >, (k, v)| {
    h.insert(k,v);
    h
  }, category_and_keys, input, z);
}

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = comment(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_value_test() {
  let ini_file1 = "value
key =";
  let end = "
key =";

  let res = value_parser(ini_file1.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?})", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(end.as_bytes(),  "value"));

  let ini_file2 = "value;blah
key =";
  let end2 = ";blah
key =";

  let res2 = value_parser(ini_file2.as_bytes());
  println!("{:?}", res2);
  match res2 {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res2, Done(end2.as_bytes(),  "value"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(ini_file.as_bytes(), h);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, Done(ini_without_key_value.as_bytes(), expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, Done(ini_after_parser.as_bytes(), ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let ini_after_parser = "";

  let res = categories(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, Done(ini_after_parser.as_bytes(), expected_h));
}

<commit_msg>Move code around<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult,FlatMapper,Mapper,line_ending,not_line_ending, space, alphanumeric, multispace};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn empty_result(i:&[u8]) -> IResult<&[u8], ()> { Done(i,()) }
tag!(semicolon ";".as_bytes());
tag!(lsb       "[".as_bytes());
tag!(rsb       "]".as_bytes());
tag!(equal     "=".as_bytes());

take_until_and_leave!(category_bytes "]".as_bytes());
fn category_name(input: &[u8]) -> IResult<&[u8], &str> {
  category_bytes(input).map_res(str::from_utf8)
}

take_until!(not_equal      "=".as_bytes());
take_until_either_and_leave!(value_bytes "\n;".as_bytes());

fn value_parser(input:&[u8]) -> IResult<&[u8], &str> {
  value_bytes(input).map_res(str::from_utf8)
}

fn parameter_parser(input: &[u8]) -> IResult<&[u8], &str> {
  alphanumeric(input).map_res(str::from_utf8)
}

o!(comment_body     <&[u8], &[u8]>       semicolon ~ [ not_line_ending]);
o!(comment          <&[u8], ()>          comment_body ~ line_ending ~ [ empty_result ]);
opt!(opt_comment    <&[u8], &[u8]>       comment_body);
o!(category         <&[u8], &str>        lsb ~ [ category_name ] ~ rsb ~ opt_multispace);
opt!(opt_multispace <&[u8], &[u8]>       multispace);
opt!(opt_space      <&[u8], &[u8]>       space);
o!(value            <&[u8],&str>         opt_space ~ equal ~ opt_space ~ [ value_parser ] ~ opt_space ~ opt_comment ~ opt_multispace);
chain!(key_value    <&[u8],(&str,&str)>, ||{(key, val)},
    key: parameter_parser,
    val: value,
);

fn keys_and_values<'a,'b>(input: &'a[u8], mut z: HashMap<&'a str, &'a str>) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  fold0_impl!(<&[u8], HashMap<&str, &str> >, | mut h:HashMap<&'a str, &'a str>, (k, v)| {
    h.insert(k,v);
    h
  }, key_value, input, z);
}

fn keys_and_values_wrapper<'a,'b>(input:&'a[u8]) -> IResult<'b,&'a[u8], HashMap<&'a str, &'a str> > {
  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(input, h);
  //println!("{:?}", res);
  res
}

chain!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>,move ||{(category, keys)},
    category: category,
    keys: keys_and_values_wrapper,
);

fn categories<'a>(input: &'a[u8]) -> IResult<&'a[u8], HashMap<&'a str, HashMap<&'a str, &'a str> > > {
  let z: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  fold0_impl!(<&[u8], HashMap<&str, HashMap<&str, &str> > >, |mut h:HashMap<&'a str, HashMap<&'a str, &'a str> >, (k, v)| {
    h.insert(k,v);
    h
  }, category_and_keys, input, z);
}

#[test]
fn parse_comment_test() {
  let ini_file = ";comment
[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let ini_without_comment = "[category]
parameter=value
key = value2

[other]
number = 1234
str = a b cc dd ; comment";

  let res = comment(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_comment.as_bytes(), ()));
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_category.as_bytes(), "category"));
}

#[test]
fn parse_value_test() {
  let ini_file1 = "value
key =";
  let end = "
key =";

  let res = value_parser(ini_file1.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?})", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res, Done(end.as_bytes(),  "value"));

  let ini_file2 = "value;blah
key =";
  let end2 = ";blah
key =";

  let res2 = value_parser(ini_file2.as_bytes());
  println!("{:?}", res2);
  match res2 {
    IResult::Done(i, o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  assert_eq!(res2, Done(end2.as_bytes(),  "value"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, Done(ini_without_key_value.as_bytes(), ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let h: HashMap<&str, &str> = HashMap::new();
  let res = keys_and_values(ini_file.as_bytes(), h);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, Done(ini_without_key_value.as_bytes(), expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, Done(ini_after_parser.as_bytes(), ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let ini_after_parser = "";

  let res = categories(ini_file.as_bytes());
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, Done(ini_after_parser.as_bytes(), expected_h));
}

<|endoftext|>


<commit_before>extern crate timexif;

#[test]
fn do_the_thing() {
    let imgs = timexif::sequencer::get_images("tests/sample-imgs");
    assert_eq!(imgs.len(), 2);
}
<commit_msg>Tests on the actual content.<commit_after>extern crate chrono;

extern crate timexif;

use std::collections::HashMap;

use chrono::{NaiveDate, NaiveDateTime, NaiveTime};

/// There are four images, two of which have valid timestamps.
#[test]
fn correct_number_of_images() {
    let imgs = timexif::sequencer::get_images("tests/sample-imgs");
    assert_eq!(imgs.len(), 2);
}

#[test]
fn correct_timestamps() {
    let dt = |y, m, d, h, min, s|
    NaiveDateTime::new(NaiveDate::from_ymd(y, m, d), NaiveTime::from_hms(h, min, s));

    let mut expected = HashMap::new();

    expected.insert("tests/sample-imgs/large from dslr.JPG",
                    dt(2014, 7, 12, 11, 24, 56));
    expected.insert("tests/sample-imgs/phone photo.jpg",
                    dt(2016, 4, 16, 12, 27, 14));

    let imgs = timexif::sequencer::get_images("tests/sample-imgs");
    for img in imgs {
        let path = img.path.to_str().unwrap();
        assert!(expected.contains_key(path));
        let dt = expected.get(path).unwrap();
        assert_eq!(dt, &img.timestamp);
    }
}
<|endoftext|>