<commit_before>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    ~{
        topmod: ~{
            name: option::from_maybe(doc.topmod.name, attrs.name)
            with *doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let source = "#[link(name = \"bond\")];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_crate(fold, doc);
    assert doc.topmod.name == "bond";
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let srv = fold.ctxt;
    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_mod(ctxt.ast.node.attrs)
        }
    } else {
        astsrv::exec(srv) {|ctxt|
            let attrs = alt ctxt.map.get(doc.id) {
              ast_map::node_item(item) { item.attrs }
            };
            attr_parser::parse_mod(attrs)
        }
    };
    let doc = fold::default_seq_fold_mod(fold, doc);
    ret merge_mod_attrs(doc, attrs);

    fn merge_mod_attrs(
        doc: doc::moddoc,
        attrs: attr_parser::mod_attrs
    ) -> doc::moddoc {
        ~{
            brief: attrs.brief,
            desc: attrs.desc
            with *doc
        }
    }
}

#[test]
fn fold_mod_should_extract_mod_attributes() {
    let source = "#[doc = \"test\"] mod a { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod.mods[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_mod_should_extract_top_mod_attributes() {
    let source = "#[doc = \"test\"];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod);
    assert doc.desc == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.map.get(doc.id) {
          ast_map::node_item(item) { item.attrs }
        };
        attr_parser::parse_fn(attrs)
    };
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret ~{
            id: doc.id,
            name: doc.name,
            brief: attrs.brief,
            desc: attrs.desc,
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return)
        };
    }

    fn merge_arg_attrs(
        docs: [doc::argdoc],
        attrs: [attr_parser::arg_attrs]
    ) -> [doc::argdoc] {
        vec::map(docs) {|doc|
            alt vec::find(attrs) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    ~{
                        desc: some(attr.desc)
                        with *doc
                    }
                }
                none { doc }
            }
        }
        // FIXME: Warning when documenting a non-existent arg
    }

    fn merge_ret_attrs(
        doc: option<doc::retdoc>,
        _attrs: option<str>
    ) -> option<doc::retdoc> {
        // FIXME
        doc
    }
}

#[test]
fn fold_fn_should_extract_fn_attributes() {
    let source = "#[doc = \"test\"] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_fn_should_extract_arg_attributes() {
    let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.args[0].desc == some("b");
}<commit_msg>rustdoc: Attach return value descriptions to the doc tree<commit_after>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    ~{
        topmod: ~{
            name: option::from_maybe(doc.topmod.name, attrs.name)
            with *doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let source = "#[link(name = \"bond\")];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_crate(fold, doc);
    assert doc.topmod.name == "bond";
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let srv = fold.ctxt;
    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_mod(ctxt.ast.node.attrs)
        }
    } else {
        astsrv::exec(srv) {|ctxt|
            let attrs = alt ctxt.map.get(doc.id) {
              ast_map::node_item(item) { item.attrs }
            };
            attr_parser::parse_mod(attrs)
        }
    };
    let doc = fold::default_seq_fold_mod(fold, doc);
    ret merge_mod_attrs(doc, attrs);

    fn merge_mod_attrs(
        doc: doc::moddoc,
        attrs: attr_parser::mod_attrs
    ) -> doc::moddoc {
        ~{
            brief: attrs.brief,
            desc: attrs.desc
            with *doc
        }
    }
}

#[test]
fn fold_mod_should_extract_mod_attributes() {
    let source = "#[doc = \"test\"] mod a { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod.mods[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_mod_should_extract_top_mod_attributes() {
    let source = "#[doc = \"test\"];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod);
    assert doc.desc == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.map.get(doc.id) {
          ast_map::node_item(item) { item.attrs }
        };
        attr_parser::parse_fn(attrs)
    };
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret ~{
            id: doc.id,
            name: doc.name,
            brief: attrs.brief,
            desc: attrs.desc,
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return)
        };
    }

    fn merge_arg_attrs(
        docs: [doc::argdoc],
        attrs: [attr_parser::arg_attrs]
    ) -> [doc::argdoc] {
        vec::map(docs) {|doc|
            alt vec::find(attrs) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    ~{
                        desc: some(attr.desc)
                        with *doc
                    }
                }
                none { doc }
            }
        }
        // FIXME: Warning when documenting a non-existent arg
    }

    fn merge_ret_attrs(
        doc: option<doc::retdoc>,
        attrs: option<str>
    ) -> option<doc::retdoc> {
        alt doc {
          some(doc) {
            some({
                desc: attrs
                with doc
            })
          }
          none {
            // FIXME: Warning about documenting nil?
            none
          }
        }
    }
}

#[test]
fn fold_fn_should_extract_fn_attributes() {
    let source = "#[doc = \"test\"] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_fn_should_extract_arg_attributes() {
    let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.args[0].desc == some("b");
}

#[test]
fn fold_fn_should_extract_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert option::get(doc.return).desc == some("what");
}<|endoftext|>


<commit_before>//! Types to represent text to be displayed by widgets.
//!
//! This module is light on documentation. See the existing widget
//! implementations for inspiration.

use anyhow::{anyhow, Result};
use cairo::{Context, Surface};
use pango::{EllipsizeMode, FontDescription};
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub struct Color {
    red: f64,
    green: f64,
    blue: f64,
}

macro_rules! color {
    ($name:ident,($r:expr, $g:expr, $b:expr)) => {
        #[allow(dead_code)]
        pub fn $name() -> Color {
            Color {
                red: $r,
                green: $g,
                blue: $b,
            }
        }
    };
}

impl Color {
    color!(red, (1.0, 0.0, 0.0));
    color!(green, (0.0, 1.0, 0.0));
    color!(blue, (0.0, 0.0, 1.0));
    color!(white, (1.0, 1.0, 1.0));
    color!(black, (0.0, 0.0, 0.0));
    color!(yellow, (1.0, 1.0, 0.0));

    pub fn apply_to_context(&self, cr: &Context) {
        cr.set_source_rgb(self.red, self.green, self.blue);
    }

    pub fn to_hex(&self) -> String {
        let r = if self.red >= 1.0 {
            255
        } else {
            (self.red * 255.0) as i32
        };
        let g = if self.green >= 1.0 {
            255
        } else {
            (self.green * 255.0) as i32
        };
        let b = if self.blue >= 1.0 {
            255
        } else {
            (self.blue * 255.0) as i32
        };
        format!("#{:0width$X}{:0width$X}{:0width$X}", r, g, b, width = 2)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Padding {
    left: f64,
    right: f64,
    top: f64,
    bottom: f64,
}

impl Padding {
    pub fn new(left: f64, right: f64, top: f64, bottom: f64) -> Padding {
        Padding {
            left,
            right,
            top,
            bottom,
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct Font(FontDescription);

impl Font {
    pub fn new(name: &str) -> Font {
        Font(FontDescription::from_string(name))
    }
}

impl fmt::Debug for Font {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Attributes {
    pub font: Font,
    pub fg_color: Color,
    pub bg_color: Option<Color>,
    pub padding: Padding,
}

fn create_pango_layout(cairo_context: &cairo::Context) -> Result<pango::Layout> {
    let layout = pangocairo::functions::create_layout(cairo_context)
        .ok_or_else(|| anyhow!("Failed to create Pango layout"))?;
    Ok(layout)
}

fn show_pango_layout(cairo_context: &cairo::Context, layout: &pango::Layout) {
    pangocairo::functions::show_layout(cairo_context, layout);
}

#[derive(Clone, Debug, PartialEq)]
pub struct Text {
    pub attr: Attributes,
    pub text: String,
    pub stretch: bool,
    pub markup: bool,
}

impl Text {
    pub(crate) fn compute(self, surface: &Surface) -> Result<ComputedText> {
        let (width, height) = {
            let context = Context::new(&surface);
            let layout = create_pango_layout(&context)?;
            if self.markup {
                layout.set_markup(&self.text);
            } else {
                layout.set_text(&self.text);
            }
            layout.set_font_description(Some(&self.attr.font.0));

            let padding = &self.attr.padding;
            let (text_width, text_height) = layout.get_pixel_size();
            let width = f64::from(text_width) + padding.left + padding.right;
            let height = f64::from(text_height) + padding.top + padding.bottom;
            (width, height)
        };

        Ok(ComputedText {
            attr: self.attr,
            text: self.text,
            stretch: self.stretch,
            x: 0.0,
            y: 0.0,
            width,
            height,
            markup: self.markup,
        })
    }
}

// This impl allows us to see whether a widget's text has changed without
// having to call the (relatively) expensive .compute().
impl PartialEq<ComputedText> for Text {
    fn eq(&self, other: &ComputedText) -> bool {
        self.attr == other.attr && self.text == other.text && self.stretch == other.stretch
    }
}

#[derive(Clone, Debug, PartialEq)]
pub(crate) struct ComputedText {
    pub attr: Attributes,
    pub text: String,
    pub stretch: bool,

    pub x: f64,
    pub y: f64,
    pub width: f64,
    pub height: f64,
    pub markup: bool,
}

impl ComputedText {
    pub fn render(&self, surface: &Surface) -> Result<()> {
        let context = Context::new(&surface);
        let layout = create_pango_layout(&context)?;
        if self.markup {
            layout.set_markup(&self.text);
        } else {
            layout.set_text(&self.text);
        }
        layout.set_font_description(Some(&self.attr.font.0));

        context.translate(self.x, self.y);

        // Set the width/height on the Pango layout so that it word-wraps/ellipises.
        let padding = &self.attr.padding;
        let text_width = self.width - padding.left - padding.right;
        let text_height = self.height - padding.top - padding.bottom;
        layout.set_ellipsize(EllipsizeMode::End);
        layout.set_width(text_width as i32 * pango::SCALE);
        layout.set_height(text_height as i32 * pango::SCALE);

        let bg_color = &self.attr.bg_color.clone().unwrap_or_else(Color::black);
        bg_color.apply_to_context(&context);
        // FIXME: The use of `height` isnt' right here: we want to do the
        // full height of the bar, not the full height of the text. It
        // would be useful if we could do Surface.get_height(), but that
        // doesn't seem to be available in cairo-rs for some reason?
        context.rectangle(0.0, 0.0, self.width, self.height);
        context.fill();

        self.attr.fg_color.apply_to_context(&context);
        context.translate(padding.left, padding.top);
        show_pango_layout(&context, &layout);

        Ok(())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct ThresholdValue {
    pub threshold: u8,
    pub color: Color,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Threshold {
    pub low: ThresholdValue,
    pub normal: ThresholdValue,
    pub high: ThresholdValue,
}

impl Default for Threshold {
    fn default() -> Self {
        Threshold {
            low: ThresholdValue {
                threshold: 40,
                color: Color::red(),
            },
            normal: ThresholdValue {
                threshold: 60,
                color: Color::yellow(),
            },
            high: ThresholdValue {
                threshold: 100,
                color: Color::green(),
            },
        }
    }
}
<commit_msg>add color constructor from rgb values<commit_after>//! Types to represent text to be displayed by widgets.
//!
//! This module is light on documentation. See the existing widget
//! implementations for inspiration.

use anyhow::{anyhow, Result};
use cairo::{Context, Surface};
use pango::{EllipsizeMode, FontDescription};
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub struct Color {
    red: f64,
    green: f64,
    blue: f64,
}

macro_rules! color {
    ($name:ident,($r:expr, $g:expr, $b:expr)) => {
        #[allow(dead_code)]
        pub fn $name() -> Color {
            Color {
                red: $r,
                green: $g,
                blue: $b,
            }
        }
    };
}

impl Color {
    color!(red, (1.0, 0.0, 0.0));
    color!(green, (0.0, 1.0, 0.0));
    color!(blue, (0.0, 0.0, 1.0));
    color!(white, (1.0, 1.0, 1.0));
    color!(black, (0.0, 0.0, 0.0));
    color!(yellow, (1.0, 1.0, 0.0));

    pub fn apply_to_context(&self, cr: &Context) {
        cr.set_source_rgb(self.red, self.green, self.blue);
    }

    pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
        Self {
            red: r as f64 / 255.0,
            green: g as f64 / 255.0,
            blue: b as f64 / 255.0,
        }
    }

    pub fn to_hex(&self) -> String {
        let r = if self.red >= 1.0 {
            255
        } else {
            (self.red * 255.0) as i32
        };
        let g = if self.green >= 1.0 {
            255
        } else {
            (self.green * 255.0) as i32
        };
        let b = if self.blue >= 1.0 {
            255
        } else {
            (self.blue * 255.0) as i32
        };
        format!("#{:0width$X}{:0width$X}{:0width$X}", r, g, b, width = 2)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Padding {
    left: f64,
    right: f64,
    top: f64,
    bottom: f64,
}

impl Padding {
    pub fn new(left: f64, right: f64, top: f64, bottom: f64) -> Padding {
        Padding {
            left,
            right,
            top,
            bottom,
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct Font(FontDescription);

impl Font {
    pub fn new(name: &str) -> Font {
        Font(FontDescription::from_string(name))
    }
}

impl fmt::Debug for Font {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Attributes {
    pub font: Font,
    pub fg_color: Color,
    pub bg_color: Option<Color>,
    pub padding: Padding,
}

fn create_pango_layout(cairo_context: &cairo::Context) -> Result<pango::Layout> {
    let layout = pangocairo::functions::create_layout(cairo_context)
        .ok_or_else(|| anyhow!("Failed to create Pango layout"))?;
    Ok(layout)
}

fn show_pango_layout(cairo_context: &cairo::Context, layout: &pango::Layout) {
    pangocairo::functions::show_layout(cairo_context, layout);
}

#[derive(Clone, Debug, PartialEq)]
pub struct Text {
    pub attr: Attributes,
    pub text: String,
    pub stretch: bool,
    pub markup: bool,
}

impl Text {
    pub(crate) fn compute(self, surface: &Surface) -> Result<ComputedText> {
        let (width, height) = {
            let context = Context::new(&surface);
            let layout = create_pango_layout(&context)?;
            if self.markup {
                layout.set_markup(&self.text);
            } else {
                layout.set_text(&self.text);
            }
            layout.set_font_description(Some(&self.attr.font.0));

            let padding = &self.attr.padding;
            let (text_width, text_height) = layout.get_pixel_size();
            let width = f64::from(text_width) + padding.left + padding.right;
            let height = f64::from(text_height) + padding.top + padding.bottom;
            (width, height)
        };

        Ok(ComputedText {
            attr: self.attr,
            text: self.text,
            stretch: self.stretch,
            x: 0.0,
            y: 0.0,
            width,
            height,
            markup: self.markup,
        })
    }
}

// This impl allows us to see whether a widget's text has changed without
// having to call the (relatively) expensive .compute().
impl PartialEq<ComputedText> for Text {
    fn eq(&self, other: &ComputedText) -> bool {
        self.attr == other.attr && self.text == other.text && self.stretch == other.stretch
    }
}

#[derive(Clone, Debug, PartialEq)]
pub(crate) struct ComputedText {
    pub attr: Attributes,
    pub text: String,
    pub stretch: bool,

    pub x: f64,
    pub y: f64,
    pub width: f64,
    pub height: f64,
    pub markup: bool,
}

impl ComputedText {
    pub fn render(&self, surface: &Surface) -> Result<()> {
        let context = Context::new(&surface);
        let layout = create_pango_layout(&context)?;
        if self.markup {
            layout.set_markup(&self.text);
        } else {
            layout.set_text(&self.text);
        }
        layout.set_font_description(Some(&self.attr.font.0));

        context.translate(self.x, self.y);

        // Set the width/height on the Pango layout so that it word-wraps/ellipises.
        let padding = &self.attr.padding;
        let text_width = self.width - padding.left - padding.right;
        let text_height = self.height - padding.top - padding.bottom;
        layout.set_ellipsize(EllipsizeMode::End);
        layout.set_width(text_width as i32 * pango::SCALE);
        layout.set_height(text_height as i32 * pango::SCALE);

        let bg_color = &self.attr.bg_color.clone().unwrap_or_else(Color::black);
        bg_color.apply_to_context(&context);
        // FIXME: The use of `height` isnt' right here: we want to do the
        // full height of the bar, not the full height of the text. It
        // would be useful if we could do Surface.get_height(), but that
        // doesn't seem to be available in cairo-rs for some reason?
        context.rectangle(0.0, 0.0, self.width, self.height);
        context.fill();

        self.attr.fg_color.apply_to_context(&context);
        context.translate(padding.left, padding.top);
        show_pango_layout(&context, &layout);

        Ok(())
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct ThresholdValue {
    pub threshold: u8,
    pub color: Color,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Threshold {
    pub low: ThresholdValue,
    pub normal: ThresholdValue,
    pub high: ThresholdValue,
}

impl Default for Threshold {
    fn default() -> Self {
        Threshold {
            low: ThresholdValue {
                threshold: 40,
                color: Color::red(),
            },
            normal: ThresholdValue {
                threshold: 60,
                color: Color::yellow(),
            },
            high: ThresholdValue {
                threshold: 100,
                color: Color::green(),
            },
        }
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;

use std::path::Path;
use std::str::from_utf8_unchecked;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {super::filename (path)}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
pub fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}

/// Wraps `gethostname` to fetch the current hostname into a temporary buffer.
#[cfg(unix)]
pub fn with_hostname (visitor: &mut FnMut (&[u8])) -> Result<(), std::io::Error> {
  use libc::{size_t, gethostname};  // http://man7.org/linux/man-pages/man2/gethostname.2.html
  use std::ffi::CStr;
  use std::io;

  let mut buf = [0; 128];
  let rc = unsafe {gethostname (buf.as_mut_ptr(), (buf.len() - 1) as size_t)};
  if rc == 0 {
    let cs = unsafe {CStr::from_ptr (buf.as_ptr())};
    Ok (visitor (cs.to_bytes()))
  } else {
    Err (io::Error::last_os_error())}}

#[cfg(unix)] #[test]
fn test_hostname() {
  let mut hostname = String::new();
  with_hostname (&mut |bytes| hostname = String::from_utf8_lossy (bytes) .into_owned()) .unwrap();}
<commit_msg>+slurp<commit_after>#![feature(libc)]
extern crate libc;

use std::path::Path;
use std::str::from_utf8_unchecked;

/// Shortcut to path->filename conversion.
///
/// Returns the unchanged `path` if there is a character encoding error or something.
pub fn filename<'a> (path: &'a str) -> &'a str {
  match Path::new (path) .file_name() {
    Some (filename) => match filename.to_str() {
      Some (fstr) => if fstr.ends_with (".rs") {&fstr[0 .. fstr.len() - 3]} else {fstr},
      None => path},
    None => path}}

mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {super::filename (path)}}

// A trick to use the `try_s` macro from both the outside and inside of the crate.
//mod gstuff {pub fn filename<'a> (path: &'a str) -> &'a str {::filename (path)}}

/// Returns on error, converting the `Err` value to `String` and prepending the current location.
///
/// cf. http://www.reddit.com/r/rust/comments/29wwzw/error_handling_and_result_types/cipcm9a
#[macro_export] macro_rules! try_s {
  ($e: expr) => {match $e {Ok (ok) => ok, Err (err) => {return Err (format! ("{}:{}] {}", ::gstuff::filename (file!()), line!(), err));}}}}

// Like `try_s`, but takes a reference.
#[macro_export] macro_rules! try_sp {
  ($e: expr) => {match $e {&Ok (ref ok) => ok,
    &Err (ref err) => {return Err (format! ("{}:{}] {:?}", ::gstuff::filename (file!()), line!(), err));}}}}

/// Returns a `Err(String)`, prepending the current location (file name and line number) to the string.
///
/// Examples: `ERR! ("too bad")`; `ERR! ("{}", foo)`;
#[macro_export] macro_rules! ERR {
  ($format: expr, $($args: tt)+) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!(), $($args)+))};
  ($format: expr) => {Err (format! (concat! ("{}:{}] ", $format), ::gstuff::filename (file!()), line!()))}}

/// A helper to build a string on the stack.
///
/// Given an array it makes a writeable cursor available to the passed code block.
///
/// Returns a &str slice pointing at memory between the array start and the cursor.
///
/// Example:
///
///     use std::io::Write;
///     let mut foobar: [u8; 128] = unsafe {std::mem::uninitialized()};
///     let foobar = gstring! (foobar, {
///         write! (foobar, "foo") .expect ("!write");
///         write! (foobar, "bar") .expect ("!write");
///     });
///
/// Alternatives: https://crates.io/crates/stack.
#[macro_export] macro_rules! gstring {($array: ident, $code: block) => {{
  let end = {
    let mut $array = ::std::io::Cursor::new (&mut $array[..]);
    let $array = &mut $array;
    $code;
    $array.position() as usize};
  unsafe {::std::str::from_utf8_unchecked (&$array[0..end])}}}}

/// Takes a netstring from the front of the slice.
///
/// Returns the unpacked netstring and the remainder of the slice.
pub fn netstring (at: &[u8]) -> Result<(&[u8], &[u8]), String> {
  let length_end = match at.iter().position (|&ch| ch < b'0' || ch > b'9') {Some (l) if l > 0 => l, _ => return ERR! ("No len.")};
  match at.get (length_end) {Some (&ch) if ch == b':' => (), _ => return ERR! ("No colon.")};
  let length = unsafe {from_utf8_unchecked (&at[0 .. length_end])};
  let length: usize = try_s! (length.parse());
  let bulk_pos = 0 + length_end + 1;
  let bulk_end = bulk_pos + length;
  match at.get (bulk_end) {Some (&ch) if ch == b',' => (), _ => return ERR! ("No comma.")}
  Ok ((&at[bulk_pos .. bulk_end], &at[bulk_end + 1 ..]))}

/// Wraps `gethostname` to fetch the current hostname into a temporary buffer.
#[cfg(unix)]
pub fn with_hostname (visitor: &mut FnMut (&[u8])) -> Result<(), std::io::Error> {
  use libc::{size_t, gethostname};  // http://man7.org/linux/man-pages/man2/gethostname.2.html
  use std::ffi::CStr;
  use std::io;

  let mut buf = [0; 128];
  let rc = unsafe {gethostname (buf.as_mut_ptr(), (buf.len() - 1) as size_t)};
  if rc == 0 {
    let cs = unsafe {CStr::from_ptr (buf.as_ptr())};
    Ok (visitor (cs.to_bytes()))
  } else {
    Err (io::Error::last_os_error())}}

#[cfg(unix)] #[test]
fn test_hostname() {
  let mut hostname = String::new();
  with_hostname (&mut |bytes| hostname = String::from_utf8_lossy (bytes) .into_owned()) .unwrap();}

/// Read contents of the file into a String.
fn slurp (path: &AsRef<Path>) -> String {
  let mut file = match fs::File::open (path) {
    Ok (f) => f,
    Err (ref err) if err.kind() == std::io::ErrorKind::NotFound => return String::new(),
    Err (err) => panic! ("Can't open {:?}: {}", path.as_ref(), err)};
  let mut buf = String::new();
  file.read_to_string (&mut buf) .expect ("!read");
  buf}
<|endoftext|>


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

// Algebraic Data Type (ADT) `GridVariant` use case using Rust `enum`
// should be more robust than `std::Any`

#![feature(plugin)]
#![plugin(docopt_macros)]
#![feature(custom_derive)]
#![plugin(indoc)]

extern crate rustc_serialize;
extern crate docopt;
extern crate num;

use docopt::Docopt;
use std::io;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::io::Cursor;
use std::mem;
use std::iter::FromIterator;

extern crate endianness;
use endianness::{ByteOrder, read_u32, read_f32, read_f64};
use num::Num;

use std::fmt::Debug;

type c32 = num::Complex<f32>;
type c64 = num::Complex<f64>;

struct Grid<T> {
    points: Vec<Vec<T>>,
}

#[derive(Debug)]
enum GridType {
    F32T,
    F64T,
    C32T,
    C64T,
}

enum GridVariant {
    GridF32(Box<Grid<f32>>),
    GridF64(Box<Grid<f64>>),
    GridC32(Box<Grid<c32>>),
    GridC64(Box<Grid<c64>>),
}

trait GridTrait<T> {
    // a constructor
    fn new() -> Grid<T> {
        Grid { points: Vec::new() }
    }

    // unformatted read from the buffer
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &Vec<u8>);
}

impl GridTrait<f32> for Grid<f32> {
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f32>();
                let val = read_f32(&grid_buf[start..], byte_order);
                val.unwrap()
            }))
        }));
    }
}

impl GridTrait<c32> for Grid<c32> {
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f32>();
                let start_2 = start_1 + mem::size_of::<f32>(); // next f32 number
                let (real, imag) = (read_f32(&grid_buf[start_1..], byte_order),
                                    read_f32(&grid_buf[start_2..], byte_order));
                c32::new(real.unwrap(), imag.unwrap())
            }))
        }));
    }
}

impl GridTrait<f64> for Grid<f64> {
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f64>();
                let val = read_f64(&grid_buf[start..], byte_order);
                val.unwrap()
            }))
        }));
    }
}

// the Docopt usage string.
// https://github.com/docopt/docopt.rs
docopt!(Args derive Debug, "
Read grid gen.

Usage:
  gridgen read <file> [--verbose] [-d <dpath>] [-o <asy-file-name>]

Options:
  -h --help       Show this screen.
  -d --data-path  path to input data.
  -o --out-asy    name of output asy file.
  --verbose       Be verbose.

");

fn read_from_file(namein: &String,
                  data_path: &String,
                  verbose: bool)
                  -> Result<(ByteOrder, GridType, u32, u32, Vec<u8>), io::Error> {
    // let name = format!("{}/{}.bin", data_path, namein);
    let name = format!("{}/{}", data_path, namein);
    let mut try_open = File::open(name.clone());
    let mut file = match try_open {
        Ok(f) => f,
        Err(err) => panic!("\"{}\" : {}\n", name, err),
    };
    let mut buf = [0u8; 4];
    if verbose {
        println!("read from file: {}", name);
    }
    try!(file.read(&mut buf[0..1]));
    let is_big_endian = unsafe { mem::transmute::<[u8; 1], u8>([buf[0]]) } == 1;
    let byte_order = if is_big_endian {
        ByteOrder::BigEndian
    } else {
        ByteOrder::LittleEndian
    };

    try!(file.read(&mut buf[..]));
    let prec = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let typ = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let xe = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let ye = read_u32(&buf[..], byte_order).unwrap();

    if verbose {
        println!("prec: {} (1 - Single Precision, 2 - Double Precision) typ: {} (1 - Real \
                  Values, 2 - Complex Values) xe: {} ye: {}",
                 prec,
                 typ,
                 xe,
                 ye);
    }

    let (grid_type, grid_elem_size) = match (prec, typ) {
        (1, 1) => (GridType::F32T, mem::size_of::<f32>()),
        (1, 2) => (GridType::C32T, mem::size_of::<c32>()),
        (2, 1) => (GridType::F64T, mem::size_of::<f64>()),
        (2, 2) => (GridType::C64T, mem::size_of::<c64>()),
        (_, _) => panic!("illegal combination of prec: {} typ: {}", prec, typ),
    };
    let grid_sz = (xe * ye) as usize;
    let mut grid_buf = Vec::new();
    let sz = file.read_to_end(&mut grid_buf).unwrap();
    if sz != (grid_sz * grid_elem_size) {
        panic!("corrupted grid sz: {} xe*ye: {}", sz, xe * ye);
    }

    Ok((byte_order, grid_type, xe, ye, grid_buf))
}

fn read_grid(namein: &str, dpath: &String, verbose: bool) -> GridVariant {
    let (byte_order, grid_type, xe, ye, grid_buf) =
        read_from_file(&namein.to_string(), &dpath, verbose).unwrap();
    let mask_grid = match grid_type {
        GridType::F32T => {
            let mut f32_grid = Box::new(Grid::<f32>::new());
            (*f32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
            GridVariant::GridF32(f32_grid)
        }
        GridType::C32T => {
            let mut c32_grid = Box::new(Grid::<c32>::new());
            (*c32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
            GridVariant::GridC32(c32_grid)
        }
        _ => panic!("not yet implemented for grid type: {:?}", grid_type),
    };
    mask_grid
}

fn dump_grid<T: std::fmt::Display>(grid_name: &str, grid: &Grid<T>) {
    println!("-I- dumping grid: {}", grid_name);
    let points = &grid.points;
    for i in 0..points.len() {
        let row = &points[i];
        for j in 0..row.len() {
            let p = &points[i][j]; // as c64;
            println!("{} [{}][{}] = {:}",
                     grid_name,
                     i,
                     j,
                     p /* .to_string() */);
        }
    }
}

fn count_nnz<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = 0;
    for i in 0..points.len() {
        let row = &points[i];
        for j in 0..row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                nnz += 1;
            }
        }
    }
    (nnz, points.len() * points[0].len())
}

fn count_nnz_functional_way<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = points.iter().fold(0, |sum, row| {
        let incr = {
            row.iter().fold(0, |c, v| if v.is_zero() { c } else { c + 1 })
        };
        sum + incr
    });
    (nnz, points.len() * points[0].len())
}

// bounding box indices for the grid
fn grid_bb_indices<T: Num>(grid: &Grid<T>) -> ((isize, isize), (isize, isize)) {
    let points = &grid.points;
    let ((mut llx, mut lly), (mut urx, mut ury)) = ((std::isize::MAX, std::isize::MAX),
                                                    (std::isize::MIN, std::isize::MIN));
    for i in 0..points.len() {
        let row = &points[i];
        for j in 0..row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                let ii = i as isize;
                let jj = j as isize;
                if llx > ii {
                    llx = ii;
                }
                if lly > jj {
                    lly = jj;
                }
                if urx < ii {
                    urx = ii;
                }
                if ury < jj {
                    ury = jj;
                }
            }
        }
    }

    ((llx, lly), (urx, ury))
}

fn write_asy<T: Num + std::fmt::Display>(fname: &str,
                                         bounding_box: ((usize, usize), (usize, usize)),
                                         grid: &Grid<T>)
                                         -> Result<(), io::Error> {
    const DELTA: usize = 10;
    let ((llx, lly), (urx, ury)) = bounding_box;
    let mut f = try!(File::create(fname));
    try!(write!(f,
                "size({},{});\n",
                (urx - llx) * DELTA,
                (ury - lly) * DELTA));
    try!(f.write(indoc!("
                 void draw_grid_cell(pair lb, pair ru, pen p = defaultpen())
                 {
                   path r = lb -- (ru.x, lb.y) -- ru -- (lb.x, ru.y) -- cycle;
                   filldraw(r, p);
                 }\n\n")
        .as_bytes()));

    let points = &grid.points;
    for i in llx..urx {
        for j in lly..ury {
            let p = &points[i][j];
            if !p.is_zero() {
                let lb = (i * DELTA, j * DELTA);
                let ru = ((i + 1) * DELTA, (j + 1) * DELTA);
                try!(write!(f, "draw_grid_cell({:?}, {:?}, gray*{});\n", lb, ru, p));
            }
        }
    }

    Ok(())
}

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    if args.flag_verbose {
        println!("{:?}", args);
        println!("input file name: {:?}", args.arg_file);
    }

    let fname = args.arg_file;
    let dpath = args.arg_dpath;
    let asy_fname = if args.arg_asy_file_name != "" {
        args.arg_asy_file_name
    } else {
        format!("{}.asy", fname)
    };
    let (byte_order, grid_type, xe, ye, grid_buf) =
        read_from_file(&fname, &dpath, args.flag_verbose).unwrap();

    let mask_grid = read_grid(&fname.clone(), &dpath.clone(), args.flag_verbose);

    match mask_grid {
        GridVariant::GridF32(agrid) => //dump_grid("f32_grid", &*agrid),
        {
          let (nnz, total) = count_nnz_functional_way(&*agrid);
          println!("nnz for f32 grid: {:} total: {:} ratio: {:.3}%",
                    nnz, total, (nnz as f64 / total as f64)* 100.0);
          let bb = grid_bb_indices(&*agrid);
          let ((llx,lly), (urx,ury)) = bb;
          let (x_extent, y_extent) = (urx-llx, ury-lly);
          println!("a bounding box indices for the grid mask: {:?} x_extent: {:} y_extent: {:}",
                   bb, x_extent, y_extent);
          let halo = 10;
          //write_asy(&asy_fname,
          //          ( ((llx - halo) as usize, (lly - halo) as usize),
          //            ((urx + halo) as usize, (ury + halo) as usize) ),
          //          &*agrid);
          write_asy(&asy_fname,
                    ( ( (llx - halo)         as usize, (lly - halo)         as usize),
                      ( (llx + x_extent / 8) as usize, (lly + y_extent / 8) as usize) ),
                    &*agrid);
        }

        GridVariant::GridC32(agrid) => dump_grid("c32_grid", &*agrid),
        _ => panic!("not yet implemented")
    }

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

// Algebraic Data Type (ADT) `GridVariant` use case using Rust `enum`
// should be more robust than `std::Any`

#![feature(plugin)]
#![plugin(docopt_macros)]
#![feature(custom_derive)]
#![plugin(indoc)]

extern crate rustc_serialize;
extern crate docopt;
extern crate num;

use docopt::Docopt;
use std::io;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::io::Cursor;
use std::mem;
use std::iter::FromIterator;

extern crate endianness;
use endianness::{ByteOrder, read_u32, read_f32, read_f64};
use num::Num;

use std::fmt::Debug;

type c32 = num::Complex<f32>;
type c64 = num::Complex<f64>;

struct Grid<T> {
    points: Vec<Vec<T>>,
}

#[derive(Debug)]
enum GridType {
    F32T,
    F64T,
    C32T,
    C64T,
}

enum GridVariant {
    GridF32(Box<Grid<f32>>),
    GridF64(Box<Grid<f64>>),
    GridC32(Box<Grid<c32>>),
    GridC64(Box<Grid<c64>>),
}

trait GridTrait<T> {
    // a constructor
    fn new() -> Grid<T> {
        Grid { points: Vec::new() }
    }

    // unformatted read from the buffer
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &[u8]);
}

impl GridTrait<f32> for Grid<f32> {
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &[u8]) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f32>();
                let val = read_f32(&grid_buf[start..], byte_order);
                val.unwrap()
            }))
        }));
    }
}

impl GridTrait<c32> for Grid<c32> {
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &[u8]) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f32>();
                let start_2 = start_1 + mem::size_of::<f32>(); // next f32 number
                let (real, imag) = (read_f32(&grid_buf[start_1..], byte_order),
                                    read_f32(&grid_buf[start_2..], byte_order));
                c32::new(real.unwrap(), imag.unwrap())
            }))
        }));
    }
}

impl GridTrait<f64> for Grid<f64> {
    fn read(&mut self, byte_order: ByteOrder, xsize: usize, ysize: usize, grid_buf: &[u8]) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f64>();
                let val = read_f64(&grid_buf[start..], byte_order);
                val.unwrap()
            }))
        }));
    }
}

// the Docopt usage string.
// https://github.com/docopt/docopt.rs
docopt!(Args derive Debug, "
Read grid gen.

Usage:
  gridgen read <file> [--verbose] [-d <dpath>] [-o <asy-file-name>]

Options:
  -h --help       Show this screen.
  -d --data-path  path to input data.
  -o --out-asy    name of output asy file.
  --verbose       Be verbose.

");

fn read_from_file(namein: &String,
                  data_path: &str,
                  verbose: bool)
                  -> Result<(ByteOrder, GridType, u32, u32, Vec<u8>), io::Error> {
    // let name = format!("{}/{}.bin", data_path, namein);
    let name = format!("{}/{}", data_path, namein);
    let mut try_open = File::open(name.clone());
    let mut file = match try_open {
        Ok(f) => f,
        Err(err) => panic!("\"{}\" : {}\n", name, err),
    };
    let mut buf = [0u8; 4];
    if verbose {
        println!("read from file: {}", name);
    }
    try!(file.read(&mut buf[0..1]));
    let is_big_endian = unsafe { mem::transmute::<[u8; 1], u8>([buf[0]]) } == 1;
    let byte_order = if is_big_endian {
        ByteOrder::BigEndian
    } else {
        ByteOrder::LittleEndian
    };

    try!(file.read(&mut buf[..]));
    let prec = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let typ = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let xe = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let ye = read_u32(&buf[..], byte_order).unwrap();

    if verbose {
        println!("prec: {} (1 - Single Precision, 2 - Double Precision) typ: {} (1 - Real \
                  Values, 2 - Complex Values) xe: {} ye: {}",
                 prec,
                 typ,
                 xe,
                 ye);
    }

    let (grid_type, grid_elem_size) = match (prec, typ) {
        (1, 1) => (GridType::F32T, mem::size_of::<f32>()),
        (1, 2) => (GridType::C32T, mem::size_of::<c32>()),
        (2, 1) => (GridType::F64T, mem::size_of::<f64>()),
        (2, 2) => (GridType::C64T, mem::size_of::<c64>()),
        (_, _) => panic!("illegal combination of prec: {} typ: {}", prec, typ),
    };
    let grid_sz = (xe * ye) as usize;
    let mut grid_buf = Vec::new();
    let sz = file.read_to_end(&mut grid_buf).unwrap();
    if sz != (grid_sz * grid_elem_size) {
        panic!("corrupted grid sz: {} xe*ye: {}", sz, xe * ye);
    }

    Ok((byte_order, grid_type, xe, ye, grid_buf))
}

fn read_grid(namein: &str, dpath: &str, verbose: bool) -> GridVariant {
    let (byte_order, grid_type, xe, ye, grid_buf) =
        read_from_file(&namein.to_string(), &dpath, verbose).unwrap();
    let mask_grid = match grid_type {
        GridType::F32T => {
            let mut f32_grid = Box::new(Grid::<f32>::new());
            (*f32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
            GridVariant::GridF32(f32_grid)
        }
        GridType::C32T => {
            let mut c32_grid = Box::new(Grid::<c32>::new());
            (*c32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
            GridVariant::GridC32(c32_grid)
        }
        _ => panic!("not yet implemented for grid type: {:?}", grid_type),
    };
    mask_grid
}

fn dump_grid<T: std::fmt::Display>(grid_name: &str, grid: &Grid<T>) {
    println!("-I- dumping grid: {}", grid_name);
    let points = &grid.points;
    for i in 0..points.len() {
        let row = &points[i];
        for j in 0..row.len() {
            let p = &points[i][j]; // as c64;
            println!("{} [{}][{}] = {:}",
                     grid_name,
                     i,
                     j,
                     p /* .to_string() */);
        }
    }
}

fn count_nnz<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = 0;
    for i in 0..points.len() {
        let row = &points[i];
        for j in 0..row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                nnz += 1;
            }
        }
    }
    (nnz, points.len() * points[0].len())
}

fn count_nnz_functional_way<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = points.iter().fold(0, |sum, row| {
        let incr = {
            row.iter().fold(0, |c, v| if v.is_zero() { c } else { c + 1 })
        };
        sum + incr
    });
    (nnz, points.len() * points[0].len())
}

// bounding box indices for the grid
fn grid_bb_indices<T: Num>(grid: &Grid<T>) -> ((isize, isize), (isize, isize)) {
    let points = &grid.points;
    let ((mut llx, mut lly), (mut urx, mut ury)) = ((std::isize::MAX, std::isize::MAX),
                                                    (std::isize::MIN, std::isize::MIN));
    for i in 0..points.len() {
        let row = &points[i];
        for j in 0..row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                let ii = i as isize;
                let jj = j as isize;
                if llx > ii {
                    llx = ii;
                }
                if lly > jj {
                    lly = jj;
                }
                if urx < ii {
                    urx = ii;
                }
                if ury < jj {
                    ury = jj;
                }
            }
        }
    }

    ((llx, lly), (urx, ury))
}

fn write_asy<T: Num + std::fmt::Display>(fname: &str,
                                         bounding_box: ((usize, usize), (usize, usize)),
                                         grid: &Grid<T>)
                                         -> Result<(), io::Error> {
    const DELTA: usize = 10;
    let ((llx, lly), (urx, ury)) = bounding_box;
    let mut f = try!(File::create(fname));
    try!(write!(f,
                "size({},{});\n",
                (urx - llx) * DELTA,
                (ury - lly) * DELTA));
    try!(f.write(indoc!("
                 void draw_grid_cell(pair lb, pair ru, pen p = defaultpen())
                 {
                   path r = lb -- (ru.x, lb.y) -- ru -- (lb.x, ru.y) -- cycle;
                   filldraw(r, p);
                 }\n\n")
        .as_bytes()));

    let points = &grid.points;
    for i in llx..urx {
        for j in lly..ury {
            let p = &points[i][j];
            if !p.is_zero() {
                let lb = (i * DELTA, j * DELTA);
                let ru = ((i + 1) * DELTA, (j + 1) * DELTA);
                try!(write!(f, "draw_grid_cell({:?}, {:?}, gray*{});\n", lb, ru, p));
            }
        }
    }

    Ok(())
}

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    if args.flag_verbose {
        println!("{:?}", args);
        println!("input file name: {:?}", args.arg_file);
    }

    let fname = args.arg_file;
    let dpath = args.arg_dpath;
    let asy_fname = if args.arg_asy_file_name != "" {
        args.arg_asy_file_name
    } else {
        format!("{}.asy", fname)
    };
    let (byte_order, grid_type, xe, ye, grid_buf) =
        read_from_file(&fname, &dpath, args.flag_verbose).unwrap();

    let mask_grid = read_grid(&fname.clone(), &dpath.clone(), args.flag_verbose);

    match mask_grid {
        GridVariant::GridF32(agrid) => //dump_grid("f32_grid", &*agrid),
        {
          let (nnz, total) = count_nnz_functional_way(&*agrid);
          println!("nnz for f32 grid: {:} total: {:} ratio: {:.3}%",
                    nnz, total, (nnz as f64 / total as f64)* 100.0);
          let bb = grid_bb_indices(&*agrid);
          let ((llx,lly), (urx,ury)) = bb;
          let (x_extent, y_extent) = (urx-llx, ury-lly);
          println!("a bounding box indices for the grid mask: {:?} x_extent: {:} y_extent: {:}",
                   bb, x_extent, y_extent);
          let halo = 10;
          //write_asy(&asy_fname,
          //          ( ((llx - halo) as usize, (lly - halo) as usize),
          //            ((urx + halo) as usize, (ury + halo) as usize) ),
          //          &*agrid);
          write_asy(&asy_fname,
                    ( ( (llx - halo)         as usize, (lly - halo)         as usize),
                      ( (llx + x_extent / 8) as usize, (lly + y_extent / 8) as usize) ),
                    &*agrid);
        }

        GridVariant::GridC32(agrid) => dump_grid("c32_grid", &*agrid),
        _ => panic!("not yet implemented")
    }

}
<|endoftext|>


<commit_before>//! Contains architecture-specific types and modules

use capstone::Capstone;
use constants::Endian;
use error::CsResult;
use std::fmt::Debug;
use std::marker::PhantomData;

macro_rules! define_subset_enum {
    ( [
        $subset_enum:ident = $base_enum:ident
      ]
      $( $variant:ident, )*
    ) => {
        #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
        pub enum $subset_enum {
            $(
                $variant,
            )*
        }

        impl From<$subset_enum> for $base_enum {
            fn from(other: $subset_enum) -> $base_enum {
                match other {
                    $(
                        $subset_enum::$variant => $base_enum::$variant,
                    )*
                }
            }
        }
    };
}

/// Define arch builders
macro_rules! define_arch_builder {
    // ExtraMode rules
    ( @extra_modes () ) => {};
    ( @extra_modes ( $( $extra_mode:ident, )+ ) ) => {
        impl super::BuildsCapstoneExtraMode<ArchMode, ArchExtraMode> for ArchCapstoneBuilder {
            fn extra_mode<T: Iterator<Item=ArchExtraMode>>(&mut self, extra_mode: T) -> & mut Self {
                self.extra_mode.clear();
                self.extra_mode.extend(extra_mode);
                self
            }
        }
    };

    // Syntax rules
    ( @syntax () ) => {};
    ( @syntax ( $( $syntax:ident, )+ ) ) => {
        impl super::BuildsCapstoneSyntax<ArchMode, ArchSyntax> for ArchCapstoneBuilder {
            fn syntax(& mut self, syntax: ArchSyntax) -> &mut Self {
                self.syntax = Some(syntax);
                self
            }
        }
    };

    // Endian rules
    ( @endian ( false) ) => {};
    ( @endian ( true ) ) => {
        impl super::BuildsCapstoneEndian<ArchMode> for ArchCapstoneBuilder {
            fn endian(&mut self, endian: Endian) -> &mut Self {
                self.endian = Some(endian);
                self
            }
        }
    };

    // Entrance rule
    (
        $( [
            ( $arch:ident, $arch_variant:ident )
            ( mode: $( $mode:ident, )+ )
            ( extra_modes: $( $extra_mode:ident, )* )
            ( syntax: $( $syntax:ident, )* )
            ( both_endian: $( $endian:ident )* )
        ] )+
    ) => {
        // We put builders in `arch::arch_builder::$ARCH` so we can put manual arch-specific code
        // in `arch::$ARCH`. The contents of each module is imported from `arch::$ARCH`.

        $(
            /// Architecture-specific build code
            pub mod $arch {
                use capstone::Capstone;
                use constants::{Arch, Endian, ExtraMode, Mode, Syntax};
                use error::{CsResult, Error};

                define_arch_builder!( @syntax ( $( $syntax, )* ) );
                define_arch_builder!( @endian ( $( $endian )* ) );
                define_arch_builder!( @extra_modes ( $( $extra_mode, )* ) );

                define_subset_enum!(
                    [ ArchMode = Mode ]
                    $( $mode, )*
                );

                define_subset_enum!(
                    [ ArchExtraMode = ExtraMode ]
                    $( $extra_mode, )*
                );

                define_subset_enum!(
                    [ ArchSyntax = Syntax ]
                    $( $syntax, )*
                );

                #[derive(Clone)]
                pub struct ArchCapstoneBuilder {
                    pub(crate) mode: Option<ArchMode>,
                    pub(crate) is_detail: bool,
                    pub(crate) extra_mode: Vec<ArchExtraMode>,
                    pub(crate) syntax: Option<ArchSyntax>,
                    pub(crate) endian: Option<Endian>,
                }

                impl super::BuildsCapstone<ArchMode> for ArchCapstoneBuilder {
                    fn mode(&mut self, mode: ArchMode) -> &mut Self {
                        self.mode = Some(mode);
                        self
                    }

                    fn detail(&mut self, enable_detail: bool) -> &mut Self {
                        self.is_detail = enable_detail;
                        self
                    }

                    fn build(&mut self) -> CsResult<Capstone> {
                        let mode = match self.mode {
                            Some(mode) => mode,
                            None => {
                                let msg: &'static str = concat!(
                                    "Must specify mode for ",
                                    stringify!($arch),
                                    "::ArchCapstoneBuilder with `mode()` method",
                                );
                                return Err(Error::CustomError(msg));
                            }
                        };
                        let extra_mode = self.extra_mode.iter().map(|x| ExtraMode::from(*x));
                        let mut capstone = Capstone::new_raw(Arch::$arch_variant,
                                                             mode.into(),
                                                             extra_mode,
                                                             self.endian)?;

                        if let Some(syntax) = self.syntax {
                            capstone.set_syntax(Syntax::from(syntax))?;
                        }
                        if self.is_detail {
                            capstone.set_detail(self.is_detail)?;
                        }

                        Ok(capstone)
                    }
                }

                impl Default for ArchCapstoneBuilder {
                    fn default() -> Self {
                        ArchCapstoneBuilder {
                            mode: None,
                            is_detail: false,
                            extra_mode: vec![],
                            endian: None,
                            syntax: None,
                        }
                    }
                }
            }
        )+

        impl CapstoneBuilder {
            $(
                pub fn $arch(self) -> $arch::ArchCapstoneBuilder {
                    Default::default()
                }
            )*
        }
    }
}

/// Base X macro with arch info
macro_rules! arch_info_base {
    ($x_macro:ident) => {
        $x_macro!(
                [
                    ( arm, ARM )
                    ( mode:
                        Arm,
                        Thumb,
                        )
                    ( extra_modes:
                        MClass,
                        V8,
                        )
                    ( syntax:
                        NoRegName,
                        )
                    ( both_endian: true )
                ]
                [
                    ( arm64, ARM64 )
                    ( mode:
                        Arm,
                        )
                    ( extra_modes: )
                    ( syntax: )
                    ( both_endian: true )
                ]
                [
                    ( mips, MIPS )
                    ( mode:
                        Mode32,
                        Mode64,
                        Mips32R6,
                        MipsGP64,
                        )
                    ( extra_modes:
                        Micro,
                        )
                    ( syntax: )
                    ( both_endian: true )
                ]
                [
                    ( ppc, PPC )
                    ( mode:
                        Mode32,
                        Mode64,
                        )
                    ( extra_modes: )
                    ( syntax:
                        NoRegName,
                        )
                    ( both_endian: true )
                ]
                [
                    ( sparc, SPARC )
                    ( mode:
                        Default,
                        V9,
                        )
                    ( extra_modes: )
                    ( syntax: )
                    ( both_endian: false )
                ]
                [
                    ( sysz, SYSZ )
                    ( mode:
                        Default,
                        )
                    ( extra_modes: )
                    ( syntax: )
                    ( both_endian: false )
                ]
                [
                    ( x86, X86 )
                    ( mode:
                        Mode16,
                        Mode32,
                        Mode64,
                        )
                    ( extra_modes: )
                    ( syntax:
                        Intel,
                        Att,
                        )
                    ( both_endian: false )
                ]
                [
                    ( xcore, XCORE )
                    ( mode:
                        Default,
                        )
                    ( extra_modes: )
                    ( syntax: )
                    ( both_endian: false  )
                ]
            );
    };
}

/// Builds a `Capstone` struct
pub trait BuildsCapstone<ArchMode> {
    /// Set the disassembly mode
    fn mode(&mut self, mode: ArchMode) -> &mut Self;

    /// Enable detailed output
    fn detail(&mut self, enable_detail: bool) -> &mut Self;

    /// Get final `Capstone`
    fn build(&mut self) -> CsResult<Capstone>;
}

/// Implies that a `CapstoneBuilder` architecture has extra modes
pub trait BuildsCapstoneExtraMode<ArchMode, ArchExtraMode>: BuildsCapstone<ArchMode> {
    /// Set architecture endianness
    fn extra_mode<T: Iterator<Item = ArchExtraMode>>(&mut self, extra_mode: T) -> &mut Self;
}

/// Implies that a `CapstoneBuilder` has different syntax options
pub trait BuildsCapstoneSyntax<ArchMode, ArchSyntax>: BuildsCapstone<ArchMode> {
    /// Set the disassembly syntax
    fn syntax(&mut self, syntax: ArchSyntax) -> &mut Self;
}

/// Implies that a `CapstoneBuilder` architecture has a configurable endianness
pub trait BuildsCapstoneEndian<ArchMode>: BuildsCapstone<ArchMode> {
    /// Set architecture endianness
    fn endian(&mut self, endian: Endian) -> &mut Self;
}

/// Contains builder-pattern implementations
pub(crate) mod arch_builder {
    use super::*;

    arch_info_base!(define_arch_builder);
}

/// Builds `Capstone` object
#[derive(Debug)]
pub struct CapstoneBuilder(
    /// Hidden field to prevent users from instantiating `CapstoneBuilder`
    PhantomData<()>,
);

impl CapstoneBuilder {
    /// Create a `CapstoneBuilder`
    pub(crate) fn new() -> Self {
        CapstoneBuilder(PhantomData)
    }
}

/// Provides architecture-specific details about an instruction
pub trait DetailsArchInsn: PartialEq + Debug {
    type Operand: Into<ArchOperand> + Default + Clone + Debug + PartialEq;
    type OperandIterator: Iterator<Item = Self::Operand>;

    fn operands(&self) -> Self::OperandIterator;
}

/// Define PartialEq for a type given representation getter methods
macro_rules! impl_PartialEq_repr_fields {
    // With generic parameters
    (
        $name:ty [ $( $lifetime:tt ),* ];
        $( $field:ident),*
    ) => {
        impl<$( $lifetime ),*> ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &Self) -> bool {
                $(
                    if self.$field() != other.$field() {
                        return false;
                    }
                )*
                true
            }
        }
    };

    // No generic parameters
    (
        $name:ty;
        $( $field:ident),*
    ) => {
        impl_PartialEq_repr_fields!(
            $name [];
            $( $field),*
        );
    };
}

/// Base macro for defining arch details
macro_rules! detail_arch_base {
    ($x_macro:ident) => {
        $x_macro!(
                [
                    detail = ArmDetail,
                    insn_detail = ArmInsnDetail<'a>,
                    op = ArmOperand,
                    /// Returns the ARM details, if any
                    => arch_name = arm,
                ]
                [
                    detail = Arm64Detail,
                    insn_detail = Arm64InsnDetail<'a>,
                    op = Arm64Operand,
                    /// Returns the ARM64 details, if any
                    => arch_name = arm64,
                ]
                [
                    detail = MipsDetail,
                    insn_detail = MipsInsnDetail<'a>,
                    op = MipsOperand,
                    /// Returns the MIPS details, if any
                    => arch_name = mips,
                ]
                [
                    detail = PpcDetail,
                    insn_detail = PpcInsnDetail<'a>,
                    op = PpcOperand,
                    /// Returns the PPC details, if any
                    => arch_name = ppc,
                ]
                [
                    detail = SparcDetail,
                    insn_detail = SparcInsnDetail<'a>,
                    op = SparcOperand,
                    /// Returns the SPARC details, if any
                    => arch_name = sparc,
                ]
                [
                    detail = X86Detail,
                    insn_detail = X86InsnDetail<'a>,
                    op = X86Operand,
                    /// Returns the X86 details, if any
                    => arch_name = x86,
                ]
                [
                    detail = XcoreDetail,
                    insn_detail = XcoreInsnDetail<'a>,
                    op = XcoreOperand,
                    /// Returns the XCore details, if any
                    => arch_name = xcore,
                ]
            );
    };
}

/// Define ArchDetail enum, ArchOperand enum, and From<$Operand> for ArchOperand
macro_rules! detail_defs {
    (
        $( [
            detail = $Detail:tt,
            insn_detail = $InsnDetail:ty,
            op = $Operand:tt,
            $( #[$func_attr:meta] )+
            => arch_name = $arch_name:ident,
        ] )+
    ) => {
        $(
            use self::$arch_name::*;
        )+

        /// Architecture-independent enum of detail structures
        #[derive(Debug)]
        pub enum ArchDetail<'a> {
            $( $Detail($InsnDetail), )+
        }

        /// Architecture-independent enum of operands
        #[derive(Clone, Debug, PartialEq)]
        pub enum ArchOperand {
            $( $Operand($Operand), )+
        }

        impl<'a> ArchDetail<'a> {
            /// Returns architecture independent set of operands
            pub fn operands(&'a self) -> Vec<ArchOperand> {
                match *self {
                    $(
                        ArchDetail::$Detail(ref detail) => {
                            let ops = detail.operands();
                            let map = ops.map(ArchOperand::from);
                            let vec: Vec<ArchOperand> = map.collect();
                            vec
                        }
                    )+
                }
            }

            $(
                $( #[$func_attr] )+
                pub fn $arch_name(&'a self) -> Option<& $InsnDetail> {
                    if let ArchDetail::$Detail(ref arch_detail) = *self {
                        Some(arch_detail)
                    } else {
                        None
                    }
                }
            )+
        }

        $(
            impl From<$Operand> for ArchOperand {
                fn from(op: $Operand) -> ArchOperand {
                    ArchOperand::$Operand(op)
                }
            }
        )+
    }
}

/// Define OperandIterator and DetailsArch impl
macro_rules! def_arch_details_struct {
    (
        InsnDetail = $InsnDetail:ident;
        Operand = $Operand:ident;
        OperandIterator = $OperandIterator:ident;
        OperandIteratorLife = $OperandIteratorLife:ty;
        [ $iter_struct:item ]
        cs_arch_op = $cs_arch_op:ty;
        cs_arch = $cs_arch:ty;
    ) => {
        /// Iterates over instruction operands
        #[derive(Clone)]
        $iter_struct

        impl<'a> $OperandIteratorLife {
            fn new(ops: &[$cs_arch_op]) -> $OperandIterator {
                $OperandIterator(ops.iter())
            }
        }

        impl<'a> Iterator for $OperandIteratorLife {
            type Item = $Operand;

            fn next(&mut self) -> Option<Self::Item> {
                match self.0.next() {
                    None => None,
                    Some(op) => Some($Operand::from(op)),
                }
            }
        }

        impl<'a> ExactSizeIterator for $OperandIteratorLife {
            fn len(&self) -> usize { self.0.len() }
        }

        impl<'a> PartialEq for $OperandIteratorLife {
            fn eq(&self, other: & $OperandIteratorLife) -> bool {
                self.len() == other.len() && {
                    let self_clone: $OperandIterator = self.clone();
                    let other_clone: $OperandIterator = (*other).clone();
                    self_clone.zip(other_clone).all(|(a, b)| a == b)
                }
            }
        }

        impl<'a> ::std::fmt::Debug for $OperandIteratorLife {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> ::std::fmt::Result {
                fmt.debug_struct(stringify!($OperandIterator)).finish()
            }
        }

        impl<'a> ::std::fmt::Debug for $InsnDetail<'a> {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> ::std::fmt::Result {
                fmt.debug_struct(stringify!($InsnDetail))
                    .field(stringify!($cs_arch), &(self.0 as *const $cs_arch))
                    .finish()
            }
        }

        impl<'a> ::arch::DetailsArchInsn for $InsnDetail<'a> {
            type OperandIterator = $OperandIteratorLife;
            type Operand = $Operand;

            fn operands(&self) -> $OperandIteratorLife {
                $OperandIterator::new(&self.0.operands[..self.0.op_count as usize])
            }
        }
    }
}

detail_arch_base!(detail_defs);

/// Define "pub mod" uses
macro_rules! define_arch_mods {
    (
        $( [
            ( $arch:ident, $arch_variant:ident )
            ( mode: $( $mode:ident, )+ )
            ( extra_modes: $( $extra_mode:ident, )* )
            ( syntax: $( $syntax:ident, )* )
            ( both_endian: $( $endian:ident )* )
        ] )+
    ) => {
        $( pub mod $arch; )+
    }
}

// Define modules at the end so that they can see macro definitions
arch_info_base!(define_arch_mods);
<commit_msg>Correct rustfmt formatting error<commit_after>//! Contains architecture-specific types and modules

use capstone::Capstone;
use constants::Endian;
use error::CsResult;
use std::fmt::Debug;
use std::marker::PhantomData;

macro_rules! define_subset_enum {
    ( [
        $subset_enum:ident = $base_enum:ident
      ]
      $( $variant:ident, )*
    ) => {
        #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
        pub enum $subset_enum {
            $(
                $variant,
            )*
        }

        impl From<$subset_enum> for $base_enum {
            fn from(other: $subset_enum) -> $base_enum {
                match other {
                    $(
                        $subset_enum::$variant => $base_enum::$variant,
                    )*
                }
            }
        }
    };
}

/// Define arch builders
macro_rules! define_arch_builder {
    // ExtraMode rules
    ( @extra_modes () ) => {};
    ( @extra_modes ( $( $extra_mode:ident, )+ ) ) => {
        impl super::BuildsCapstoneExtraMode<ArchMode, ArchExtraMode> for ArchCapstoneBuilder {
            fn extra_mode<T: Iterator<Item=ArchExtraMode>>(&mut self, extra_mode: T) -> & mut Self {
                self.extra_mode.clear();
                self.extra_mode.extend(extra_mode);
                self
            }
        }
    };

    // Syntax rules
    ( @syntax () ) => {};
    ( @syntax ( $( $syntax:ident, )+ ) ) => {
        impl super::BuildsCapstoneSyntax<ArchMode, ArchSyntax> for ArchCapstoneBuilder {
            fn syntax(& mut self, syntax: ArchSyntax) -> &mut Self {
                self.syntax = Some(syntax);
                self
            }
        }
    };

    // Endian rules
    ( @endian ( false) ) => {};
    ( @endian ( true ) ) => {
        impl super::BuildsCapstoneEndian<ArchMode> for ArchCapstoneBuilder {
            fn endian(&mut self, endian: Endian) -> &mut Self {
                self.endian = Some(endian);
                self
            }
        }
    };

    // Entrance rule
    (
        $( [
            ( $arch:ident, $arch_variant:ident )
            ( mode: $( $mode:ident, )+ )
            ( extra_modes: $( $extra_mode:ident, )* )
            ( syntax: $( $syntax:ident, )* )
            ( both_endian: $( $endian:ident )* )
        ] )+
    ) => {
        // We put builders in `arch::arch_builder::$ARCH` so we can put manual arch-specific code
        // in `arch::$ARCH`. The contents of each module is imported from `arch::$ARCH`.

        $(
            /// Architecture-specific build code
            pub mod $arch {
                use capstone::Capstone;
                use constants::{Arch, Endian, ExtraMode, Mode, Syntax};
                use error::{CsResult, Error};

                define_arch_builder!( @syntax ( $( $syntax, )* ) );
                define_arch_builder!( @endian ( $( $endian )* ) );
                define_arch_builder!( @extra_modes ( $( $extra_mode, )* ) );

                define_subset_enum!(
                    [ ArchMode = Mode ]
                    $( $mode, )*
                );

                define_subset_enum!(
                    [ ArchExtraMode = ExtraMode ]
                    $( $extra_mode, )*
                );

                define_subset_enum!(
                    [ ArchSyntax = Syntax ]
                    $( $syntax, )*
                );

                #[derive(Clone)]
                pub struct ArchCapstoneBuilder {
                    pub(crate) mode: Option<ArchMode>,
                    pub(crate) is_detail: bool,
                    pub(crate) extra_mode: Vec<ArchExtraMode>,
                    pub(crate) syntax: Option<ArchSyntax>,
                    pub(crate) endian: Option<Endian>,
                }

                impl super::BuildsCapstone<ArchMode> for ArchCapstoneBuilder {
                    fn mode(&mut self, mode: ArchMode) -> &mut Self {
                        self.mode = Some(mode);
                        self
                    }

                    fn detail(&mut self, enable_detail: bool) -> &mut Self {
                        self.is_detail = enable_detail;
                        self
                    }

                    fn build(&mut self) -> CsResult<Capstone> {
                        let mode = match self.mode {
                            Some(mode) => mode,
                            None => {
                                let msg: &'static str = concat!(
                                    "Must specify mode for ",
                                    stringify!($arch),
                                    "::ArchCapstoneBuilder with `mode()` method",
                                );
                                return Err(Error::CustomError(msg));
                            }
                        };
                        let extra_mode = self.extra_mode.iter().map(|x| ExtraMode::from(*x));
                        let mut capstone = Capstone::new_raw(Arch::$arch_variant,
                                                             mode.into(),
                                                             extra_mode,
                                                             self.endian)?;

                        if let Some(syntax) = self.syntax {
                            capstone.set_syntax(Syntax::from(syntax))?;
                        }
                        if self.is_detail {
                            capstone.set_detail(self.is_detail)?;
                        }

                        Ok(capstone)
                    }
                }

                impl Default for ArchCapstoneBuilder {
                    fn default() -> Self {
                        ArchCapstoneBuilder {
                            mode: None,
                            is_detail: false,
                            extra_mode: vec![],
                            endian: None,
                            syntax: None,
                        }
                    }
                }
            }
        )+

        impl CapstoneBuilder {
            $(
                pub fn $arch(self) -> $arch::ArchCapstoneBuilder {
                    Default::default()
                }
            )*
        }
    }
}

/// Base X macro with arch info
macro_rules! arch_info_base {
    ($x_macro:ident) => {
        $x_macro!(
            [
                ( arm, ARM )
                ( mode:
                    Arm,
                    Thumb,
                    )
                ( extra_modes:
                    MClass,
                    V8,
                    )
                ( syntax:
                    NoRegName,
                    )
                ( both_endian: true )
            ]
            [
                ( arm64, ARM64 )
                ( mode:
                    Arm,
                    )
                ( extra_modes: )
                ( syntax: )
                ( both_endian: true )
            ]
            [
                ( mips, MIPS )
                ( mode:
                    Mode32,
                    Mode64,
                    Mips32R6,
                    MipsGP64,
                    )
                ( extra_modes:
                    Micro,
                    )
                ( syntax: )
                ( both_endian: true )
            ]
            [
                ( ppc, PPC )
                ( mode:
                    Mode32,
                    Mode64,
                    )
                ( extra_modes: )
                ( syntax:
                    NoRegName,
                    )
                ( both_endian: true )
            ]
            [
                ( sparc, SPARC )
                ( mode:
                    Default,
                    V9,
                    )
                ( extra_modes: )
                ( syntax: )
                ( both_endian: false )
            ]
            [
                ( sysz, SYSZ )
                ( mode:
                    Default,
                    )
                ( extra_modes: )
                ( syntax: )
                ( both_endian: false )
            ]
            [
                ( x86, X86 )
                ( mode:
                    Mode16,
                    Mode32,
                    Mode64,
                    )
                ( extra_modes: )
                ( syntax:
                    Intel,
                    Att,
                    )
                ( both_endian: false )
            ]
            [
                ( xcore, XCORE )
                ( mode:
                    Default,
                    )
                ( extra_modes: )
                ( syntax: )
                ( both_endian: false  )
            ]
        );
    };
}

/// Builds a `Capstone` struct
pub trait BuildsCapstone<ArchMode> {
    /// Set the disassembly mode
    fn mode(&mut self, mode: ArchMode) -> &mut Self;

    /// Enable detailed output
    fn detail(&mut self, enable_detail: bool) -> &mut Self;

    /// Get final `Capstone`
    fn build(&mut self) -> CsResult<Capstone>;
}

/// Implies that a `CapstoneBuilder` architecture has extra modes
pub trait BuildsCapstoneExtraMode<ArchMode, ArchExtraMode>: BuildsCapstone<ArchMode> {
    /// Set architecture endianness
    fn extra_mode<T: Iterator<Item = ArchExtraMode>>(&mut self, extra_mode: T) -> &mut Self;
}

/// Implies that a `CapstoneBuilder` has different syntax options
pub trait BuildsCapstoneSyntax<ArchMode, ArchSyntax>: BuildsCapstone<ArchMode> {
    /// Set the disassembly syntax
    fn syntax(&mut self, syntax: ArchSyntax) -> &mut Self;
}

/// Implies that a `CapstoneBuilder` architecture has a configurable endianness
pub trait BuildsCapstoneEndian<ArchMode>: BuildsCapstone<ArchMode> {
    /// Set architecture endianness
    fn endian(&mut self, endian: Endian) -> &mut Self;
}

/// Contains builder-pattern implementations
pub(crate) mod arch_builder {
    use super::*;

    arch_info_base!(define_arch_builder);
}

/// Builds `Capstone` object
#[derive(Debug)]
pub struct CapstoneBuilder(
    /// Hidden field to prevent users from instantiating `CapstoneBuilder`
    PhantomData<()>,
);

impl CapstoneBuilder {
    /// Create a `CapstoneBuilder`
    pub(crate) fn new() -> Self {
        CapstoneBuilder(PhantomData)
    }
}

/// Provides architecture-specific details about an instruction
pub trait DetailsArchInsn: PartialEq + Debug {
    type Operand: Into<ArchOperand> + Default + Clone + Debug + PartialEq;
    type OperandIterator: Iterator<Item = Self::Operand>;

    fn operands(&self) -> Self::OperandIterator;
}

/// Define PartialEq for a type given representation getter methods
macro_rules! impl_PartialEq_repr_fields {
    // With generic parameters
    (
        $name:ty [ $( $lifetime:tt ),* ];
        $( $field:ident),*
    ) => {
        impl<$( $lifetime ),*> ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &Self) -> bool {
                $(
                    if self.$field() != other.$field() {
                        return false;
                    }
                )*
                true
            }
        }
    };

    // No generic parameters
    (
        $name:ty;
        $( $field:ident),*
    ) => {
        impl_PartialEq_repr_fields!(
            $name [];
            $( $field),*
        );
    };
}

/// Base macro for defining arch details
macro_rules! detail_arch_base {
    ($x_macro:ident) => {
        $x_macro!(
            [
                detail = ArmDetail,
                insn_detail = ArmInsnDetail<'a>,
                op = ArmOperand,
                /// Returns the ARM details, if any
                => arch_name = arm,
            ]
            [
                detail = Arm64Detail,
                insn_detail = Arm64InsnDetail<'a>,
                op = Arm64Operand,
                /// Returns the ARM64 details, if any
                => arch_name = arm64,
            ]
            [
                detail = MipsDetail,
                insn_detail = MipsInsnDetail<'a>,
                op = MipsOperand,
                /// Returns the MIPS details, if any
                => arch_name = mips,
            ]
            [
                detail = PpcDetail,
                insn_detail = PpcInsnDetail<'a>,
                op = PpcOperand,
                /// Returns the PPC details, if any
                => arch_name = ppc,
            ]
            [
                detail = SparcDetail,
                insn_detail = SparcInsnDetail<'a>,
                op = SparcOperand,
                /// Returns the SPARC details, if any
                => arch_name = sparc,
            ]
            [
                detail = X86Detail,
                insn_detail = X86InsnDetail<'a>,
                op = X86Operand,
                /// Returns the X86 details, if any
                => arch_name = x86,
            ]
            [
                detail = XcoreDetail,
                insn_detail = XcoreInsnDetail<'a>,
                op = XcoreOperand,
                /// Returns the XCore details, if any
                => arch_name = xcore,
            ]
        );
    };
}

/// Define ArchDetail enum, ArchOperand enum, and From<$Operand> for ArchOperand
macro_rules! detail_defs {
    (
        $( [
            detail = $Detail:tt,
            insn_detail = $InsnDetail:ty,
            op = $Operand:tt,
            $( #[$func_attr:meta] )+
            => arch_name = $arch_name:ident,
        ] )+
    ) => {
        $(
            use self::$arch_name::*;
        )+

        /// Architecture-independent enum of detail structures
        #[derive(Debug)]
        pub enum ArchDetail<'a> {
            $( $Detail($InsnDetail), )+
        }

        /// Architecture-independent enum of operands
        #[derive(Clone, Debug, PartialEq)]
        pub enum ArchOperand {
            $( $Operand($Operand), )+
        }

        impl<'a> ArchDetail<'a> {
            /// Returns architecture independent set of operands
            pub fn operands(&'a self) -> Vec<ArchOperand> {
                match *self {
                    $(
                        ArchDetail::$Detail(ref detail) => {
                            let ops = detail.operands();
                            let map = ops.map(ArchOperand::from);
                            let vec: Vec<ArchOperand> = map.collect();
                            vec
                        }
                    )+
                }
            }

            $(
                $( #[$func_attr] )+
                pub fn $arch_name(&'a self) -> Option<& $InsnDetail> {
                    if let ArchDetail::$Detail(ref arch_detail) = *self {
                        Some(arch_detail)
                    } else {
                        None
                    }
                }
            )+
        }

        $(
            impl From<$Operand> for ArchOperand {
                fn from(op: $Operand) -> ArchOperand {
                    ArchOperand::$Operand(op)
                }
            }
        )+
    }
}

/// Define OperandIterator and DetailsArch impl
macro_rules! def_arch_details_struct {
    (
        InsnDetail = $InsnDetail:ident;
        Operand = $Operand:ident;
        OperandIterator = $OperandIterator:ident;
        OperandIteratorLife = $OperandIteratorLife:ty;
        [ $iter_struct:item ]
        cs_arch_op = $cs_arch_op:ty;
        cs_arch = $cs_arch:ty;
    ) => {
        /// Iterates over instruction operands
        #[derive(Clone)]
        $iter_struct

        impl<'a> $OperandIteratorLife {
            fn new(ops: &[$cs_arch_op]) -> $OperandIterator {
                $OperandIterator(ops.iter())
            }
        }

        impl<'a> Iterator for $OperandIteratorLife {
            type Item = $Operand;

            fn next(&mut self) -> Option<Self::Item> {
                match self.0.next() {
                    None => None,
                    Some(op) => Some($Operand::from(op)),
                }
            }
        }

        impl<'a> ExactSizeIterator for $OperandIteratorLife {
            fn len(&self) -> usize { self.0.len() }
        }

        impl<'a> PartialEq for $OperandIteratorLife {
            fn eq(&self, other: & $OperandIteratorLife) -> bool {
                self.len() == other.len() && {
                    let self_clone: $OperandIterator = self.clone();
                    let other_clone: $OperandIterator = (*other).clone();
                    self_clone.zip(other_clone).all(|(a, b)| a == b)
                }
            }
        }

        impl<'a> ::std::fmt::Debug for $OperandIteratorLife {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> ::std::fmt::Result {
                fmt.debug_struct(stringify!($OperandIterator)).finish()
            }
        }

        impl<'a> ::std::fmt::Debug for $InsnDetail<'a> {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> ::std::fmt::Result {
                fmt.debug_struct(stringify!($InsnDetail))
                    .field(stringify!($cs_arch), &(self.0 as *const $cs_arch))
                    .finish()
            }
        }

        impl<'a> ::arch::DetailsArchInsn for $InsnDetail<'a> {
            type OperandIterator = $OperandIteratorLife;
            type Operand = $Operand;

            fn operands(&self) -> $OperandIteratorLife {
                $OperandIterator::new(&self.0.operands[..self.0.op_count as usize])
            }
        }
    }
}

detail_arch_base!(detail_defs);

/// Define "pub mod" uses
macro_rules! define_arch_mods {
    (
        $( [
            ( $arch:ident, $arch_variant:ident )
            ( mode: $( $mode:ident, )+ )
            ( extra_modes: $( $extra_mode:ident, )* )
            ( syntax: $( $syntax:ident, )* )
            ( both_endian: $( $endian:ident )* )
        ] )+
    ) => {
        $( pub mod $arch; )+
    }
}

// Define modules at the end so that they can see macro definitions
arch_info_base!(define_arch_mods);
<|endoftext|>